1.SSM集成框架

1.1.SSM集成框架简介

1.1.1.为什么要使用SSM集成框架

时至今日,MVC三层架构仍然是我们开发应用程序时所采用的主流架构模式,而 SpringMVC 就是一款优秀的 MVC 框架。那么,为什么我们仍然要将 SpringMVC 与 Spring、MyBatis 集成在一起使用呢。
首先,SpringMVC 对持久层没有任何支持,所以持久层需要使用 MyBatis。其次,为了将 SpringMVC 和 MyBatis 所需组件解耦,需要由 Spring 为其注入。这就是为什么要 SSM 集成的原因。

1.1.2.SSM集成分析

简单来说:SSM集成就是使用 Spring 给 SpringMVC 和 MyBatis 注入所需要组件。
具体来说:SSM集成就是:

  1. 由 SpringMVC 负责搭建 MVC 架构,由 MyBatis 负责持久层。
  2. 由 Spring 给 SpringMVC 注入控制层组件、业务层组件、数据层组件等。
  3. 由 Spring 给 MyBatis 注入数据源、SqlSessionFactory、事务等。

    1.2.SSM集成

    1.2.1.创建Maven工程并添加依赖

    02.SSM集成 - 图1
    在pom.xml文件中添加如下依赖
    1. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    2. <modelVersion>4.0.0</modelVersion>
    3. <groupId>com.neusoft</groupId>
    4. <artifactId>ssm</artifactId>
    5. <version>0.0.1-SNAPSHOT</version>
    6. <packaging>war</packaging>
    7. <!-- 添加项目jdk编译插件 -->
    8. <build>
    9. <plugins>
    10. <!-- 设置jdk版本 -->
    11. <plugin>
    12. <groupId>org.apache.maven.plugins</groupId>
    13. <artifactId>maven-compiler-plugin</artifactId>
    14. <configuration>
    15. <source>1.8</source>
    16. <target>1.8</target>
    17. <encoding>utf-8</encoding>
    18. </configuration>
    19. </plugin>
    20. </plugins>
    21. </build>
    22. <properties>
    23. <spring.version>5.2.8.RELEASE</spring.version>
    24. </properties>
    25. <dependencies>
    26. <!-- 此依赖会关联引用Spring中的所有基础jar包 -->
    27. <dependency>
    28. <groupId>org.springframework</groupId>
    29. <artifactId>spring-context</artifactId>
    30. <version>${spring.version}</version>
    31. </dependency>
    32. <!-- SpringMVC的jar包 (会依赖spring-web)-->
    33. <dependency>
    34. <groupId>org.springframework</groupId>
    35. <artifactId>spring-webmvc</artifactId>
    36. <version>${spring.version}</version>
    37. </dependency>
    38. <!-- Spring支持jdbc的jar包(会依赖 spring-tx事务jar包) -->
    39. <dependency>
    40. <groupId>org.springframework</groupId>
    41. <artifactId>spring-jdbc</artifactId>
    42. <version>${spring.version}</version>
    43. </dependency>
    44. <!-- aspectj依赖jar包 -->
    45. <dependency>
    46. <groupId>org.aspectj</groupId>
    47. <artifactId>aspectjweaver</artifactId>
    48. <version>1.8.7</version>
    49. </dependency>
    50. <!-- jackson依赖jar包 -->
    51. <dependency>
    52. <groupId>com.fasterxml.jackson.core</groupId>
    53. <artifactId>jackson-databind</artifactId>
    54. <version>2.9.0</version>
    55. </dependency>
    56. <!--mybatis 依赖包 -->
    57. <dependency>
    58. <groupId>org.mybatis</groupId>
    59. <artifactId>mybatis</artifactId>
    60. <version>3.5.1</version>
    61. </dependency>
    62. <!-- mybatis-spring 依赖包 -->
    63. <dependency>
    64. <groupId>org.mybatis</groupId>
    65. <artifactId>mybatis-spring</artifactId>
    66. <version>2.0.0</version>
    67. </dependency>
    68. <!-- mysql驱动 依赖包 -->
    69. <dependency>
    70. <groupId>mysql</groupId>
    71. <artifactId>mysql-connector-java</artifactId>
    72. <version>5.1.6</version>
    73. </dependency>
    74. </dependencies>
    75. </project>

    1.2.2.加载Spring容器

    在Web项目中,如果每次请求时都要读取 Spring 配置文件并加载 Spring 容器,将会很耗费资源。所以我们要在服务器启动时,就加载 Spring 容器。
    所以,我们可以在 ServletContext 监听器中监听 服务器启动,然后加载 Spring 容器。而且,这个监听器 Spring已经做好了,我们只要在 web.xml 文件中配置即可。
    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
     <!-- Spring整合web项目用的ServletContext监听器 -->
     <listener>
         <listener-class>
             org.springframework.web.context.ContextLoaderListener
         </listener-class>
     </listener>
     <!-- 指定spring配置文件路径,默认加载 /WEB-INF/applicationContext.xml -->
     <context-param>
         <param-name>contextConfigLocation</param-name>
         <param-value>classpath:applicationContext.xml</param-value>
     </context-param>
    </web-app>
    

    1.2.3.创建Spring容器

    创建applicationContext.xml 配置文件,也就是 Spring 容器。
    <?xml version="1.0" encoding="UTF-8"?>
    <beans
     xmlns="http://www.springframework.org/schema/beans"
     xmlns:context="http://www.springframework.org/schema/context"
     xmlns:tx="http://www.springframework.org/schema/tx"
     xmlns:aop="http://www.springframework.org/schema/aop"
     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/context 
                         http://www.springframework.org/schema/context/spring-context.xsd
                         http://www.springframework.org/schema/tx 
                         http://www.springframework.org/schema/tx/spring-tx.xsd
                         http://www.springframework.org/schema/aop 
                         http://www.springframework.org/schema/aop/spring-aop.xsd">
     <!-- 后面会陆续的添加内容 -->
    </beans>
    

    1.2.4.集成MyBatis

    1.2.4.1.创建Mapper接口

    package com.neusoft.ssm.mapper;
    import org.apache.ibatis.annotations.Mapper;
    import com.neusoft.ssm.po.Dept;
    @Mapper
    public interface DeptMapper {
     public Dept getDeptById(Integer deptno);
    }
    

    注意:Mapper接口需要使用 @Mapper 注解

