SSM integration-xml version

1. SSM integration

1.1 Step analysis

①Integrate Mybatis with Spring

Inject the Service layer Dao layer into the Spring container

②Introduce and configure SpringMVC

Inject the Controller layer into the SpringMVC container

③ Let the web project automatically read the Spring configuration file to create the Spring container when the web project starts

You can use ContextLoaderListener to create a Spring container.

1.2 Common doubts

  • Why use two containers?
    Because if the Controller is not placed in the MVC container, it will have no effect and cannot process the request. If the Service is not placed in the Spring container, declarative transactions cannot be used.

  • The Controller in the SpringMVC container needs to rely on the Service. Can it obtain the dependent Service object from the Spring container?
    The Spring container is equivalent to the parent container, and the MVC container is equivalent to the child container. In addition to using objects in its own container, child containers can also use objects in the parent container.

  • How to achieve such a parent-child container relationship?
    For details, you can watch the video of the source code analysis stage. But we can currently simulate it with code.

  • When did the two containers have this parent-child relationship?
    In ContextLoaderListener, the container will be stored in the servletContext domain after the container is created. In this way, when the DispatcherServlet starts, after the SpringMVC container is created, the Spring container object will be obtained from the servletContext domain and set as its parent container, so that the child container can obtain the beans in the parent container. See the source code analysis video for details.

1.3 Preparations

import all dependencies

 		<!--Spring-context-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.9.RELEASE</version>
        </dependency>
        <!--AOP相关依赖-->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.13</version>
        </dependency>
        <!-- spring-jdbc -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.1.9.RELEASE</version>
        </dependency>
        <!-- mybatis整合到Spring的整合包 -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.0.4</version>
        </dependency>
        <!--mybatis依赖-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.4</version>
        </dependency>
        <!--log4j依赖,打印mybatis日志-->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
          <!--日志-->
	    <dependency>
	      <groupId>ch.qos.logback</groupId>
	      <artifactId>logback-classic</artifactId>
	      <version>1.2.3</version>
	    </dependency>
        <!--分页查询,pagehelper-->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper</artifactId>
            <version>4.0.0</version>
        </dependency>

        <!--mysql驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
        <!-- druid数据源 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.16</version>
        </dependency>
        <!-- junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <!-- spring整合junit的依赖 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.1.9.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.12</version>
            <scope>provided</scope>
        </dependency>


        <!-- servlet依赖 -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>
        <!--springmvc的依赖-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.1.9.RELEASE</version>
        </dependency>
        <!-- jackson,帮助进行json转换-->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.9.0</version>
        </dependency>

        <!--commons文件上传,如果需要文件上传功能,需要添加本依赖-->
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.4</version>
        </dependency>
        <!-- Spring5和Thymeleaf整合包-->
	    <dependency>
	      <groupId>org.thymeleaf</groupId>
	      <artifactId>thymeleaf-spring5</artifactId>
	      <version>3.0.12.RELEASE</version>
	    </dependency>

1.4 Related configuration

① Integrate Spring and Mybatis
to create a Spring core configuration file in the resources directory: applicationContext.xml content is as follows

<?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:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://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/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
    <!--扫描组件(除控制层)-->
    <context:component-scan base-package="com.lx">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>
    <!--引入jdbc.properties配置文件-->
    <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
    <!--配置数据源-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <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>
    <!--配置事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!--
        开启事务的注解驱动
        将使用注解@Transactional标识的方法或类中所有的方法进行事务管理
    -->
    <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
    <!--配置SqlSessionFactoryBean,可以直接在Spring的IOC中获取SqlSessionFactory-->
    <bean class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--设置MyBatis的核心配置文件的路径-->
        <property name="configLocation" value="classpath:mybatis-config.xml"></property>
        <!--设置数据源-->
        <property name="dataSource" ref="dataSource"></property>
        <!--设置类型别名所对应的包-->
        <property name="typeAliasesPackage" value="com.lx.pojo"></property>
        <!--设置映射文件的路径,只有映射文件的包和mapper接口的包不-致时需要设置-->
        <!-- <property name="mapperlocations" value="classpath:mappers/*.xml"></property>-->
    </bean>
      <!--开启aop注解支持-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
    <!--配置mapper接口的扫描,可以将指定包下所有的mapper接口,通过sqlSession创建代理实现类对象,并将这些对象交给IOC容器管理-->
        <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
            <property name="basePackage" value="com.lx.mapper"></property>
        </bean>
