Detailed integration of Spring+SpringMVC+MyBatis+logback (SSM) project

Overall directory structure

Insert image description here

Table Structure

Insert image description here

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>demo-maven</artifactId>
        <groupId>com.fu</groupId>
        <version>1</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <packaging>war</packaging>

    <artifactId>spring-springmvc-mybatis-demo</artifactId>

    <dependencies>
        <!-- lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <!-- webmvc -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
        </dependency>
        <!-- 主要是jdbc包含事务 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
        </dependency>
        <!-- 日志logback底层已经附带了slf4j,因此不需要引入slf4j依赖 -->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
        </dependency>
        <!-- spring-webmvc继承servlet-api HttpServletRequest/Response -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <scope>provided</scope>
        </dependency>
        <!-- 序列化和反序列化 -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
        </dependency>
        <!-- 文件上传 -->
        <!--<dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.5</version>
        </dependency>-->
        <!-- 测试 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- mysql驱动 -->
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <version>8.0.33</version>
            <scope>runtime</scope>
        </dependency>
        <!-- 数据库连接池 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.16</version>
        </dependency>
        <!-- mybatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.13</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.1.1</version>
        </dependency>
        <!-- 分页插件 -->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper</artifactId>
            <version>5.3.2</version>
        </dependency>
    </dependencies>

    <build>
        <finalName>ssm</finalName>
    </build>

    <!-- 多环境配置 -->
    <profiles>
        <profile>
            <id>dev</id>
            <build>
                <filters>
                    <filter>src/main/resources/environment/dev.properties</filter>
                </filters>
            </build>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
        </profile>
        <profile>
            <id>test</id>
            <build>
                <filters>
                    <filter>src/main/resources/environment/test.properties</filter>
                </filters>
            </build>
        </profile>
        <profile>
            <id>prod</id>
            <build>
                <filters>
                    <filter>src/main/resources/environment/prod.properties</filter>
                </filters>
            </build>
        </profile>
    </profiles>

</project>

Create new src/main/webapp/WEB-INF/web.xml

<?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">
    <!-- 配置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>springMVC</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!-- 设置SpringMVC配置文件自定义的位置和名称 -->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring-mvc.xml</param-value>
        </init-param>
        <!-- 将DispatcherServlet初始化的时间提前到服务器启动时 -->
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>springMVC</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:spring.xml</param-value>
    </context-param>

</web-app>

Create new /src/main/resources/spring.xml

<?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">

    <!-- 配置数据源 -->
    <bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init">
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

    <!-- 配置事务管理器(这个包在org.springframework.jdbc下,因此要导入spring-jdbc依赖) -->
    <bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="druidDataSource"/>
    </bean>

    <!-- 开启事务的注解驱动,将使用注解@Transactional标识的方法或类中所有的方法进行事务管理 -->
    <tx:annotation-driven transaction-manager="dataSourceTransactionManager"/>

    <!-- 配置SqlSessionFactoryBean(不需要配置id),可以直接在Spring的IOC容器中获取SqlSessionFactory -->
    <bean class="org.mybatis.spring.SqlSessionFactoryBean">
        <!-- 设置数据源 -->
        <property name="dataSource" ref="druidDataSource"/>
        <!-- 设置类型别名路径 -->
        <property name="typeAliasesPackage" value="com.fu.ssm.entity"/>
        <!-- 设置映射文件路径(如果映射文件和Mapper接口文件路径一致,则可以不配置) -->
        <property name="mapperLocations" value="classpath:mapper/*.xml"/>
        <!-- 全局变量 -->
        <property name="configurationProperties">
            <props>
                <!-- 驼峰式命名 -->
                <prop key="mapUnderscoreToCamelCase">true</prop>
                <prop key="jdbcTypeForNull">NULL</prop>
                <prop key="logImpl">SFL4J</prop>
                <prop key="loggingLevel">INFO</prop>
            </props>
        </property>
        <!-- 插件 -->
        <property name="plugins">
            <array>
                <!-- 分页插件 -->
                <bean class="com.github.pagehelper.PageInterceptor"/>
                <!-- 输出SQL到控制台 -->
                <bean class="com.fu.ssm.base.MyBatisSQLInterceptor"/>
            </array>
        </property>
    </bean>

    <!-- 配置Mapper接口的扫描,可以将指定包下所以的Mapper接口,通过SqlSession创建代理实现类对象,并将这些对象交给IOC容器管理 -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.fu.ssm.mapper"/>
    </bean>