1.2.4.2.创建映射文件

<?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="com.neusoft.ssm.mapper.DeptMapper">
    <select id="getDeptById" parameterType="int" resultType="Dept">
        select * from dept where deptno=#{deptno}
    </select>
</mapper>

1.2.4.3.在Spring容器中配置MyBatis

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/emp?characterEncoding=utf-8
jdbc.username=root
jdbc.password=123
<!-- 引入db配置文件  -->
<context:property-placeholder location="classpath:db.properties" />
<!-- 配置dataSource数据源 -->
<bean id="dataSource"
        class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="${jdbc.driver}"></property>
    <property name="url" value="${jdbc.url}"></property>
    <property name="username" value="${jdbc.username}"></property>
    <property name="password" value="${jdbc.password}"></property>
</bean>
<!-- 创建SqlSessionFactory,并配置实体对象别名 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource"></property>
    <property name="typeAliasesPackage" value="com.neusoft.ssm.po" />
</bean>
<!-- 配置Mapper。自动扫描Mapper接口,并为其注入SqlSessionFactory -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="basePackage" value="com.neusoft.ssm.mapper"></property>
    <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
</bean>
<!-- 配置Spring提供的事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 开启注解事务 -->
<tx:annotation-driven transaction-manager="transactionManager"/>

1.2.5.集成SpringMVC

实际上,Spring 框架中包含 SpringMVC ,所以 SpringMVC 本身不需要集成。所以,下面除了做SpringMVC的相关配置外,主要是注入 service 组件。

1.2.5.1.配置SpringMVC前端控制器

<servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
           <param-name>contextConfigLocation</param-name>
        <param-value>classpath:springmvc-servlet.xml</param-value>
    </init-param>
</servlet>
<servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>
<!--使⽤Rest风格的URI,将页⾯普通的post请求转为指定的delete或者put请求,可选的配置-->
<filter>
    <filter-name>HiddenHttpMethodFilter</filter-name>
    <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>HiddenHttpMethodFilter</filter-name>
    <servlet-name>springmvc</servlet-name>
</filter-mapping>
<filter>
    <filter-name>HttpPutFormContentFilter</filter-name>
    <filter-class>org.springframework.web.filter.HttpPutFormContentFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>HttpPutFormContentFilter</filter-name>
    <servlet-name>springmvc</servlet-name>
</filter-mapping>

1.2.5.2.创建SpringMVC配置文件

创建springmvc-servlet.xml 配置文件,也就是 SpringMVC的配置文件。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    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/context
                        http://www.springframework.org/schema/context/spring-context.xsd
                        http://www.springframework.org/schema/aop
                        http://www.springframework.org/schema/aop/spring-aop.xsd
                        http://www.springframework.org/schema/mvc
                        http://www.springframework.org/schema/mvc/spring-mvc.xsd">
    <mvc:annotation-driven />
    <context:component-scan base-package="com.neusoft.ssm.controller" />
</beans>

1.2.5.3.创建service组件