</beans>

Create a jdbc.properties file in the resources directory with the following content:

jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/ssm_db?serverTimezone=UTC
jdbc.username=root
jdbc.password=root

Create mybatis-config.xml in the resources directory, the content is as follows:

<?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>
    <settings>
        <!--将下划线映射为驼峰-->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>
    <!--配置分页插件-->
    <plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
    </plugins>
</configuration>

Create log4j.xml in the resources directory with the following content:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
    <appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
        <param name="Encoding" value="UTF-8" />
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%-5p %d{MM-dd HH:mm:ss,SSS} %m (%F:%L) \n" />
        </layout>
    </appender>
    <logger name="java.sql">
        <level value="debug" />
    </logger>
    <logger name="org.apache.ibatis">
        <level value="info" />
    </logger>
    <root>
        <level value="debug" />
        <appender-ref ref="STDOUT" />
    </root>
</log4j:configuration>

②SpringMVC configuration file
Create springmvc.xml in the resources directory, the content is as follows:

<?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 https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
    <!--扫描控制层组件-->
    <context:component-scan base-package="com.lx.controller"></context:component-scan>
    <!--配置Thymeleaf视图解析器,前后端不分离项目使用-->
    <bean id="viewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
        <property name="order" value="1"/>
        <property name="characterEncoding" value="UTF-8"/>
        <property name="templateEngine">
            <bean class="org.thymeleaf.spring5.SpringTemplateEngine">
                <property name="templateResolver">
                    <bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
                        <!-- 视图前缀-->
                        <property name="prefix" value="/WEB-INF/templates/"/>
                        <!--视图后缀-->
                        <property name="suffix" value=".html"/>
                        <property name="templateMode" value="HTML5"/>
                        <property name="characterEncoding" value="UTF-8" />
                    </bean>
                </property>
            </bean>
        </property>
    </bean>
    <!--配置默认的servlet处理静态资源-->
    <mvc:default-servlet-handler />
    <!--开启mvc注解驱动,解决响应乱码-->
    <mvc:annotation-driven>
        <mvc:message-converters>
            <bean class="org.springframework.http.converter.StringHttpMessageConverter">
                <constructor-arg value="utf-8"/>
            </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>
    <!--配置视图控制器 前后端不分离项目使用-->
    <mvc:view-controller path="/" view-name="index"></mvc:view-controller>
    <!--配置文件上传解析器 前后端不分离项目使用-->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean>
</beans>

③Integrate Spring into the web project, configure web, xml
       ~~~~~~      Let the Spring container be created when the web project starts. You can use the listener ContextLoaderListener provided by Spring, so we need to configure this listener in web.xml and configure the path of the Spring configuration file.


web.xml

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>
  <!--配置spring的编码过滤器-->
  <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>
    <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>
  <!--配置处理请求方式的过滤器,前后端不分离使用-->
  <filter>
    <filter-name>HiddenHttpMethodFilter</filter-name>
    <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>HiddenHttpMethodFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
  <!--配置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:springmvc.xml</param-value>
    </init-param>
    <!--将DispatcherServlet的初始化时间提前到服务器启动时-->
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>DispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
  <!--配置Spring的监听器,在服务器启动时加载Spring的配置文件-->
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  <!--设置Spring配置文件自定义的位置和名称-->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml</param-value>
  </context-param>
</web-app>

1.5 Write Controller, Service, Dao

Let's write an interface for querying users based on id to test
the Controller layer

@RestController
public class UserController {
    
    

    @Autowired
    private UserService userService;

    @GetMapping("/user/{id}")
    public User findById(@PathVariable("id") Integer id){
    
    
        User user = userService.findById(id);
        return user;
    }
}

Service layer

public interface UserService {
    
    
    User findById(Integer id);
}
@Service
public class UserServiceImpl implements UserService {
    
    
    @Autowired
    private UserDao userDao;

    public User findById(Integer id) {
    
    
        return userDao.findById(id);
    }
}

Dao layer