</beans>

Create new /src/main/resources/spring-mvc.xml

<?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.fu.ssm"/>

    <!-- 配置默认的servlet处理静态资源 -->
    <mvc:default-servlet-handler/>

    <!-- 开启mvc注解驱动 -->
    <mvc:annotation-driven/>

    <!-- 配置文件上传解析器 -->
    <!--    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"/>-->

    <!-- 异常解析器 -->
    <!--    <bean id="simpleMappingExceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"/>-->
</beans>

Create new /src/main/resources/logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">    <!-- 控制台彩色日志格式,注意:%L打印行号对性能有影响,因此不建议在生产环境使用。 -->
    <property name="CONSOLE_LOG_PATTERN" value="[%d{HH:mm:ss} %p %.10t] %C{39}\.%M\\(\\): %m%n"/>

    <!--输出到控制台-->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder" charset="UTF-8">
            <!-- 输出到控制台的日志格式 -->
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
        </encoder>
    </appender>
    <!-- 配置了MyBatisSQLInterceptor,则这里不需要配置。 -->
    <logger name="com.fu.ssm.mapper" level="DEBUG" />

    <root level="INFO">
        <appender-ref ref="CONSOLE" />
    </root>

</configuration>

Create new /src/main/resources/environment/dev.properties, test.properties, prod.properties

Currently, the contents of the three files dev.properties, test.properties, and prod.properties are the same and can be configured as needed.

jdbc.driver=com.mysql.cj.jdbc.Driver
# 把&替换成&amp;(注意分号也是其中的一部分)
jdbc.url=jdbc:mysql://localhost:3306/ssm?useUnicode=true&amp;characterEncoding=UTF-8&amp;autoReconnect=true&amp;useSSL=false&amp;serverTimezone=Asia/Shanghai
jdbc.username=root
jdbc.password=123456

Create new /src/main/java/com/fu/ssm/base/MyBatisSQLInterceptor.java

Printing SQL interceptor is not recommended. It is recommended to use logback logger with properties to differentiate between environments.

package com.fu.ssm.base;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

/**
 * MyBatis输出日志
 */
@Slf4j
@Intercepts({
    
    @Signature(type = Executor.class, method = "query", args = {
    
    MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})})
public class MyBatisSQLInterceptor implements Interceptor {
    
    
    private static final ObjectMapper om = new ObjectMapper();

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
    
    
        //如果输出中文乱码,则需要添加Tomcat JVM参数-Dfile.encoding=UTF-8
        Object[] args = invocation.getArgs();
        if (args != null && args.length > 1) {
    
    
            MappedStatement mappedStatement = (MappedStatement) args[0];
            Object parameter = args[1];
            BoundSql boundSql = mappedStatement.getBoundSql(parameter);
            String sql = boundSql.getSql();
            log.info("params:{}\nsql:{}", om.writeValueAsString(parameter), sql);
        }
        return invocation.proceed();
    }
}

Create a new /src/main/java/com/fu/ssm/base/PageDTO.java paging base class

Used for DTO to inherit PageDTO to implement paging

import com.github.pagehelper.IPage;
import lombok.Data;

@Data
public class PageDTO implements IPage {
    
    
    private Integer page;//起始页
    private Integer size;//每页数量
    private String orderBy;//排序

    /**
     * 初始化的时候就设置默认参数,如果不传则默认起始页为1,条数为10。
     */
    public PageDTO(){
    
    
        this.page=1;
        this.size=10;
    }

    @Override
    public Integer getPageNum() {
    
    
        return page;
    }

    @Override
    public Integer getPageSize() {
    
    
        return size;
    }

    @Override
    public String getOrderBy() {
    
    
        return orderBy;
    }

}

Create new /src/main/java/com/fu/ssm/controller/TestController.java

The standard controller omits the new/modify/delete interface.

