前面博文我们创建了springboot工程,处理了http请求,处理了属性的依赖注入和http请求的参数解析,那么一个基本的springboot工程已经搭建好了。现在来尝试springboot与持久层的集成,使用mybatis框架。

提前安装好mysql以备调试,参考教程:

提前下载好mybatis自动生成工具,参考教程:

提前创建用户、数据库、table。然后开始集成mybatis。

一、修改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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.test2</groupId>
    <artifactId>qftest2</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>qftest2</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.4.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <!-- 想要配置log4j2,就要先去除logging包 -->
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- 添加log4j2依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-log4j2</artifactId>
        </dependency>

        <!-- json所有依赖jar包 -->
        <dependency>
            <groupId>net.sf.json-lib</groupId>
            <artifactId>json-lib</artifactId>
            <version>2.4</version>
            <classifier>jdk15</classifier>
        </dependency>
        <dependency>
            <groupId>commons-beanutils</groupId>
            <artifactId>commons-beanutils</artifactId>
            <version>1.7.0</version>
        </dependency>
        <dependency>
            <groupId>commons-collections</groupId>
            <artifactId>commons-collections</artifactId>
            <version>3.1</version>
        </dependency>
        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>2.5</version>
        </dependency>
        <dependency>
            <groupId>net.sf.ezmorph</groupId>
            <artifactId>ezmorph</artifactId>
            <version>1.0.3</version>
        </dependency>

        <!-- 热部署 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
            <scope>true</scope>
        </dependency>

        <!-- thymeleaf -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <!-- jdbc -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <!-- mysql -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <!--mybatis -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency>
        <!-- commons -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.4</version>
        </dependency>
        <!-- 分页插件 -->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.2.5</version>
        </dependency>
        <!-- alibaba的druid数据库连接池 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.9</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <!-- 没有该配置,devtools 不生效 -->
                    <fork>true</fork>
                </configuration>
            </plugin>

        </plugins>
    </build>


</project>


直接放出文件源码,我的每处修改都加了备注,供参考。自动下载依赖包需要时间,等吧。依赖的jar包版本要留意,错了真的可能报错,排查要好久。springboot是2.0版本一定要留意,如果一定要用springboot1.5版本的化,请参考这个博文 写的很详细。

二、修改配置文件:

添加mybatis需要的必要配置,由于配置较多,建议直接更换配置文件,删除原application.properties文件,新增application.yml配置文件。还是直接放出代码供参考吧,错一点就跑不起来。


server:
  port: 8081
  servlet:
    context-path: /qftest
  tomcat:
    uri-encoding: UTF-8

#logging:
  #config: src/main/resources/mapping/log4j2.xml

spring:
  profiles:
    active: dev
  http:
    encoding:
      charset: UTF-8
      enabled: true
      force: true
  messages:
    encoding: UTF-8
  datasource:
    name: test
    type: com.alibaba.druid.pool.DruidDataSource
    #druid相关配置
    druid:
      #监控统计拦截的filters
      filters: stat
      driver-class-name: com.mysql.jdbc.Driver
      #基本属性
      url: jdbc:mysql://127.0.0.1:3306/testdb1?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true
      username: qftest1
      password: Pass@word
      #配置初始化大小/最小/最大
      initial-size: 1
      min-idle: 1
      max-active: 20
      #获取连接等待超时时间
      max-wait: 60000
      #间隔多久进行一次检测,检测需要关闭的空闲连接
      time-between-eviction-runs-millis: 60000
      #一个连接在池中最小生存的时间
      min-evictable-idle-time-millis: 300000
      validation-query: SELECT 'x'
      test-while-idle: true
      test-on-borrow: false
      test-on-return: false
      #打开PSCache,并指定每个连接上PSCache的大小。oracle设为true,mysql设为false。分库分表较多推荐设置为false
      pool-prepared-statements: false
      max-pool-prepared-statement-per-connection-size: 20
