SSM framework integration

1. Basic introduction

SSM framework: SpringMVC, Spring, Mybatis three frameworks; first remember the order of these three frameworks, I personally think that the key to integration is Spring .

Mybatis: An excellent lightweight framework for the persistence layer, responsible for the interaction with the database; the Dao layer is written for the Service layer to call, and the Service layer is for the Controller layer to call!

SpringMVC: A lightweight framework at the Web level, the core is the front controller DispatcherServlet, you only need to write the Controller layer to call the Service layer!

Spring: I personally think that the key to integration depends on the integration of Spring and Spring in the three major frameworks. First, let’s take a look at what Spring will do:

First, an agent is required to host the core configuration files of Mybatis, data sources (dataSources), SQL executor factory (SqlSessionFactroy), and SQL executor (SqlSession). In fact, this step is to integrate the operation of the entire dao layer.

Secondly, the service level is integrated, and the service level calls the Dao level; transactions need to be configured and aop is used for transaction configuration in some operations.

Finally, integrate the configuration files of SpringMVC and add all the configurations of SpringMVC to the core of Spring!

Because of this, I personally think that Spring is the core of the core, and I support SpringMVC and Mybatis by my own efforts; it perfectly integrates the Controller layer with the Service layer and the Dao layer! (As shown below)

Insert picture description here



2. Preparation for project construction

Tools: IDEA 2021, Maven, MySQL5.7...

Basic project dependencies: Junit test 4.12, JDBC driver 5.1.47, Servlet4.0.1, JSP2.33, JSTL tag library 1.2...

Framework dependencies: mybatis3.5.3, mybatis-spring2.0.6, spring-webmvc5.3.5, spring-orm5.3.5, spring-jdbc5.3.5, spring-jcl5.3.5...

Other dependencies: druid data source, jackson, aspectjweaver weaving, lombok annotations; these are all options to find the corresponding replacement.

2.1, project creation

First create a Maven project and check the webapp template. (You can also uncheck in add FrameWord to select Web)

Insert picture description here


Take gav as you like, there are no specific requirements; then find the maven configuration and maven warehouse; and finally finish directly.

2.2, project construction

Here, because the webapp template is checked, some things need to be changed:

Change the jdk in maven from 1.7 to 1.8

Import project dependencies

And add filtering resource export problem

<build>
    <!-- 解决资源导出问题 -->
    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>true</filtering>
        </resource>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>true</filtering>
        </resource>
    </resources>
</build>

<dependencies>
    <!-- Junit测试包 -->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13</version>
    </dependency>
    <dependency>
        <groupId>org.hamcrest</groupId>
        <artifactId>hamcrest-core</artifactId>
        <version>1.3</version>
    </dependency>

    <!-- lombok注解、jackson、jdbc、druid数据源、aop织入 -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.12</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.11.4</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.47</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.1.10</version>
    </dependency>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.9.6</version>
    </dependency>


    <!-- spring、mybatis依赖-->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.3</version>
    </dependency>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>2.0.6</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.3.5</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-orm</artifactId>
        <version>5.3.5</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.3.5</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jcl</artifactId>
        <version>5.3.5</version>
    </dependency>


    <!-- Servlet全家桶 -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>4.0.1</version>
    </dependency>
    <dependency>
        <groupId>javax.servlet.jsp</groupId>
        <artifactId>javax.servlet.jsp-api</artifactId>
        <version>2.3.3</version>
    </dependency>
    <dependency>
        <groupId>javax.servlet.jsp.jstl</groupId>
        <artifactId>jstl-api</artifactId>
        <version>1.2</version>
    </dependency>
    <dependency>
        <groupId>taglibs</groupId>
        <artifactId>standard</artifactId>
        <version>1.1.2</version>
    </dependency>

</dependencies>


2.3. Create a package and configuration file
Insert picture description here
  • spring-xxx.xml configuration file skeleton
<?xml version="1.0" encoding="UTF8"?>
<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:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="
    http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd
    http://www.springframework.org/schema/tx  https://www.springframework.org/schema/tx/spring-tx.xsd
    http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">

</beans>
  • mybatis-config.xml configuration file skeleton
<?xml version="1.0" encoding="UTF8"?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Configuration 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>


</configuration>



3. Integrate mybatis (dao layer)

Create a basic database, table, add some data to facilitate testing; create the corresponding pojo entity class

Write dao layer interface code

Write the mapper configuration file

