SSM三大框架集成-三层架构-SSM集成

- 三层架构

  • MVC设计模式与三层架构的区别

    • 实际上三层架构与MVC没有太大的联系,只是目标一致:都是为了解耦、提高代码复用

    • MVC是一种设计模式或一种设计思想,而三层架构是一种软件架构

  • 什么是三层架构:三层架构是一种比较经典的软件架构,还有其他架构,例如四层架构等

  • 为什么需要使用三层架构

    • 开发人员可以只关注整个结构中的其中某一层
    • 可以很容易的用新的实现来替换原有层次的实现
    • 可以降低层与层之间的依赖
    • 有利于标准化
    • 利于各层逻辑的复用
    • 安全性高。用户端只能通过逻辑层来访问数据层,减少了入口点,把很多危险的系统功能都屏蔽了
    • 项目结构更清楚,分工更明确,有利于后期的维护和升级
  • 三层架构是哪三层

    • 数据访问层【数据层】/持久化层/DAL:主要是对数据库进行CRUD操作,不写任何逻辑代码

    • 业务处理层【业务层】/Service层/BLL:主要是业务逻辑的处理,负责表示层与数据层(持久层)的数据的传递和逻辑处理

    • 表现层/界面层/UI:展示数据或提供数据的界面,或者用户看到的界面,例如html,jsp,swing等。Controller控制器、View视图都属于表现层,界面中数据的传递要依靠Controller,传递数据的格式就是模型数据

  • 数据层框架

    • Hibernate、SpringJdbc、Mybatis【iBatis】等,封装原生JDBC代码
  • 表现层框架

    • Struts2、SpringMvc等,封装原生Servlet代码
  • 三层架构规范

    • 表现层/controller层设计

      • 无需接口,所有的类在controller包下,类名为:XxxController/UserController
    • 业务层/service层设计

      • 需要接口与实现类,接口与实现类都在service包下

      • 接口名称为:IXxxService/IUserService

      • 实现类为:在service包下创建impl包,实现类在impl包下,XxxServiceImpl/UserServiceImpl

    • 持久层设计,两种方式

      • 持久层设计方式一:dao层

         - 需要接口与实现类,接口与实现类都在dao包下
        
         - 接口名称为:IXxxDao/IUserDao
        
         - 实现类为:在service包下创建impl包,实现类在impl包下,XxxDaoImpl/UserDaoImpl
         
        复制代码
      • 持久层设计方式二:mapper层,Mybatis官方推荐使用(推荐使用)

          - 无需实现类,所有接口都在mapper包下,接口名称为:XxxMapper/UserMapper
        复制代码

image.png

注意:domain并不算是软件架构的一层,我们的实体类统一都会放在domain中,每一层都会使用到domain中的实体类

- SSM集成

  • SSM集成就是三大框架的集成:Spring + SpringMVC + Mybatis

  • SSM框架集成步骤

1.导入jar包:今日需要用到7类jar包

image.png

image.png

2.导入数据库表/建立数据库表:今日以员工表为例

image.png

3.编写domain

package cn.itsource.domain;

import java.util.Date;

import org.springframework.format.annotation.DateTimeFormat;

import com.fasterxml.jackson.annotation.JsonFormat;

public class Emp {
	  
	  // 主键id
	  private Integer eid;
	  // 编号
	  private String eno;
	  // 名称
	  private String ename;
	  // 年龄
	  private Integer age;
	  // 性别
	  private char sex;
	  // 电话
	  private String tel;
	  // 地址
	  private String address;
	  // 薪资
	  private double sal;
	  
	  // 创建时间
	  @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
	  private Date createdTime;
	  
	public Integer getEid() {
		return eid;
	}
	public void setEid(Integer eid) {
		this.eid = eid;
	}
	public String getEno() {
		return eno;
	}
	public void setEno(String eno) {
		this.eno = eno;
	}
	public String getEname() {
		return ename;
	}
	public void setEname(String ename) {
		this.ename = ename;
	}
	public Integer getAge() {
		return age;
	}
	public void setAge(Integer age) {
		this.age = age;
	}
	public char getSex() {
		return sex;
	}
	public void setSex(char sex) {
		this.sex = sex;
	}
	public String getTel() {
		return tel;
	}
	public void setTel(String tel) {
		this.tel = tel;
	}
	public String getAddress() {
		return address;
	}
	public void setAddress(String address) {
		this.address = address;
	}
	public double getSal() {
		return sal;
	}
	public void setSal(double sal) {
		this.sal = sal;
	}
	
