前言

  • 服务器开发分为三层:表现层 + 业务层 + 持久层

  • 整合的桥梁或者说是方式,我们使用:XML(配置文件)+ 注解的方式

整合的整体思路:

  1. 搭建整合的环境(引入依赖,创建包,创建实体类)
  2. 先搭建好 Spring
  3. Spring 整合 SpringMVC
  4. Spring 整合 MyBatis

image-20210318205124357

包结构:

image-20210318210741556

搭建整合环境

数据库部分

1
2
3
4
5
6
7
8
create database ssm;
use ssm;
create table account(
id int primary key auto_increment,
name varchar(20),
money double
);

依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<spring.version>5.0.2.RELEASE</spring.version>
<slf4j.version>1.6.6</slf4j.version>
<log4j.version>1.2.12</log4j.version>
<mysql.version>5.1.6</mysql.version>
<mybatis.version>3.4.5</mybatis.version>
</properties>

<dependencies>
<!-- spring -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.8</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>compile</scope>
</dependency>

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>

<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>

<!-- log start -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
</dependency>

<!-- log end -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>

<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.0</version>
</dependency>

<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
</dependencies>

实体类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
public class Account implements Serializable{

private Integer id;
private String name;
private Double money;

public Account() {
}

public Account(Integer id, String name, Double money) {
this.id = id;
this.name = name;
this.money = money;
}

public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Double getMoney() {
return money;
}

public void setMoney(Double money) {
this.money = money;
}

@Override
public String toString() {
return "Account{" +
"id=" + id +
", name='" + name + '\'' +
", money=" + money +
'}';
}
}

Dao 层

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* 帐户dao接口
*/
@Repository
public interface AccountDao {

// 查询所有账户
public List<Account> findAll();

// 保存帐户信息
public void saveAccount(Account account);

}

Serivice 层

image-20210318210831320

接口

1
2
3
4
5
6
7
8
9
public interface AccountService {

// 查询所有账户
public List<Account> findAll();

// 保存帐户信息
public void saveAccount(Account account);

}

实现类

1
2
3
4
5
6
7
8
9
10
11
public class AccountServiceImpl implements AccountService{

public List<Account> findAll() {
System.out.println("业务层:查询所有账户...");
return null;
}

public void saveAccount(Account account) {
System.out.println("业务层:保存帐户...");
}
}

Spring 搭建

  • 在 Spring 层,我们要进行业务的处理
  1. 创建好配置文件

    image-20210318211034573

  2. 完成配置文件

    1. 开启注解扫描

      1
      2
      3
      4
      5
      <!--开启注解的扫描,希望处理service和dao,controller不需要Spring框架去处理-->
      <context:component-scan base-package="cn.itcast" >
      <!--配置哪些注解不扫描-->
      <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />
      </context:component-scan>
  3. 在 Serivice 层的类上加注解

    1
    @Service("accountService")
  4. 编写测试

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public class TestSpring {

    @Test
    public void run1(){
    // 加载配置文件
    ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
    // 获取对象
    AccountService as = (AccountService) ac.getBean("accountService");
    // 调用方法
    as.findAll();
    }
    }

image-20210318222226498

Spring 整合 SpringMVC

搭建测试 SpringMVC 的开发环境

  1. web.xml 中配置DispatcherServlet前端控制器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <!--配置前端控制器-->
    <servlet>
    <servlet-name>dispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!--加载springmvc.xml配置文件-->
    <init-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:springmvc.xml</param-value>
    </init-param>
    <!--启动服务器,创建该servlet-->
    <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
    <servlet-name>dispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
    </servlet-mapping>
  2. 配置解决中文乱码的过滤器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    <!--解决中文乱码的过滤器-->
    <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>
    </filter>
    <filter-mapping>
    <filter-name>characterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
    </filter-mapping>
  3. 新建 springmvc.xml

    image-20210318214209343

  4. 添加约束

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/mvc
    http://www.springframework.org/schema/mvc/spring-mvc.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd">

    </beans>
  5. 开启注解扫描

    1
    2
    3
    4
    <!--开启注解扫描,只扫描Controller注解 与Spring的注解反过来-->
    <context:component-scan base-package="cn.itcast">
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
    </context:component-scan>
  6. 配置视图解析器

    1
    2
    3
    4
    5
    <!--配置的视图解析器对象-->
    <bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/pages/"/>
    <property name="suffix" value=".jsp"/>
    </bean>
  7. 过滤静态资源

    1
    2
    3
    4
    <!--过滤静态资源-->
    <mvc:resources location="/css/" mapping="/css/**" />
    <mvc:resources location="/images/" mapping="/images/**" />
    <mvc:resources location="/js/" mapping="/js/**" />
  8. 开启注解

    1
    2
    <!--开启SpringMVC注解的支持-->
    <mvc:annotation-driven/>
  • 测试:
  1. 控制层

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    /**
    * 帐户web
    */
    @Controller
    @RequestMapping("/account")
    public class AccountController {

    @RequestMapping("/findAll")
    public String findAll(Model model){
    System.out.println("表现层:查询所有账户...");
    // 调用service的方法
    return "list";
    }

    }
  2. index.jsp

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
    <title>Title</title>
    </head>
    <body>
    <a href="account/findAll">测试查询</a>
    </body>
    </html>
  3. list.jsp

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <html>
    <head>
    <title>Title</title>
    </head>
    <body>
    <h3>查询所有的帐户</h3>

    </body>
    </html>
  4. 结果

    image-20210318215832607

