- 三层架构
-
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 复制代码
-
-
注意:domain并不算是软件架构的一层,我们的实体类统一都会放在domain中,每一层都会使用到domain中的实体类
- SSM集成
-
SSM集成就是三大框架的集成:Spring + SpringMVC + Mybatis
-
SSM框架集成步骤
1.导入jar包:今日需要用到7类jar包
2.导入数据库表/建立数据库表:今日以员工表为例
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 }"/>  
地址:<input type="text" name="address" value="${query.address }"/>  
薪水:
<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,访问页面,测试功能
- 项目目录
SSM三大框架集成就完成了




近期评论