	@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
	public Date getCreatedTime() {
		return createdTime;
	}
	public void setCreatedTime(Date createdTime) {
		this.createdTime = createdTime;
	}
	@Override
	public String toString() {
		return "Emp [eid=" + eid + ", eno=" + eno + ", ename=" + ename + ", age=" + age + ", sex=" + sex + ", tel="
				+ tel + ", address=" + address + ", sal=" + sal + ", createdTime=" + createdTime + "]";
	}

	  
}

复制代码

4.编写mapper接口

package cn.itsource.mapper;

import java.util.List;

import cn.itsource.domain.Emp;
import cn.itsource.query.EmpQuery;

public interface EmpMapper {
	
	// 查询所有
	List<Emp> findAllEmp();
	
	// 根据主键ID查询
	Emp findById(Integer eid);
	
	// 根据主键ID修改
	void updateById(Integer eid);
	
	// 根据主键ID删除
	void deleteById(Integer eid);
	
	// 新增
	void addEmp(Emp emp);
	
	// 根据条件查询
	List<Emp> findByQuery(EmpQuery empQuery);

}

复制代码

5.编写mapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  
  <mapper namespace="cn.itsource.mapper.EmpMapper">
  		
  		<select id="findAllEmp" resultType="Emp">
  			select * from emp
  		</select>
  		
  		<select id="findByQuery" resultType="Emp">
  			select * from emp
  			
  			<!-- 会自动帮我们拼接一个where 关键字, 并且帮助我们去除多余的and关键字 -->
  			<where>
  				<!-- 因为条件可能为空,所以我们需要使用到if标签,帮我们判断 -->
  				<if test="ename != null and ename != '' ">
  					and ename like CONCAT('%',#{ename},'%')
  				</if>
  				
  				<if test="address != null and address != '' ">
  					and address like CONCAT('%',#{address},'%')
  				</if>
  				
  				<if test="sal == 1 ">
  					and <![CDATA[sal < 3000]]>
  				</if>
  				
  				<if test="sal == 2 ">
  					and <![CDATA[sal >= 3000 and sal <= 5000]]>
  				</if>
  				
  				<if test="sal == 3 ">
  					and <![CDATA[sal > 5000 and sal <= 8000]]>
  				</if>
  				
  				<if test="sal == 4 ">
  					and <![CDATA[sal > 8000]]>
  				</if>
  			</where>
  			
  		</select>
  		
  		<delete id="deleteById">
  			delete from emp where eid = #{eid}
  		</delete>
  		
  </mapper>
复制代码

6.编写service

  • 接口
package cn.itsource.service;

import java.util.List;

import cn.itsource.domain.Emp;
import cn.itsource.query.EmpQuery;

public interface IEmpService {
	
		// 查询所有
		List<Emp> findAllEmp();
		
		// 根据主键ID查询
		Emp findById(Integer eid);
		
		// 根据主键ID修改
		void updateById(Integer eid);
		
		// 根据主键ID删除
		void deleteById(Integer eid);
		
		// 新增
		void addEmp(Emp emp);
		
		// 根据条件查询
		List<Emp> findByQuery(EmpQuery empQuery);	

}

复制代码
  • 实现类
package cn.itsource.service.impl;

import java.util.List;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import cn.itsource.domain.Emp;
import cn.itsource.mapper.EmpMapper;
import cn.itsource.query.EmpQuery;
import cn.itsource.service.IEmpService;

@Service //把当前的类交个spring管理   创建对象的工作交给spring
public class EmpServiceImpl implements IEmpService{
	
	@Autowired
	private EmpMapper empMapper;

	// 查询所有
	@Override
	public List<Emp> findAllEmp() {
		return empMapper.findAllEmp();
	}

	// 根据ID查询
	@Override
	public Emp findById(Integer eid) {
		// TODO Auto-generated method stub
		return null;
	}

	// 根据ID修改
	@Override
	public void updateById(Integer eid) {
		// TODO Auto-generated method stub
		
	}

	// 根据ID删除
	@Override
	public void deleteById(Integer eid) {
		empMapper.deleteById(eid);
	}

	// 新增
	@Override
	public void addEmp(Emp emp) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public List<Emp> findByQuery(EmpQuery empQuery) {
		return empMapper.findByQuery(empQuery);
	}

}

复制代码

7.编写spring核心配置文件:applicationContext.xml

  • 1.配置数据库连接池对象:BasicDataSource

    • 1.1.jdbc.properties
  • 2.配置mybatis核心对象:SqlSessionFactoryBean

    • 1.1.扫描别名包

    • 1.2.扫描mapper.xml

    • 1.3.依赖数据库连接池

  • 3.扫描service层

  • 4.扫描mapper接口

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd"
>
	<!-- 引入jdbc.properties -->
	<context:property-placeholder location="classpath:jdbc.properties"/>
	
	<!-- 配置扫描包,service层 -->
	<context:component-scan base-package="cn.itsource.service"/>

	<!-- 配置数据库连接池对象 -->
	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
		<property name="username" value="${jdbc.username}"/>
		<property name="password" value="${jdbc.password}"/>
		<property name="url" value="${jdbc.url}"/>
		<property name="driverClassName" value="${jdbc.driverClassName}"/>
	</bean>
	
	<!-- 配置mybatis核心对象 -->
	<bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<!-- 依赖dataSource -->
		<property name="dataSource" ref="dataSource"/>
		<!-- 扫描公共包 -->
		<property name="typeAliasesPackage" value="cn.itsource.domain"/>
		<!-- 加载mapper.xml -->
		<property name="mapperLocations" value="classpath:cn/itsource/mapper/*Mapper.xml"/>
	</bean>
	
	<!-- MapperFactoryBean就是专门用来管理所有的mapper接口的,
	你只要配置了这个,spring就知道你的mapper接口是需要他来帮助创建实现类的 -->
	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
	<property name="basePackage" value="cn.itsource.mapper"></property>
	</bean>
	
</beans>
复制代码
  • jdbc.properties
jdbc.driverClassName=com.mysql.cj.jdbc.Driver

jdbc.url=jdbc:mysql://localhost:3306/ssm

jdbc.username=root

jdbc.password=root
复制代码

7.测试

package cn.itsource.test;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import cn.itsource.service.IEmpService;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class EmpMapperTest {
	
	@Autowired
	private IEmpService iEmpService;
	
	@Test
	public void test() {
		iEmpService.findAllEmp().forEach(System.out::println);
	}

}

复制代码

8.加入log.properties核心配置文件

#控制台输出+自定义布局

log4j.rootLogger=DEBUG,my

#指定输出器

log4j.appender.my=org.apache.log4j.ConsoleAppender

#指定布局器(自定义布局)

#指定布局为自定义布局

log4j.appender.my.layout=org.apache.log4j.PatternLayout

#指定在自定义布局的格式,%d -- 表示当前系统时间,%t -- 执行该业务的线程名称,%p -- 日记器的级别,-5 -- 5表示输出字符的个数,符号表示右对齐

#%c -- 表示指定业务所在的类的完全限定名(包名.类名),%m -- 输出额外信息,%n -- 表示换行

log4j.appender.my.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n

#设置package(可以是自定义的包也可以是api的包)输出级别

log4j.logger.org.springframework=info

log4j.logger.cn.itsource=debug
复制代码

9.编写controller层

package cn.itsource.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import cn.itsource.domain.Emp;
import cn.itsource.query.EmpQuery;
import cn.itsource.service.IEmpService;

@Controller
@RequestMapping("/emp")
public class EmpController {
	
	@Autowired
	private IEmpService iEmpService;
	
	
	/**
	 * 查询所有
	 * @param model
	 * @return
	 */
	@RequestMapping("/findAllEmp")
	public String findAllEmp(Model model) {
	
		// 调用持久层方法
		List<Emp> findAllEmp = iEmpService.findAllEmp();
		model.addAttribute("emps", findAllEmp);
		
		return "show";

	}
	
	/**
	 * 根据条件查询员工列表
	 * @param model
	 * @param empQuery
	 * @return
	 */
	@RequestMapping("/findByQuery")
	public String findByQuery(Model model, EmpQuery empQuery) {
		// 调用service层方法
		List<Emp> findByQuery = iEmpService.findByQuery(empQuery);
		model.addAttribute("emps", findByQuery);
		model.addAttribute("query", empQuery);
		return "show";
	}
	
	/**
	 * 根据id删除,并且重定向到findByQuery接口,查询最新的数据
	 * @param eid
	 * @return
	 */
	@RequestMapping("/deleteById")
	public String deleteById(Integer eid) {
		iEmpService.deleteById(eid);
		return "redirect:/emp/findByQuery";
	}
	

}

复制代码

10.编写springMVC核心配置文件:applicationContext-mvc.xml

    1.扫包

    2.静态资源放行

    3.开启springMVC注解的支持

    4.配置视图解析器

    5.配置上传解析器(根据业务,如果需要上传解析器,再配置)

    6.配置拦截器(根据业务,如果需要登录再配置)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd"
>

	<!-- 扫描包,controller -->
	<context:component-scan base-package="cn.itsource.controller"/>
	
	<!-- 开启静态资源放行 -->
	<mvc:default-servlet-handler/>
	
	<!-- 开启springMVC注解的支持 -->
	<mvc:annotation-driven/>
	
	<!-- 配置视图解析器 -->
	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<!-- 前缀 -->
		<property name="Prefix" value="/WEB-INF/views/"/>
		<!-- 后缀 -->
		<property name="Suffix" value=".jsp"></property>
	</bean>
	
</beans>
复制代码

11.编写web.xml

    1.配置springMVC核心对象

    2.解决post提交乱码问题

    3.开启spring容器

<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                      http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
  version="3.1"
  metadata-complete="false">
  
  	<!-- 加载指定路径的核心配置文件 -->
  	<context-param>
  		<param-name>contextConfigLocation</param-name>
  		<param-value>classpath:applicationContext.xml</param-value>
  	</context-param>

	<!-- 开启spring容器 -->
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
	
	<!-- 配置springMVC核心对象 -->
	<servlet>
		<servlet-name>dispatcherServlet</servlet-name>	
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath:applicationContext-mvc.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>dispatcherServlet</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>
	
	<!-- 解决post提交乱码问题 -->
	<filter>
	<filter-name>characterEncodingFilter</filter-name>
	<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
	<!-- 指定字符编码集 -->
	<init-param>
	<param-name>encoding</param-name>
	<param-value>UTF-8</param-value>
	</init-param>
	<!-- 强制指定字符编码,即使request或response设置了字符编码,
	也会强制使用当前设置的,任何情况下强制使用此编码 -->
	<init-param>
	<param-name>forceEncoding</param-name>
	<param-value>true</param-value>
	</init-param>
	</filter>
	<filter-mapping>
	<filter-name>characterEncodingFilter</filter-name>
	<url-pattern>/*</url-pattern>
	</filter-mapping>
</web-app>

复制代码

12.编写jsp

<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<!DOCTYPE html>
<html>
<head>
<title>model</title>
<style type="text/css">
	body{
		background-color: silver;
	}
	table{
		border-collapse: collapse; 
		width: 100%;
		text-align: center;
		margin: 20px auto;
		font-family: "微软雅黑";
	}
	td{
		border: 1px solid green;
		height: 30px;
	}
	caption {
		margin: 5px;
		font-size: 30px;
		font-weight: bold;
	}

</style>
</head>
<body>
	<form action="/emp/findByQuery">
		<div>
		<h1>员工列表显示</h1>
			姓名:<input type="text" name="ename" value="${query.ename }"/> &emsp; 
			地址:<input type="text" name="address" value="${query.address }"/> &emsp; 
			薪水:
			<select name="sal" id="sal">
				<option value="">请选择薪水:</option>
				<option value="1" <c:if test="${query.sal == 1}">selected=selected</c:if>>3000以下</option>
				<option value="2" <c:if test="${query.sal == 2}">selected=selected</c:if>>[3000-5000)</option>
				<option value="3" <c:if test="${query.sal == 3}">selected=selected</c:if>>[5000-8000)</option>
				<option value="4" <c:if test="${query.sal == 4}">selected=selected</c:if>>8000以上</option>
			</select>
			<input type="submit" value="搜索"/>
		</div>
		<script type="text/javascript">
			document.getElementById("deptno").value="${emp.deptno}";
			document.getElementById("sal").value="${emp.sal}";
		</script>
	</form> 
	<table>
		<thead>
			<tr>
				<td>ID</td>
				<td>编号</td>
				<td>姓名</td>
				<td>年龄</td>
				<td>性别</td>
				<td>地址</td>
				<td>薪水</td>
				<td>创建时间</td>
				<td>操作</td>
			</tr>
		</thead>
		<tbody id="tbody">
			<c:forEach  items="${emps}" var="e">
				<tr>
					<td>${e.eid}</td>
					<td>${e.eno}</td>
					<td>${e.ename}</td>
					<td>${e.age}</td>
					<td>${e.sex}</td>
					<td>${e.address}</td>
					<td>${e.sal}</td>
					<td>
					<fmt:formatDate value="${e.createdTime}" pattern="yyyy-MM-dd HH:mm:ss"/>
					</td>
					<td>
						<a href="#">编辑</a>
						<a href="/emp/deleteById?eid=${e.eid}">删除</a>
					</td>
				</tr>
			</c:forEach>
		</tbody>
	</table>
</body>
</html>
复制代码

13.启动tomcat,访问页面,测试功能

  • 项目目录

image.png

SSM三大框架集成就完成了