实现整合

问题:

我们知道,SpringMVC 现在的配置是只扫描 Controller 注解,而别的注解不扫,这就导致一个问题,我们的 Spring 的配置文件:applicationContext.xml是没有被加载的,因此里面的扫描也不会生效,那我们的 service 层就是个摆设,根本没有被加载到 IOC 容器中,就没办法注入了。

解决:

启动容器的时候就得把Spring的配置文件给加载了才行;

image-20210318221747580

下面我们就要在 web.xml 中做以下两件事:

  1. 配置 Spring 的监听器

    1
    2
    3
    4
    <!--配置Spring的监听器,默认只加载WEB-INF目录下的applicationContext.xml配置文件-->
    <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
  2. 设置配置文件的路径

    1
    2
    3
    4
    5
    <!--设置配置文件的路径-->
    <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml</param-value>
    </context-param>

此时我们的 Controller 层就可以做到 Service 的注入了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Controller
@RequestMapping("/account")
public class AccountController {

@Autowired
private AccountService accountService;

@RequestMapping("/findAll")
public String findAll(Model model){
System.out.println("表现层:查询所有账户...");
// 调用service的方法
List<Account> list = accountService.findAll();
return "list";
}


}

image-20210318222140952

Spring 整合 MyBatis

搭建测试 MyBatis 环境

ps:配置文件找不到的处理方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
</includes>
</resource>
</resources>
  • dao 接口上加注解,进行映射

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    /**
    * 帐户dao接口
    */
    @Repository
    public interface AccountDao {

    // 查询所有账户
    @Select("select * from account")
    public List<Account> findAll();


    }
  • 编写 sql 配置文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration
    PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <!--configuration核心配置文件-->
    <configuration>
    <environments default="development">
    <environment id="development">
    <transactionManager type="JDBC"/>
    <dataSource type="POOLED">
    <property name="driver" value="com.mysql.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC&amp;useSSL=false"/>
    <property name="username" value="root"/>
    <property name="password" value="123456"/>
    </dataSource>
    </environment>
    </environments>

    <mappers>
    <package name="cn.itcast.dao"/>
    </mappers>
    </configuration>

  • 进行测试

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24

    /**
    * 测试查询
    * @throws Exception
    */
    @Test
    public void run1() throws Exception {
    // 加载配置文件
    InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
    // 创建SqlSessionFactory对象
    SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
    // 创建SqlSession对象
    SqlSession session = factory.openSession();
    // 获取到代理对象
    AccountDao dao = session.getMapper(AccountDao.class);
    // 查询所有数据
    List<Account> list = dao.findAll();
    for(Account account : list){
    System.out.println(account);
    }
    // 关闭资源
    session.close();
    in.close();
    }

image-20210319202414601

image-20210319202613009

Spring 整合 Mybatis 实现

  • 思路:通过让 Spring 框架接管 Mybatis 中的SqlSessionFactory 工厂的创建,再通过读取mapper配置内容去创建dao 的代理对象实现类,将它们(SqlSessionFactory 工厂和代理对象)存入IOC 容器

Mybatis 交由 Spring 托管