import com.fu.ssm.dto.TestDTO;
import com.fu.ssm.entity.Test;
import com.fu.ssm.service.TestService;
import com.github.pagehelper.PageSerializable;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("test")
@RequiredArgsConstructor
public class TestController {
    
    
    private final TestService testService;

    /**
     * 通过test表的id获取test信息
     * @param id 主键
     */
    @RequestMapping(value = "selectTestById", method = RequestMethod.POST)
    @ResponseBody
    public Test selectByTestId(@RequestBody Integer id) {
    
    
        return testService.selectByTestId(id);
    }

    /**
     * 分页查询test表记录
     * @param testDTO test数据传输对象
     */
    @RequestMapping(value = "selectTestPage", method = RequestMethod.POST)
    @ResponseBody
    public PageSerializable<Test> selectTestPage(@RequestBody TestDTO testDTO) {
    
    
        return testService.selectTestPage(testDTO);
    }

}

Create new /src/main/java/com/fu/ssm/service/TestService.java

Standard service interface

import com.github.pagehelper.PageSerializable;

public interface TestService {
    
    

    Test selectByTestId(Integer id);

    PageSerializable<Test> selectTestPage(TestDTO testDTO);
}

Create new /src/main/java/com/fu/ssm/service/impl/TestServiceImpl.java

Standard service interface implementation class

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.github.pagehelper.PageSerializable;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

@Slf4j
@Service
@RequiredArgsConstructor
public class TestServiceImpl implements TestService {
    
    
    private final TestMapper testMapper;

    @Override
    public Test selectByTestId(Integer id) {
    
    
        log.debug("debug");
        log.info("info");
        log.warn("warn");
        log.error("warn");
        return testMapper.selectByTestId(id);
    }

    @Override
    public PageSerializable<Test> selectTestPage(TestDTO testDTO) {
    
    
        //PageHelper底层使用ThreadLocal防止并发造成数据问题,因此用完要关闭ThreadLocal。
        PageHelper.startPage(testDTO).close();
        //PageInfo会返回更为详细的内容,PageSerializable只返回list和total。
//        log.info("{}", PageInfo.of(testMapper.selectTestPage(testDTO)));
        return PageSerializable.of(testMapper.selectTestPage(testDTO));
    }

}

Create new /src/main/java/com/fu/ssm/mapper/TestMapper.java

Standard Object Relational Mapping

import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public interface TestMapper {
    
    
    Test selectByTestId(Integer id);

    List<Test> selectTestPage(TestDTO testDTO);
}

Create new /src/main/resources/mapper/TestMapper.xml

mybatis dynamic SQL

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.fu.ssm.mapper.TestMapper">

    <select id="selectByTestId" parameterType="java.lang.Integer" resultType="com.fu.ssm.entity.Test">
        select id,name,age from test where id = #{id}
    </select>

    <select id="selectTestPage" resultType="com.fu.ssm.entity.Test">
        select id,name,age from test
        <where>
            <if test="name != null and name != ''">
                <bind name="username" value="'%' + name + '%'"/>
                and name like #{username}
            </if>
        </where>
    </select>

</mapper>

Create new /src/main/java/com/fu/ssm/entity/Test.java

Entity class

import lombok.Data;

@Data
public class Test {
    
    
    private Integer id;
    private String name;
    private Integer age;
}

Create new /src/main/java/com/fu/ssm/dto/TestDTO.java

Entity class data transfer object

import lombok.Data;
import lombok.EqualsAndHashCode;

/**
 * test数据传输对象
 */
@Data
@EqualsAndHashCode(callSuper = false)
public class TestDTO extends PageDTO {
    
    
    private String name;//名称
}

Configure Tomcat

Insert image description here

Virtual machine options

-Xms256m
-Xmx512m
-XX:ReservedCodeCacheSize=256m
-Dfile.encoding=UTF-8

Insert image description here

deploy

Insert image description here
Insert image description here

start up

Insert image description here

Test interface and SQL output

Insert image description here

Insert image description here

Multiple environments

Insert image description here
You can choose either MyBatisSQLInterceptor or logback logger to configure SQL output. It is recommended to use logback logger.

Guess you like

Origin blog.csdn.net/weixin_43933728/article/details/132312269