##
mybatis:
  mapper-locations: classpath:mapping/*.xml  #注意:一定要对应mapper映射xml文件的所在路径
  type-aliases-package: com.test2.qftest2.model  # 注意:对应实体类的路径


其中,spring.profiles.active 属性依然是将生产环境和开发环境配置分离。仔细看我前面的博文应该会发现,我的log4j2配置文件中生产环境和测试环境输出地址是分开配置的,但是都写在了log4j2配置文件里,上线前打包工程的时候要留意修改,不然会报错。那么今天就注释掉application.yml中关于log4j2的配置,改为在application-dev和-prod中分开配置。同时log4j2配置文件也拆分成log4j2-dev和log4j2-prod两个不同的版本。

application-dev.properties内容
 
test.testinfo = 调用dev.properties信息成功
logging.config:  classpath:log4j2-dev.xml
 
application-prod.properties内容
 
test.testinfo = 调用prod.properties信息成功
logging.config:  classpath:log4j2-prod.xml


log4j2-dev.xml内容


<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <properties>
        <!-- 文件输出格式 -->
        <property name="PATTERN">%d{yyyy-MM-dd HH:mm:ss.SSS} |-%-5level [%thread] %c [%L] -| %msg%n</property>
        <!--设置日志在硬盘上输出的目录-->
        <!-- 相对路径配置,日志会存放在项目根目录下,依据相对路径创建文件夹 -->
        <property name="logPath">log</property><!-- 开发时强烈建议相对路径,好找。 绝对路径受操作系统限制,而且本地开发环境下真的分不清是哪个项目记的。。。-->
        <!-- 绝对路径配置,日志会存放指定的绝对路径下 -->
        <!--<property name="logPath">D:/log</property>--><!-- 生产环境发布时建议按项目要求设置绝对路径-->
    </properties>
    <appenders>
        <Console name="CONSOLE" target="system_out">
            <PatternLayout pattern="${PATTERN}" />
        </Console>

        <!--设置级别为INFO日志输出到info.log中-->
        <RollingFile name="INFO" filename="${logPath}/info.log"
                     filepattern="${logPath}/%d{YYYYMMdd}-%i-info.log.zip">
            <Filters>
                <!--设置只输出级别为INFO的日志-->
                <ThresholdFilter level="INFO"/>
                <ThresholdFilter level="WARN" onMatch="DENY" onMismatch="NEUTRAL"/>
            </Filters>
            <PatternLayout pattern="[ %-5p]:%d{YYYY-MM-dd HH:mm:ss} [%t] %c{1}:%L - %msg%n" />
            <Policies>
                <!--设置每天打包日志一次-->
                <TimeBasedTriggeringPolicy interval="1" modulate="true"/>
                <!--设置日志文件满1MB后打包-->
                <SizeBasedTriggeringPolicy size="1 MB" />
            </Policies>
            <DefaultRolloverStrategy max="20" />
        </RollingFile>

        <!--设置级别为WARN日志输出到warn.log中-->
        <RollingFile name="WARN" filename="${logPath}/warn.log"
                     filepattern="${logPath}/%d{YYYYMMdd}-%i-warn.log.zip">
            <Filters>
                <!--设置只输出级别为WARN的日志-->
                <ThresholdFilter level="WARN"/>
                <ThresholdFilter level="ERROR" onMatch="DENY" onMismatch="NEUTRAL"/>
            </Filters>
            <PatternLayout pattern="[ %-5p]:%d{YYYY-MM-dd HH:mm:ss} [%t] %c{1}:%L - %msg%n" />
            <Policies>
                <!--设置每天打包日志一次-->
                <TimeBasedTriggeringPolicy interval="1" modulate="true"/>
                <!--设置日志文件满1MB后打包-->
                <SizeBasedTriggeringPolicy size="1 MB" />
            </Policies>
            <DefaultRolloverStrategy max="20" />
        </RollingFile>

        <!--设置级别为ERROR日志输出到error.log中-->
        <RollingFile name="ERROR" filename="${logPath}/error.log"
                     filepattern="${logPath}/%d{YYYYMMdd}-%i-error.log.zip">
            <!--设置只输出级别为ERROR的日志-->
            <ThresholdFilter level="ERROR"/>
            <PatternLayout pattern="[ %-5p]:%d{YYYY-MM-dd HH:mm:ss} [%t] %c{1}:%L - %msg%n" />
            <Policies>
                <!--设置每天打包日志一次-->
                <TimeBasedTriggeringPolicy interval="1" modulate="true"/>
                <!--设置日志文件满1MB后打包-->
                <SizeBasedTriggeringPolicy size="1 MB" />
            </Policies>
            <DefaultRolloverStrategy max="20" />
        </RollingFile>

        <!--设置级别为DEBUG日志输出到debug.log中-->
        <RollingFile name="DEBUG" filename="${logPath}/debug.log"
                     filepattern="${logPath}/%d{YYYYMMdd}-%i-debug.log.zip">
            <!--设置只输出级别为DEBUG的日志-->
            <Filters>
                <ThresholdFilter level="DEBUG"/>
                <ThresholdFilter level="INFO" onMatch="DENY" onMismatch="NEUTRAL"/>
            </Filters>
            <PatternLayout pattern="[ %-5p]:%d{YYYY-MM-dd HH:mm:ss} [%t] %c{1}:%L - %msg%n" />
            <Policies>
                <!--设置每天打包日志一次-->
                <TimeBasedTriggeringPolicy interval="1" modulate="true"/>
                <!--设置日志文件满1MB后打包-->
                <SizeBasedTriggeringPolicy size="1 MB" />
            </Policies>
            <DefaultRolloverStrategy max="20" />
        </RollingFile>

        <!--设置通过邮件发送日志信息-->
        <!--
        <SMTP name="Mail" subject="XXXXSaaS系统正式版异常信息" to="yong.shi@lengjing.info" from="message@lengjing.info"
              smtpUsername="message@lengjing.info" smtpPassword="LENG****1234" smtpHost="mail.lengjing.info" smtpDebug="false"
              smtpPort="25" bufferSize="10">
            <PatternLayout pattern="[%-5p]:%d{YYYY-MM-dd HH:mm:ss} [%t] %c{1}:%L - %msg%n" />
        </SMTP>
        -->

    </appenders>
    <Loggers>
        <logger name="com.test2.qftest2" level="INFO" additivity="true">
            <appender-ref ref="INFO" />
            <appender-ref ref="WARN" />
            <appender-ref ref="ERROR" />
            <appender-ref ref="DEBUG" />
            <!--<appender-ref ref="Mail" />-->
        </logger>
        <!--<root level="DEBUG">--><!-- debug信息实在是太多了,不想看 -->
        <root level="INFO">
            <appender-ref ref="CONSOLE"/>
        </root>
    </Loggers>
</configuration>


log4j2-prod.xml只是把<property name="logPath">标签内容修改一下,就不粘源码了。

 

三、使用mybatis工具生成model、mapper、mapping代码

具体参考我的教程

教程里的示例table就是现在要用的,创建好的src目录下的代码也可以拷贝过来。注意为教程中的文件结构配置是图简便设置的,粘贴的时候要仔细检查下,个人建议还是按照你工程中的实际文件结构配置mybatis代码生成工具的xml配置文件,不然生成的代码里,要改好多东西,昨晚的痛苦经历不忍回忆。。。

粘好的程序结构如下图所示

SPRINGBOOT申明持久化队列 springboot持久层框架_mysql

mapping文件夹请留意,里面放的是dao层的sql代码,都是xml文件,我整体放在resources下了。application.yml中mybatis的配置指定mapper-locations时一定要指向这个mapping包,而且这个mapping包里千万不要放别的配置文件,比如log4j2.xml。。。

为了方便测试,对生成的代码添加点功能,主要是为了试试分页查询。

UserMapper.java中添加函数
List<User> selectAllUser();
UserMapper.xml中添加配置

<select id="selectAllUser" resultMap="BaseResultMap">
  select
  <include refid="Base_Column_List" />
    from t_user
</select>


 

四、创建controller和service

创建controller、service、service.impl文件夹、创建UserController类、UserService、UserServiceImpl类。

UserController类源码


package com.test2.qftest2.controller;

import com.test2.qftest2.model.User;
import com.test2.qftest2.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping(value = "/user")
public class UserController {

    @Autowired
    private UserService userService;

    @ResponseBody
    @RequestMapping(value = "/add", produces = {"application/json;charset=UTF-8"})
    public int addUser(User user){
        return userService.addUser(user);
    }

    @ResponseBody
    @RequestMapping(value = "/all/{pageNum}/{pageSize}", produces = {"application/json;charset=UTF-8"})
    public Object findAllUser(@PathVariable("pageNum") int pageNum, @PathVariable("pageSize") int pageSize){
        return userService.findAllUser(pageNum,pageSize);
    }
}


UserService类源码


package com.test2.qftest2.service;

import com.test2.qftest2.model.User;
import java.util.List;
 
public interface UserService {

    int addUser(User user);

    List<User> findAllUser(int pageNum, int pageSize);
}


UserServiceImpl类源码


package com.test2.qftest2.service.impl;

import com.github.pagehelper.PageHelper;
import com.test2.qftest2.mapper.UserMapper;
import com.test2.qftest2.model.User;
import com.test2.qftest2.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
 
@Service(value = "userService")
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;//这里会报错,但是并不会影响

    @Override
    public int addUser(User user) {
        return userMapper.insertSelective(user);

    }

    /*
     * 这个方法中用到了我们开头配置依赖的分页插件pagehelper
     * 很简单,只需要在service层传入参数,然后将参数传递给一个插件的一个静态方法即可;
     * pageNum 开始页数
     * pageSize 每页显示的数据条数
     * */

    @Override
    public List<User> findAllUser(int pageNum, int pageSize) {
        //将参数传给这个方法就可以实现物理分页了,非常简单。
        PageHelper.startPage(pageNum, pageSize);
        return userMapper.selectAllUser();
    }
}


创建好的程序结构如下图所示

SPRINGBOOT申明持久化队列 springboot持久层框架_spring_02

其中UserServiceImpl.java类中,private UserMapper userMapper会报错,如果实在强迫症受不了的化参考下图处理。

SPRINGBOOT申明持久化队列 springboot持久层框架_spring_03

至此,springboot集成mybatis配置完成。编译运行后可使用postman工具进行测试

SPRINGBOOT申明持久化队列 springboot持久层框架_mysql_04

当然了,编译运行的过程中会遇到很多异常,踩很多坑, 只能根据情况一点一点排查了。