package com.neusoft.ssm.service;
import com.neusoft.ssm.po.Dept;
public interface DeptService {
    public Dept getDeptById(Integer deptno);
}
package com.neusoft.ssm.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.neusoft.ssm.mapper.DeptMapper;
import com.neusoft.ssm.po.Dept;
import com.neusoft.ssm.service.DeptService;
@Service
public class DeptServiceImpl implements DeptService{
    @Autowired
    private DeptMapper deptMapper;
    @Override
    @Transactional
    public Dept getDeptById(Integer deptno) {
        return deptMapper.getDeptById(deptno);
    }
}

注意:

  1. 使用 @Service 注解标识这是一个 service 组件。
  2. 使用 @Autowired 注解自动注入 mapper 组件。

1.2.5.3.创建SpringMVC处理器

package com.neusoft.ssm.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.neusoft.ssm.po.Dept;
import com.neusoft.ssm.service.DeptService;
@Controller
public class DeptController {
    @Autowired
    private DeptService deptService;
    @ResponseBody
    @RequestMapping("/getDeptById")
    public Dept getDeptById(Integer deptno) throws Exception{
        return deptService.getDeptById(deptno);
    }
}

注意:使用 @Autowired 注解注入 service 组件。

1.2.5.4.在Spring容器中添加service组件

<context:component-scan base-package="com.neusoft.ssm.service" />

1.2.6.测试

至此,SSM集成完毕。整个工程的目录结构如下:
02.SSM集成 - 图2
接下来,将此工程部署在Tomcat中,启动Tomcat,在浏览器地址栏中输入:http://localhost:8080/ssm/getDeptById?deptno=10 进行测试。

1.2.7.SSM中两个Spring容器的总结

  1. springmvc-servlet.xml:这是SpringMVC框架的专用Spring容器。所以这里只写与SpringMVC相关组件的配置。
  2. applicationContext.xml:这是整个工程的Spring容器。所以,除了SpringMVC之外的其它组件,都要配置在这里。比如:dao、service、事务等等。

  3. 2.纯注解式SSM集成

    时下还是非常流行注解方式编程的,那么下面就使用纯注解的方式实现SSM集成。
    所谓纯注解方式就是:除了pom.xml文件外,工程中没有任何一个配置文件。

    2.1.创建Maven工程并添加依赖

    pom.xml文件中的内容同上。只是添加一个servlet-api的依赖即可:

    <project>
     <!-- 同上 -->
     <dependencies>
         <!-- 同上 -->
         <!-- 增加servlet-api依赖 -->
         <dependency>
             <groupId>javax.servlet</groupId>
             <artifactId>javax.servlet-api</artifactId>
             <version>4.0.0</version>
             <scope>provided</scope>
         </dependency>
     </dependencies>
    </project>
    

    2.2.创建工程总配置类

    在类路径下创建AppInitializer.java文件

    package com.neusoft.ssma;
    import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
    public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer{
     /**
      * 返回一个带有@Configuration注解的类。
      * 用来创建整个应用程序的全局Spring容器。
      * 也就是等同于创建applicationContext.xml容器
      */
     @Override
     protected Class<?>[] getRootConfigClasses() {
         return new Class[] {RootConfig.class};
     }
     /**
      * 返回一个带有@Configuration注解的类。
      * 用来创建SpringMVC(即Web相关)的Spring容器。
      * 也就是等同于创建springmvc-servlet.xml容器
      */
     @Override
     protected Class<?>[] getServletConfigClasses() {
         return new Class[] {WebConfig.class};
     }
     //配置SpringMVC前端控制器映射路径
     @Override
     protected String[] getServletMappings() {
         return new String[] {"/"};
     }
    }
    

    在servlet3.0以上环境中,web容器会在类路径中查找实现了javax.servlet.ServletContainerInitializer接口的类,如果能找到此类就会用它来配置Servlet容器。
    Spring3.2之后,提供了这个接口的实现,它是一个抽象类:AbstractAnnotationConfigDispatcherServletInitializer。
    要实现AbstractAnnotationConfigDispatcherServletInitializer的三个抽象方法:

  4. getRootConfigClasses:用来创建整个应用程序的全局Spring容器(等同于applicationContext.xml)。

  5. getServletConfigClasses:用来创建SpringMVC(即Web相关)的Spring容器。(等同于springmvc-servlet.xml)
  6. getServletMappings:配置SpringMVC前端控制器映射路径(SpringMVC前端控制器已自动注入)。

    总结:AppInitializer.java就相当于:web.xml + applicationContext.xml + springmvc-servlet.xml

2.3.创建Spring容器配置类

在类路径下创建RootConfig.java文件,它就相当于applicationContext.xml。