public interface UserDao {
    
    
    /**
     * 根据id查询用户
     * @param id
     * @return
     */
    User findById(Integer id);
}

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="com.lx.dao.UserDao">
    <select id="findById" resultType="com.lx.domain.User">
        select * from user where id = #{id}
    </select>
</mapper>

Second, the case

2.1 Unified response format

       ~~~~~~       We need to ensure the uniformity of the data format returned by all interfaces in a project. In this way, whether it is front-end or mobile development, after obtaining our data, it can be more convenient for unified processing.

       ~~~~~~      So we define the following result wrapper class

@JsonInclude(JsonInclude.Include.NON_NULL)
public class ResponseResult<T> {
    
    
    /**
     * 状态码
     */
    private Integer code;
    /**
     * 提示信息,如果有错误时,前端可以获取该字段进行提示
     */
    private String msg;
    /**
     * 查询到的结果数据,
     */
    private T data;

    public ResponseResult(Integer code, String msg) {
    
    
        this.code = code;
        this.msg = msg;
    }

    public ResponseResult(Integer code, T data) {
    
    
        this.code = code;
        this.data = data;
    }

    public Integer getCode() {
    
    
        return code;
    }

    public void setCode(Integer code) {
    
    
        this.code = code;
    }

    public String getMsg() {
    
    
        return msg;
    }

    public void setMsg(String msg) {
    
    
        this.msg = msg;
    }

    public T getData() {
    
    
        return data;
    }

    public void setData(T data) {
    
    
        this.data = data;
    }

    public ResponseResult(Integer code, String msg, T data) {
    
    
        this.code = code;
        this.msg = msg;
        this.data = data;
    }
}

2.2 Query all users

@RestController
public class UserController {
    
    

    @Autowired
    private UserService userService;

	//省略其他无关代码
    @GetMapping("/user")
    public ResponseResult findAll(){
    
    
        List<User> list = userService.findAll();
        return new ResponseResult(200,"操作成功",list);
    }
}
public interface UserService {
    
    
    User findById(Integer id);

    List<User> findAll();
}
@Service
public class UserServiceImpl implements UserService {
    
    
    @Autowired
    private UserDao userDao;
	//省略其他无关代码

    public List<User> findAll() {
    
    
        return userDao.findAll();
    }
}
public interface UserDao {
    
    
	//省略其他无关代码
    List<User> findAll();
}
<?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.lx.dao.UserDao">
    <select id="findAll" resultType="com.lx.domain.User">
        select * from user
    </select>
</mapper>

2.3 Query users in pages

       ~~~~~~      In addition to the found user data, the results of the pagination query also include the current page number, the number of entries per page, and the total number of records.

Paging data encapsulation class

public class PageResult<T> {
    
    

    private Integer currentPage;

    private Integer pageSize;

    private Integer total;
    
    private List<T> data;

    public PageResult(Integer currentPage, Integer pageSize, Integer total, List<T> data) {
    
    
        this.currentPage = currentPage;
        this.pageSize = pageSize;
        this.total = total;
        this.data = data;
    }

    public Integer getCurrentPage() {
    
    
        return currentPage;
    }

    public void setCurrentPage(Integer currentPage) {
    
    
        this.currentPage = currentPage;
    }

    public Integer getPageSize() {
    
    
        return pageSize;
    }

    public void setPageSize(Integer pageSize) {
    
    
        this.pageSize = pageSize;
    }

    public Integer getTotal() {
    
    
        return total;
    }

    public void setTotal(Integer total) {
    
    
        this.total = total;
    }

    public List<T> getData() {
    
    
        return data;
    }

    public void setData(List<T> data) {
    
    
        this.data = data;
    }
}
@RestController
public class UserController {
    
    

    @Autowired
    private UserService userService;

    @GetMapping("/user/{pageSize}/{pageNum}")
    public ResponseResult findByPage(@PathVariable("pageSize") Integer pageSize,@PathVariable("pageNum") Integer pageNum){
    
    
        PageResult pageResult =  userService.findByPage(pageSize,pageNum);
        return new ResponseResult(200,"操作成功",pageResult);
    }

}
@Service
public class UserServiceImpl implements UserService {
    
    
    @Autowired
    private UserDao userDao;


