前面博文我们创建了springboot工程,处理了http请求,处理了属性的依赖注入和http请求的参数解析,那么一个基本的springboot工程已经搭建好了。现在来尝试springboot与持久层的集成,使用mybatis框架。
提前安装好mysql以备调试,参考教程:https://blog.youkuaiyun.com/qq_15903671/article/details/81977047
提前下载好mybatis自动生成工具,参考教程:https://blog.youkuaiyun.com/qq_15903671/article/details/82024680
提前创建用户、数据库、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版本的化,请参考这个博文https://blog.youkuaiyun.com/winter_chen001/article/details/77249029 写的很详细。
二、修改配置文件:
添加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代码
具体参考我的教程https://blog.youkuaiyun.com/qq_15903671/article/details/82024680
教程里的示例table就是现在要用的,创建好的src目录下的代码也可以拷贝过来。注意为教程中的文件结构配置是图简便设置的,粘贴的时候要仔细检查下,个人建议还是按照你工程中的实际文件结构配置mybatis代码生成工具的xml配置文件,不然生成的代码里,要改好多东西,昨晚的痛苦经历不忍回忆。。。
粘好的程序结构如下图所示
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(); } }
创建好的程序结构如下图所示
其中UserServiceImpl.java类中,private UserMapper userMapper会报错,如果实在强迫症受不了的化参考下图处理。
至此,springboot集成mybatis配置完成。编译运行后可使用postman工具进行测试
当然了,编译运行的过程中会遇到很多异常,踩很多坑, 只能根据情况一点一点排查了。