package com.neusoft.ssma;
import javax.sql.DataSource;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.transaction.PlatformTransactionManager;
@Configuration
//@ComponentScan用于扫描通用组件,这里用来扫描Service组件
@ComponentScan(basePackages={"com.neusoft.ssma.service"})
//@MapperScan用于扫描Mapper组件
@MapperScan(basePackages="com.neusoft.ssma.mapper")
public class RootConfig {
    //创建dataSource组件并放入Spring容器
    @Bean
    public DataSource dataSource()  {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/emp?characterEncoding=utf-8");
        dataSource.setUsername("root");
        dataSource.setPassword("123");
        return dataSource;
    }  
    //创建SqlSessionFactory组件并放入Spring容器
    @Bean
    public SqlSessionFactoryBean sqlSessionFactoryBean(){
      SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
      sqlSessionFactoryBean.setDataSource(dataSource());
      return sqlSessionFactoryBean;
    }    
    //创建PlatformTransactionManager组件并放入Spring容器
    @Bean
    public PlatformTransactionManager transactionManager(DataSource dataSource){
        //dataSource也可以通过参数注入
        return  new DataSourceTransactionManager(dataSource());
    }
}

2.4.创建Web相关Spring容器

在类路径下创建WebConfig.java文件,它就相当于springmvc-servlet.xml。

package com.neusoft.ssma;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
@Configuration
//SpringMVC注解,等同于<mvc:annotation-driven/>
@EnableWebMvc
//@ComponentScan用于扫描通用组件,这里用来扫描Controller组件
@ComponentScan(basePackages={"com.neusoft.ssma.controller"})
public class WebConfig{ }

2.5.创建其它组件

Controller组件、Service组件、Mapper组件同上,没有任何变化。

2.6.测试

至此,纯注解式SSM集成完毕。整个工程的目录结构如下:
02.SSM集成 - 图3
接下来,将此工程部署在Tomcat中,启动Tomcat,在浏览器地址栏中输入:http://localhost:8080/ssm/getDeptById?deptno=10 进行测试。

3.注解和XML

  • 注解:是一种分散式的元数据,与源代码紧绑定。
  • xml:是一种集中式的元数据,与源代码无绑定。

    元数据:描述数据的数据

3.1.XML的优点与缺点

  1. 优点:
    • xml是集中式的元数据,不需要和代码绑定的
    • 更具有扩展性。修改配置时只需要修改xml即可,不需要对现有的程序进行修改
    • 组件之间的关系一目了然
    • 有成熟的校验机制来保证正确。比如使用Schema或者是DTD来对xml的正确性进行校验
  2. 缺点:

    • 需要解析xml的工具或者是是第三方类库的支持
    • 解析xml的时候必然会占用资源,势必会影响到应用程序的性能
    • xml配置文件过多,会导致维护变得困难
    • 在程序编译期间无法对其配置项的正确性进行验证,只能在运行期发现

      3.2.注解的优点与缺点

  3. 优点:

    • 简化了XML配置,使用起来更直观
    • 类型安全,编译期即可验证正确性。XML只能在运行期才能发现问题
    • 只维护代码即可,不用再维护其它文件
  4. 缺点:

    • 注解分散到很多类中,不好管理和维护
    • 注解的开启/关闭必须修改源代码,因为注解是源代码绑定的
    • 在实现复杂的逻辑上,没有XML功能强大

      3.3.总结

      首先,不管使用注解还是XML,做的事情还是那些事情。而且注解和XML都各有各的优点和缺点,所以,能够满足自己的需求,且以一种自己认为简单的方式解决掉问题即可。
      其次,虽然Spring官方没有明说抛弃xml配置,不过事实上Spring已经转往注解配置方向前进了,SpringBoot就是最好的例子。
      SpringBoot中只有一个properties文件负责配置一些不可避免的设定,除此之外没有任何一个xml文件来定义bean,全部都是使用注解来配置。

      本章作业
  5. Spring 在SSM中起什么作用?

  6. 在SSM中还需要MyBatis配置文件吗?
  7. SSM中两个Spring容器的作用分别是什么?
  8. 什么是纯注解式SSM集成?
  9. 在纯注解式SSM集成中的配置入口是什么?
  10. AbstractAnnotationConfigDispatcherServletInitializer的三个抽象方法的作用是什么?
  11. 到底是使用xml配置方式,还是纯注解式来实现SSM集成?
  12. 编程题:
    1. 使用SSM集成框架实现一个登录案例。
    2. 使用前后端分离的模式实现。
    3. 服务器端要有数据层组件、业务层组件、控制层组件。
    4. 数据层组件使用MyBatis框架完成对数据库的操作。
    5. 控制层组件要向前端返回json数据。
    6. 前端使用ajax请求,并通过服务器端返回的json数据来判断是否登录成功。