Configure the mybatis-config.xml configuration file and register the mapper.xml

db.properties file configuration database connection parameters

Core : spring-dao.xml configuration file for configuration

3.1, create a data table and POJO entity class

Database creation

create database ssmmerge
create table login(
    `id` int(11) not null auto_increment comment '编号',
    `username` varchar(30) not null comment '账号',
    `password` varchar(30) not null comment '密码',
    primary key(`id`) 
)engine=innodb default charset=utf8;
insert into login(`id`, `username`, `password`) values (1, 'admin', '123456')

Corresponding entity classes, it is best to have a one-to-one correspondence with the fields; otherwise, you need to use ResultMap mapping in xml to solve.

@Data                       //get方法、set方法、toString...
@AllArgsConstructor         //全参构造
@NoArgsConstructor          //无参构造
public class Login implements Serializable {        //pojo类最好都实现序列化接口
    private int id;
    private String username;
    private String password;
}


3.2, write the code of the dao layer

The business is to query the account and log in as a test

package com.merge.dao;

import com.merge.pojo.Login;
import org.apache.ibatis.annotations.Param;

public interface LoginMapper {

    //查询登入账户
    public Login getLoginAccount(@Param("username") String username);

}


3.3, write the corresponding mapper configuration file

namespace binding interface, id binding method, parameterType setting parameter type, resultType setting return result type

<?xml version="1.0" encoding="UTF8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.merge.dao.LoginMapper">

    <select id="getLoginAccount" parameterType="string" resultType="Login">
        select *from login where username = #{username}
    </select>

</mapper>


3.4, configure the mybatis-config.xml file

Open the log that comes with mybatis, give the pojo entity class a short name, and register the mapper

All other loading is managed by Spring!

<?xml version="1.0" encoding="UTF8"?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Configuration 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

    <settings>
        <!-- 开启mybatis自带的日志 -->
        <setting name="logImpl" value="STDOUT_LOGGING"/>

    </settings>

    <typeAliases>
        <typeAlias type="com.merge.pojo.Login" alias="Login"/>
    </typeAliases>

    <mappers>
        <mapper class="com.merge.dao.LoginMapper"/>
    </mappers>
</configuration>


3.5, configure the db.properties file

The jdbc. prefix must be added here; otherwise, it cannot be successfully loaded when Spring is injected.

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ssmmerge?useSSL=true&useUnicode=true&characterEncoding=UTF-8
jdbc.username=root
jdbc.password=123456


3.6, configuration of spring-dao.xml

This is one of the three cores of the entire integrated business, and it is also the most complex; let’s take a look at roughly what to accomplish:

Since there are only skeletons and some basic mapper registrars left in the mybatis-config.xml configuration file (of course, these can also be added to Spring to achieve a completely less configuration file); therefore, the configuration of the data source must be the first step to be completed (Also load the db file)

When I first learn mybatis, I will write a mybatisUtils tool class to complete the construction of the SqlSessionFactory factory (singleton factory). This step is not loaded in mybatis and is fully handed over to Spring's IOC container for hosting.

Complete the realization of the dao interface, here is not unique; you can create the implementation class and then create the bean of the SqlSession in Spring; you can also omit the implementation class directly, and Spring will complete the reflection creation of the implementation class of the interface (commonly used)

<!-- 1. 加载连接参数 -->
<context:property-placeholder location="db.properties" file-encoding="UTF-8"/>

<!-- 2. 配置数据源 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
    <property name="driverClassName" value="${jdbc.driver}"/>
    <property name="url" value="${jdbc.url}"/>
    <property name="username" value="${jdbc.username}"/>
    <property name="password" value="${jdbc.password}"/>
    <!-- 这里还可以配置一些其他参数:最大连接数、超时时间...-->
    <property name="maxActive" value="20"/>
</bean>

<!-- 3. 创建SqlSessionFactory工厂, 手动封装一下为单例模式(默认不写就是单例) -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean" scope="singleton">
    <!-- 注入数据源 -->
    <property name="dataSource" ref="dataSource"/>
    
    <!-- 托管mybatis-config.xml配置文件-->
    <property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>

<!-- 4. 扫描dao下的所有包,dao接口的实现类由Spring来反射创建 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <!-- 将上述的SqlSessionFactory的bean注入进来,注意这里用value!不是ref -->
    <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
    <!-- 扫描dao下的接口,接口实现类由Spring反射创建 -->
    <property name="basePackage" value="com.merge.dao"/>