    public PageResult findByPage(Integer pageSize, Integer pageNum) {
    
    
        PageHelper.startPage(pageNum,pageSize);
        List<User> list = userDao.findAll();
        PageInfo pageInfo = new PageInfo(list);
        PageResult pageResult = new PageResult(pageInfo.getPageNum(),pageInfo.getPageSize(), (int) pageInfo.getTotal(),list);
        return pageResult;
    }
}

2.4 Insert user

	@PostMapping("/user")
    public ResponseResult insertUser(@RequestBody User user){
    
    
        userService.insertUser(user);
        return new ResponseResult(200,"操作成功");
    }

service layer

    void insertUser(User user);
  public void insertUser(User user) {
    
    
        userDao.insertUser(user);
    }

Dao layer

void insertUser(User user);

In the mapper mapping file

    <insert id="insertUser">
        insert into user values(null,#{username},#{age},#{address})
    </insert>

2.5 Delete user

Controller layer

    @DeleteMapping("/user/{id}")
    public ResponseResult deleteUser(@PathVariable("id") Integer id){
        userService.deleteUser(id);
        return new ResponseResult(200,"操作成功");
    }

Service layer

Add method definition to Service interface

    void deleteUser(Integer id);

Implement this method in the implementation class:

    public void deleteUser(Integer id) {
        userDao.deleteUser(id);
    }

Dao layer

Define the method in the interface

    void deleteUser(Integer id);

In the mapper mapping file

    <delete id="deleteUser">
        delete from user where id = #{id}
    </delete>

2.6 Update user

Controller layer

    @PutMapping("/user")
    public ResponseResult updateUser(@RequestBody User user){
        userService.updateUser(user);
        return new ResponseResult(200,"操作成功");
    }

Service layer

Add method definition to Service interface

    void updateUser(User user);

Implement this method in the implementation class:

    public void updateUser(User user) {
        userDao.updateUser(user);
    }

Dao layer

Define the method in the interface

    void updateUser(User user);

In the mapper mapping file

    <update id="updateUser">
        update user set username = #{username},age = #{age},address = #{address} where id = #{id}
    </update>

3. Unified handling of exceptions

We can use @ControllerAdvice to achieve unified handling of exceptions. When an exception occurs, a JSON response can also be returned.

code show as below:

@ControllerAdvice
public class SGControllerAdvice {
    
    

    @ExceptionHandler(Exception.class)
    @ResponseBody
    public ResponseResult handleException(Exception e){
    
    
        return new ResponseResult(500,e.getMessage());
    }
}

4. Interceptor

public class MyHandlerInterceptor implements HandlerInterceptor {
    
    

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    
    
        System.out.println("preHandle");
        return true;
    }

    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    
    
        System.out.println("postHandle");
    }

    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    
    
        System.out.println("afterCompletion");
    }
}

springmvc.xml

<!--配置拦截器-->
        <mvc:interceptors>
            <mvc:interceptor>
                <!--
                -->
                <mvc:mapping path="/**"/>
                <!--配置排除拦截的路径-->
                <!--<mvc:exclude-mapping path="/"/>-->
                <!--配置拦截器对象注入容器-->
                <bean class="com.lx.interceptor.MyHandlerInterceptor"></bean>
            </mvc:interceptor>
        </mvc:interceptors>

5. Declarative affairs

已经做好了相应的配置,只要在service方法上加上注解即可
    @Transactional
    public void test() {
    
    
        userDao.insertUser(new User(null,"test1",11,"cc"));
//        System.out.println(1/0);
        userDao.insertUser(new User(null,"test2",12,"cc2"));
    }

6. AOP

       ~~~~~~       Note that when you use AOP to enhance yourself, you should enhance the Service. The Controller cannot be enhanced, because the aspect class will be placed in the parent container, and our Controller is in the child container. Parent containers cannot access child containers.

       ~~~~~~      And if we need to enhance the Controller, it will be more useful to use interceptors.

@Aspect
@Component
public class MyAspect {
    
    

    //定义切点
    @Pointcut("execution(* com.sangeng.service..*.*(..))")
    public void pt(){
    
    

    }

    //进行增强
    @Before("pt()")
    public void before(){
    
    
        System.out.println("before");
    }
}

Guess you like

Origin blog.csdn.net/lx00000025/article/details/132170239