分为三步:配置连接池、配置 SqlSessionFactory 工厂、配置接口所在的包

  1. 配置连接池

    1
    2
    3
    4
    5
    6
    7
    <!--配置连接池-->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    <property name="driverClass" value="com.mysql.jdbc.Driver"/>
    <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/ssm?userSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=UTC"/>
    <property name="user" value="root"/>
    <property name="password" value="123456"/>
    </bean>
  2. 配置 SqlSessionFactory 工厂

    1
    2
    3
    4
    <!--配置SqlSessionFactory工厂-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    </bean>
  3. 配置接口所在包

    1
    2
    3
    4
    <!--配置AccountDao接口所在包-->
    <bean id="mapperScanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="basePackage" value="cn.itcast.dao"/>
    </bean>

以上三步的作用:以后我们的 SqlSessionFactory 就将会由 IOC 容器帮助我们创建,接着就可以创建 SqlSession,从而得到我们的 mapper 代理对象,并且这些对象全都在 IOC 容器中,意味着什么呢?就可以实现我们的依赖注入

接下来就来测试一下:

  1. 在 AccountDao 接口上添加@Repository注解

    1
    2
    3
    4
    @Repository
    public interface AccountDao {

    }
  2. Serivice 的实现类中,依赖注入我们的 Dao 类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    @Service("accountService")
    public class AccountServiceImpl implements AccountService{

    @Autowired
    private AccountDao accountDao;

    public List<Account> findAll() {
    System.out.println("业务层:查询所有账户...");
    return accountDao.findAll();
    }

    public void saveAccount(Account account) {
    System.out.println("业务层:保存帐户...");
    accountDao.saveAccount(account);
    }

    }

  3. 编写 Controller 层 增加一个视图封装数据部分

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    @Controller
    @RequestMapping("/account")
    public class AccountController {

    @Autowired
    private AccountService accountService;

    @RequestMapping("/findAll")
    public String findAll(Model model){
    System.out.println("表现层:查询所有账户...");
    // 调用service的方法
    List<Account> list = accountService.findAll();
    model.addAttribute("list",list);
    return "list";
    }


    }
  4. 前端页面

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    <%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <html>
    <head>
    <title>Title</title>
    </head>
    <body>

    <h3>查询所有的帐户</h3>

    <c:forEach items="${list}" var="account">
    ${account.name}
    </c:forEach>


    </body>
    </html>
  5. 测试(这是我已经把 sq 配置文件删除后的,也就代表着 mybatis 的 xml 配置部分已经完全交由 Spring 托管了)

    image-20210319205301055

    image-20210319205134009

引入事务

然而框架尚未完全整合完:我们的整合还差最后一步——那就是引入事务的控制

配置 Spring 框架声明式事务管理分为三步:配置事务管理器、配置事务通知、配置 AOP 增强

  1. 配置事务管理器

    1
    2
    3
    4
    <!--配置事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource" />
    </bean>
  2. 配置事务通知

    1
    2
    3
    4
    5
    6
    7
    <!--配置事务通知-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
    <tx:method name="find*" read-only="true"/>
    <tx:method name="*" isolation="DEFAULT"/>
    </tx:attributes>
    </tx:advice>
  3. 配置 AOP 增强(切入点选择的是 Service 层)

    1
    2
    3
    4
    <!--配置AOP增强-->
    <aop:config>
    <aop:advisor advice-ref="txAdvice" pointcut="execution(* cn.itcast.service.impl.*ServiceImpl.*(..))"/>
    </aop:config>

测试一下:

  1. 前端页面加入保存方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
    <title>Title</title>
    </head>
    <body>
    <a href="account/findAll">测试查询</a>

    <h3>测试包</h3>

    <form action="account/save" method="post">
    姓名:<input type="text" name="name" /><br />
    金额:<input type="text" name="money" /><br />
    <input type="submit" value="保存" /><br />
    </form>
    </body>
    </html>
  2. Controller 层加入 save 方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    /**
    * 保存
    * @return
    */
    @RequestMapping("/save")
    public void save(Account account, HttpServletRequest request, HttpServletResponse response) throws IOException {
    accountService.saveAccount(account);
    response.sendRedirect(request.getContextPath()+"/account/findAll");
    return;
    }
  3. 测试:我们加入一个 姓名 Test 金额 100 的用户

    image-20210319210932389

    image-20210319210941997

image-20210319210948522

至此,我们成功整合了 SSM 框架啦!