</bean>

<!-- 注: 手动写实现类时需要配置 -->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
    <constructor-arg ref="sqlSessionFactory"/>
</bean>

At this point, the spring-mybatis integration is completed, and the rest is the integration of the service layer and the controller layer.

Note: Whether the final sqlSession needs to create a bean depends on whether the business in the code completes the implementation class of the interface by hand, of course, it is also possible to directly implement the class without injecting it to inherit the SqlSessionDaoSupport class...too many ways to write



4. Integrate the Service level

First of all, it is clear: the Service layer is only responsible for calling the dao layer, and throws the calling interface to the Controller.

Create the LoginService interface and implementation class.

A dao interface is aggregated inside the implementation class, and then automatically injected into it using the @Autowired annotation. (Use the @Qualifier annotation to specify if it is not the only case)

The business layer is a very sensitive layer. A business has only two results: success or failure in the program; therefore, it is necessary to configure the transaction, using Spring's declarative transaction for configuration; the principle is that aop cuts in horizontally.

4.1, write LoginService interface

The interface is relatively simple, and the purpose of writing the interface is for the convenience of later maintenance and expansion; there is also an important point: aop cut-in transaction is to use the JDK proxy! Need interface (Cglib proxy can be ignored!)

package com.merge.service;

import com.merge.pojo.Login;

public interface LoginService {

    //查询登入账户
    public Login getLoginAccount(String username);

}


4.2, write LoginServiceImpl implementation class

The business layer is very pure, basically simply completing the realization of each method. The configuration of the transaction does not need to be implemented manually, and the transaction that comes with Spring uses the idea of ​​aop to cut in and automatically complete it!

package com.merge.service;

import com.merge.dao.LoginMapper;
import com.merge.pojo.Login;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service("loginService")
/*
@Transactional(
        propagation = Propagation.REQUIRED,
        isolation = Isolation.REPEATABLE_READ,
        timeout = 60000,
        readOnly = false
)
*/
public class LoginServiceImpl implements LoginService{

    @Autowired          //自动注入
    private LoginMapper loginMapper;

    @Override
    public Login getLoginAccount(String username) {
        Login account = loginMapper.getLoginAccount(username);
        return account;
    }
}


4.3, spring-service.xml configuration

The configuration file of the service layer is mainly for declarative transactions and completes the configuration of declarative transactions. Of course these declarative transactions can also be configured in the class...

  • Note: If you configure the transaction at the Service level, you need to use the @Transactional annotation, which can be used on methods or classes (indicating that all methods open transactions)
<!-- 1. 开启注解扫描 -->
<context:component-scan base-package="com.merge.service"/>
<context:annotation-config/>

<!-- 2. 创建事务 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>

<!-- 3. 配置事务参数 -->
<tx:annotation-driven/>
<tx:advice id="transactionInterceptor" transaction-manager="transactionManager">
    <!--
        *: 表示所有的方法
        propagation:传播行为
        isolation: 隔离级别使用可重复读
        timeout: 超时60s
        read-only: 是否只读,false。
    -->
    <tx:attributes>
        <tx:method name="*" propagation="REQUIRED" isolation="REPEATABLE_READ" timeout="60000" read-only="false"/>
    </tx:attributes>
</tx:advice>

<!-- 4. aop横向切入事务 -->
<aop:config>
    <!-- 定义切入点 -->
    <aop:pointcut id="pt" expression="execution(* com.merge.service.LoginServiceImpl.*(..))"/>
    <aop:advisor advice-ref="transactionInterceptor" pointcut-ref="pt"/>
</aop:config>



5. Integrate the Controller layer

The Controler layer is in charge of the SpringMVC framework, but the SpringMVC framework is a part of the Spring framework and became independent in the 3.x version. Spring integration with SpringMVC can achieve non-intrusive and seamless integration.

First prepare a few basic pages and prepare some basic resources.

Write the corresponding Controller layer, call the Service layer to complete business operations; finally give a response!

Configure the spring-mvc.xml file.

5.1, static resources

Import jquery, pictures, and write some pages.

  • Home login page index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>SSM整合</title>
</head>
<body>
    <h1>Welcome to Login</h1>
    <div>
        <span>${msg}</span>
        <form method="post" action="${pageContext.request.contextPath}/user/login">
            用户名: <input type="text" name="username" required>
            密码: <input type="text" name="password" required>
            <input type="submit" value="登录">
            <input type="reset" value="重置">
        </form>
    </div>
    <hr/>
    <img src="${pageContext.request.contextPath}/static/img/bg.jpg" width="500px" height="500px">
</body>
</html>
  • Successful login page center.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>首页</title>
</head>
<body>
    <h1>${msg}</h1>
    <h1>账户名: ${username}</h1>
    <h1>密码: ${password}</h1>
</body>
</html>
  • Login failed page error.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>错误页面</title>
</head>
<body>
    <h1>${msg}</h1>
    <a href="${pageContext.request.contextPath}/index.jsp">点击回到首页重新登入</a>
</body>
</html>


5.2, the preparation of the Controller

The Controller layer is also very pure, receiving requests, calling the Service layer, and responding to the view. As for the details of how the Service layer is called and handled, the Controller said it doesn't care!

package com.merge.controller;

import com.merge.pojo.Login;
import com.merge.service.LoginService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
@RequestMapping("/user")
public class LoginController {

    @Autowired
    private LoginService loginService;

    @RequestMapping("/login")
    public ModelAndView LoginCheck(String username, String password){
        ModelAndView mv = new ModelAndView();
        Login account = loginService.getLoginAccount(username);
        if(account.getPassword().equals(password)){
            mv.addObject("username", username);
            mv.addObject("password", password);
            mv.addObject("msg", "Successful!");
            mv.addObject("id", account.getId());
            mv.setViewName("center");
        }
        else{
            mv.addObject("msg", "账户或密码错误!");
            mv.setViewName("error");
        }
        return mv;
    }
}


5.3, configure the spring-mvc.xml file

The spring-mvc.xml configuration file only configures things that only care about the naked web level, the processing of static resources, the view parser, the scan controller annotations, and the format of response data...

<!-- 1. 开启注解驱动加载bean -->
<context:component-scan base-package="com.merge.controller"/>
<context:annotation-config/>

<!-- 2. 配置视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/page/"/>
    <property name="suffix" value=".jsp"/>
</bean>

<!-- 3. 配置静态资源加载, 加载static包下的所有静态资源 -->
<mvc:resources mapping="/static/**" location="/static/"/>

<!-- 4. 配置HttpMessageConverter消息转换 -->
<mvc:annotation-driven>
    <mvc:message-converters register-defaults="true">
        <bean class="org.springframework.http.converter.StringHttpMessageConverter">
            <constructor-arg value="UTF-8"/>
        </bean>
        <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
            <property name="objectMapper">
                <bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
                    <property name="failOnUnknownProperties" value="false"/>
                </bean>
            </property>
            <property name="defaultCharset" value="UTF-8"/>
        </bean>
    </mvc:message-converters>
</mvc:annotation-driven>



6. SSM three-layer integration

Although each layer is integrated, it needs to be configured into Spring together in the end, which is in charge of Spring.

And set up the web.xml configuration file

6.1, applicationContext.xml

The big brother of all xml configuration files integrates all the configuration files, and then hands them to tomcat to load.

<context:annotation-config/>

<!-- 1. 整合mybatis、dao -->
<import resource="classpath:spring-dao.xml"/>

<!-- 2. 整合service层 -->
<import resource="spring-service.xml"/>

<!-- 3. 整合Controller层 -->
<import resource="spring-mvc.xml"/>
Insert picture description here



6.2, web.xml configuration

Some basic things are mainly configured in web.xml:

Load the applicationContext.xml configuration file so that when Tomcat starts, all containers and all beans are created in the init method of Servlet...

Configure basic filters to filter character encoding issues.

Of course, you can also configure some basic things here, such as session expiration time, setting the project home page...

<?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_4_0.xsd"
         version="4.0">

    <servlet>
        <servlet-name>app</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:applicationContext.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>app</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <filter>
        <filter-name>EncodingFilter</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>EncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <session-config>
        <session-timeout>15</session-timeout>
    </session-config>
</web-app>


6.3, the final result graph
Insert picture description here





7. Integration test

At this point, the three major frameworks of SSM have been integrated, and almost all configuration files will not undergo major changes after the integration.

Only the mybatis-config.xml configuration file will continue to register some mappers due to business expansion.

Of course, there are still many things that have not been added to all the above integrations, such as the interceptor of SpringMVC (aop idea), the secondary cache of Mybatis...

Insert picture description here



Insert picture description here