Spring Boot系列六 Spring boot集成mybatis、分页插件pagehelper
1. 概述
本文的内容包括如下内容:
- Spring Boot集成mybatis
- Spring Boot集成pagehelper分页插件,定义分页的相关类
- 实现工具类:model转dto,实现数据层和传输层的解耦
- 完整展示了从浏览器输入URL,并从数据库操作数据的完整流程
2. Spring Boot集成Mybatis
2.1. pom.xml
mybatis和数据库的相关的jar
<!-- druid -->
<dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.0.31</version>
</dependency>
<!-- Spring Boot集成mybatis -->
<dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>1.3.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>6.0.6</version>
</dependency>
2.2. Mapper java类和xml及Model
测试表sql如下
CREATE TABLE `test`.`test` (`id` INT NOT NULL,`age` INT NULL,`name` VARCHAR(45) NULL,PRIMARY KEY (`id`),UNIQUE INDEX `id_UNIQUE` (`id` ASC));
表对应Model类: com.hry.spring.mybatis.model.TestModel
public class TestModel {private Integer id;private Integer age;private String name;// set/get略
}
配置Mapper类: com.hry.spring.mybatis.mapper.TestMapper
public interface TestMapper {int deleteByPrimaryKey(Integer id);int insert(TestModel record);int insertSelective(TestModel record);TestModel selectByPrimaryKey(Integer id);List<TestModel> selectAll();int updateByPrimaryKeySelective(TestModel record);int updateByPrimaryKey(TestModel record);
}
配置Mapper xml: TestMapper.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.hry.spring.mybatis.mapper.TestMapper"><resultMap id="BaseResultMap" type="com.hry.spring.mybatis.model.TestModel"><id column="id" jdbcType="INTEGER" property="id" /><result column="age" jdbcType="INTEGER" property="age" /><result column="name" jdbcType="VARCHAR" property="name" /></resultMap><sql id="Base_Column_List">id, age, name</sql><select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">select <include refid="Base_Column_List" />from testwhere id = #{id,jdbcType=INTEGER}</select><select id="selectAll" resultMap="BaseResultMap">select<include refid="Base_Column_List" />from testorder by id desc</select><delete id="deleteByPrimaryKey" parameterType="java.lang.Integer">delete from testwhere id = #{id,jdbcType=INTEGER}</delete><insert id="insert" parameterType="com.hry.spring.mybatis.model.TestModel">insert into test (id, age, name, )values (#{id,jdbcType=INTEGER}, #{age,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR})</insert><insert id="insertSelective" parameterType="com.hry.spring.mybatis.model.TestModel">insert into test<trim prefix="(" suffix=")" suffixOverrides=","><if test="id != null">id,</if><if test="age != null">age,</if><if test="name != null">name,</if></trim><trim prefix="values (" suffix=")" suffixOverrides=","><if test="id != null">#{id,jdbcType=INTEGER},</if><if test="age != null">#{age,jdbcType=INTEGER},</if><if test="name != null">#{name,jdbcType=VARCHAR},</if></trim></insert><update id="updateByPrimaryKeySelective" parameterType="com.hry.spring.mybatis.model.TestModel">update test<set><if test="age != null">age = #{age,jdbcType=INTEGER},</if><if test="name != null">name = #{name,jdbcType=VARCHAR},</if></set>where id = #{id,jdbcType=INTEGER}</update><update id="updateByPrimaryKey" parameterType="com.hry.spring.mybatis.model.TestModel">update testset age = #{age,jdbcType=INTEGER},name = #{name,jdbcType=VARCHAR}where id = #{id,jdbcType=INTEGER}</update>
</mapper>
2.3. mybatis配置
spring_mybatis.xml
spring.datasource.url的值配置在application.yml
<!-- ### 配置数据源 begin ###-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> <!-- 基本属性 url、user、password --><property name="url" value="${spring.datasource.url}" /><property name="username" value="${spring.datasource.username}" /><property name="password" value="${spring.datasource.password}" /><property name="driverClassName" value="${spring.datasource.driverClassName}" /><!-- 配置初始化大小、最小、最大 --><property name="initialSize" value="${spring.datasource.initialSize:5}" /><property name="minIdle" value="${spring.datasource.minIdle:5}" /> <property name="maxActive" value="${spring.datasource.maxActive:20}" /><!-- 配置获取连接等待超时的时间 --><property name="maxWait" value="${spring.datasource.maxWait:30000}" /><!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 --><property name="timeBetweenEvictionRunsMillis" value="${spring.datasource.timeBetweenEvictionRunsMillis}" /><!-- 配置一个连接在池中最小生存的时间,单位是毫秒 --><property name="minEvictableIdleTimeMillis" value="${spring.datasource.minEvictableIdleTimeMillis}" /><property name="validationQuery" value="${spring.datasource.validationQuery}" /><property name="testWhileIdle" value="${spring.datasource.testWhileIdle}" /><property name="testOnBorrow" value="${spring.datasource.testOnBorrow}" /><property name="testOnReturn" value="${spring.datasource.testOnReturn}" /><!-- 打开PSCache,并且指定每个连接上PSCache的大小 --><property name="poolPreparedStatements" value="${spring.datasource.poolPreparedStatements}" /><property name="maxPoolPreparedStatementPerConnectionSize" value="${spring.datasource.maxPoolPreparedStatementPerConnectionSize}" /><!-- 配置监控统计拦截的filters --><property name="filters" value="${spring.datasource.filters}" /><property name="connectionProperties" value="{spring.datasource.connectionProperties}" />
</bean>
<!-- ### 配置数据源 end ###--><!-- ### Mybatis和事务配置 begin ###-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"><property name="dataSource" ref="dataSource"/><!-- 配置扫描Mapper XML的位置 --><property name="mapperLocations" value="classpath:com/hry/spring/mybatis/mapper/*.xml"/><!-- 配置mybatis配置文件的位置 --><property name="configLocation" value="classpath:config/spring/mybatis_config.xml"/></bean><!-- 配置扫描Mapper接口的包路径 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"><property name="basePackage" value="com.hry.spring.mybatis.mapper"/><property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean><!-- 事务配置 -->
<bean id="transactionManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager"p:dataSource-ref="dataSource"/><tx:advice id="txAdvice" transaction-manager="transactionManager" ><tx:attributes><tx:method name="add*" propagation="REQUIRED" /><tx:method name="create*" propagation="REQUIRED" /><tx:method name="save*" propagation="REQUIRED" /><tx:method name="insert*" propagation="REQUIRED" /><tx:method name="update*" propagation="REQUIRED" /><tx:method name="batch*" propagation="REQUIRED" /><tx:method name="del*" propagation="REQUIRED" /><tx:method name="get*" propagation="SUPPORTS" read-only="true" /><tx:method name="find*" propagation="SUPPORTS" read-only="true" /><tx:method name="*" read-only="true"/></tx:attributes>
</tx:advice>
<aop:config ><aop:pointcut id="pt" expression="execution(* com.hry.spring.mybatis.service..*.*(..))" /><aop:advisor pointcut-ref="pt" advice-ref="txAdvice"/>
</aop:config>
<!-- ### Mybatis和事物配置 end ###-->
mybatis_config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration></configuration>
2.4. application.yml
配置数据库的信息如下:
# 数据库配置
spring:datasource:#### Datasource 配置 ####type: com.alibaba.druid.pool.DruidDataSourceusername: rootpassword: rooturl: jdbc:mysql://127.0.0.1:3306/test?zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2b8&useSSL=true# url: jdbc:mysql://127.0.0.1:3306/testdriverClassName: com.mysql.cj.jdbc.Driver# driverClassName: oracle.jdbc.driver.OracleDriver# 下面为连接池的补充设置,应用到上面所有数据源中# 初始化大小,最小,最大initialSize: 5minIdle: 5maxActive: 20# 配置获取连接等待超时的时间maxWait: 30000# 配置一个连接在池中最小生存的时间,单位是毫秒minEvictableIdleTimeMillis: 300000timeBetweenEvictionRunsMillis: 60000validationQuery: SELECT 1 FROM DUAL# 打开PSCache,并且指定每个连接上PSCache的大小poolPreparedStatements: falsemaxPoolPreparedStatementPerConnectionSize: 20testWhileIdle: truetestOnBorrow: falsetestOnReturn: false# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙filters: log4jconnectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
2.5. spring boot集成mybatis
通过@ImportResource加载mybatis的配置
用@Bean注解的方法fastJsonHttpMessageConverters表示使用fastjson解析json
@SpringBootApplication
// 加载mybatis配置
@ImportResource({"classpath:config/spring/spring_*.xml"})
public class MybatisSpringBoot {public static void main(String[] args){SpringApplication.run(MybatisSpringBoot.class, args);}@Beanpublic HttpMessageConverters fastJsonHttpMessageConverters() {// 格式化时间SerializeConfig mapping = new SerializeConfig();mapping.put(Date.class, new SimpleDateFormatSerializer("yyyy-MM-dd HH:mm:ss"));FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();FastJsonConfig fastJsonConfig = new FastJsonConfig();// fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat);fastJsonConfig.setSerializeConfig(mapping);fastConverter.setFastJsonConfig(fastJsonConfig);HttpMessageConverter<?> converter = fastConverter;return new HttpMessageConverters(converter);}}
3. Spring Boot集成分布插件Pagehelper
以上的功能实现了简单的mybatis应用。但是涉及到数据库的查询,不可避免需要使用到分页。这里我推荐pagehelper插件实现分页功能
3.1. pom.xml
引入相关的jar
<!-- 分布插件 -->
<dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper</artifactId><version>5.1.1</version>
</dependency>
<!-- Spring Boot集成 pagehelper-->
<dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper-spring-boot-starter</artifactId><version>1.2.1</version>
</dependency>
3.2. 分页相关的辅助类
MyPage
包装返回给前台的信息,包括本次查询的状态码、错误信息、记录总数和数据列表
public class MyPage<T> {@JSONField(ordinal = 1)private Integer code = 200;// 状态码,默认状态@JSONField(ordinal = 2)private String message = "";// 提示消息或者错误消息@JSONField(ordinal = 3)private String apiId = "";// 请求的唯一标识,预留@JSONField(ordinal = 4)private Integer totalCount = 0;//记录总数@JSONField(ordinal = 5)private List<T> rows = Collections.emptyList();//本次返回的数据列表// set/get略
}
IPageHelperPageCallBack
定义分页的回调方法,如果使分页,则必须在这个方法里使用mapper的方法。
此接口作为下文的PageCallBackUtil的参数
public interface IPageHelperPageCallBack {<T> List<T> select();
}
PageCallBackUtil
pagehelper的使用核心是:调用PageHelper.startPage(pageNum, pageSize,requireTotalCount)方法设置查询记录起始地址后,然后马上调用mapper类的方法,得到返回列表List,使用( PageInfo pageInfo = new PageInfo(list))包装list的PageInfo,PageInfo包含本次查询的信息,包括本次查询的总数,然后将Model转化为Dto类
/*** 分页的回调函数* Created by huangrongyou@yixin.im on 2017/9/6.*/
public class PageCallBackUtil {/*** 封装公共PageHelper的操作* @param qry* @param callBack* @param <T>* @return*/public static<T> MyPage<T> selectRtnPage(AbstractQry qry, IPageHelperPageCallBack callBack){Assert.notNull(qry, "qry can't be null!");Assert.notNull(callBack, "callBack cant' be null!");setPageHelperStartPage(qry);List<T> list = callBack.select();// 分页时,实际返回的结果list类型是Page<E>if(!(list instanceof Page)){throw new RuntimeException("list must be 'com.github.pagehelper.Page', now is " + list.getClass().getCanonicalName());}MyPage<T> myPage = new MyPage<T>();PageInfo<T> pageInfo = new PageInfo<T>(list);myPage.setTotalCount((int) pageInfo.getTotal());myPage.setRows(pageInfo.getList());return myPage;}/*** 设置PageHelper的startPage* @param qry*/private static void setPageHelperStartPage(AbstractQry qry) {// 设置分页信息// pageNumInteger pageNum = qry.getPageNum();pageNum = pageNum == null? AbstractQry.DEFAULT_PAGENUM : pageNum;// pageSizeInteger pageSize = qry.getPageSize();pageSize = pageSize == null ? AbstractQry.DEFAULT_PAGESIZE : pageSize;// requireTotalCountBoolean requireTotalCount = qry.getRequireTotalCount();requireTotalCount = requireTotalCount == null ? AbstractQry.DEFAULT_REQUIRETOTALCOUNT : requireTotalCount;PageHelper.startPage(pageNum, pageSize,requireTotalCount);}
}
Qry
查询条件的基类
public interface Qry {String getId();void setId(String id);
}
AbstractQry
定义分页的查询的页码信息
public class AbstractQry implements Qry {public static final int DEFAULT_PAGENUM = 1;public static final int DEFAULT_PAGESIZE = 1;public static final boolean DEFAULT_REQUIRETOTALCOUNT = false;private String id;private Integer pageNum = 1;// 第几页,首页为1private Integer pageSize = 10;// 每页记录条数private Boolean requireTotalCount = Boolean.FALSE;// 是否需要记录总数// set/get略
}
TestQry
这个类用来定义具体的查询条件
public class TestQry extends AbstractQry{}
3.3. 服务层:ITestService和TestServiceImpl
ITestService
public interface ITestService {int deleteByPrimaryKey(Integer id);int insertSelective(TestModel record);TestModel selectByPrimaryKey(Integer id);List<TestModel> selectAll(TestQry qry);MyPage<TestModel> selectAllWithPage(TestQry qry);
}
TestServiceImpl
selectAllWithPage定义了方法的使用
@Service
@Primary
public class TestServiceImpl implements ITestService{@Autowiredprivate TestMapper testMapper;@Overridepublic int deleteByPrimaryKey(Integer id) {Assert.notNull(id, "id can't be null!");return testMapper.deleteByPrimaryKey(id);}@Overridepublic MyPage<TestModel> selectAllWithPage(TestQry qry) {if(qry == null){qry = new TestQry();}MyPage<TestModel> myPage = PageCallBackUtil.selectRtnPage(qry, new IPageHelperPageCallBack() {@Overridepublic List<TestModel> select() {return testMapper.selectAll();}});return myPage;}… 其他方法略}
3.4. Control层
类 TestCtl
@RestController
@RequestMapping(value = "/simple")
@EnableSwagger2
public class TestCtl {@Autowiredprivate ITestService testService;@RequestMapping(value = "delete-by-primary-key/{id}", method = RequestMethod.GET)public int deleteByPrimaryKey( @PathVariable("id") Integer id){// 参数验证略return testService.deleteByPrimaryKey(id);}@RequestMapping(value = "insert-selective", method = RequestMethod.POST)public int insertSelective(@RequestBody TestDto dto){// 参数验证略TestModel record = new TestModel();record.setId(dto.getId());record.setAge(dto.getAge());record.setName(dto.getName());return testService.insertSelective(record);}@RequestMapping(value = "select-by-primary-key/{id}", method = RequestMethod.POST)public TestDto selectByPrimaryKey(@PathVariable("id") String id){// 参数验证略return Model2DtoUtil.model2Dto(testService.selectByPrimaryKey(Integer.parseInt(id)), TestDto.class);}@RequestMapping(value = "select-all", method = {RequestMethod.POST })public List<TestDto> selectAll(@RequestBody TestQry qry){return Model2DtoUtil.model2Dto(testService.selectAll(qry), TestDto.class);}@RequestMapping(value = "select-all-with-page", method = {RequestMethod.POST })public MyPage<TestDto> selectAllWithPage(@RequestBody TestQry qry){MyPage<TestDto> page = Model2DtoUtil.model2Dto(testService.selectAllWithPage(qry), TestDto.class);page.setMessage(getLocalInfo());return page;}private String getLocalInfo(){StringBuilder sb = new StringBuilder();try {InetAddress inetAddress = InetAddress.getLocalHost();sb.append("server info :").append("[ip:").append(inetAddress.getHostAddress()).append(",hostname:").append(inetAddress.getHostName()).append("]");} catch (UnknownHostException e) {e.printStackTrace();}return sb.toString();}
}
3.5. model转化为dto类的工具类
Model2DtoUtil
工具类,封装将model转化为dto类,实现数据层和传输层的解耦
public class Model2DtoUtil {/*** 将 MyPage<model> 修改为 MyPage<Dto>** @param sourcePage* @param cls* @param <T>* @param <K>* @return*/public static <T, K> MyPage<K> model2Dto(MyPage<T> sourcePage, Class<K> cls) {if(sourcePage == null){return null;}Assert.notNull(cls, "cls can't be null!");MyPage<K> dstPage = new MyPage<K>();dstPage.setTotalCount(sourcePage.getTotalCount());dstPage.setApiId(sourcePage.getApiId());dstPage.setMessage(sourcePage.getMessage());dstPage.setCode(sourcePage.getCode());// listList<T> sourceList = sourcePage.getRows();List<K> dstList = new ArrayList<K>();dealListModel2Dto(sourceList, cls, dstList);dstPage.setRows(dstList);return dstPage;}private static <T, K> void dealListModel2Dto(List<T> sourceList, Class<K> cls, List<K> dstList) {for (T source : sourceList) {try {K dst = cls.newInstance();CommonBeanUtils.copyProperties(source, dst);dstList.add(dst);} catch (InstantiationException e) {e.printStackTrace();throw new BeanCreationException(e.getMessage());} catch (IllegalAccessException e) {e.printStackTrace();throw new BeanCreationException(e.getMessage());}}}}
CommonBeanUtils
BeanUtils工具类:
public class CommonBeanUtils {public static void copyProperties(Object source, Object target){BeanUtils.copyProperties(source, target);}
}
3.6. application.yml
pagehelper相关的配置,其它的配置参数见官网
如果不配置以下参数,则分页机制不会启作用
# 分页配置: https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/zh/HowToUse.md
pagehelper:helperDialect: oraclereasonable: truesupportMethodsArguments: trueparams: count=countSql
4. Spring Boot集成swagger和测试
为了对测试方便,我们引入swagger
4.1. pom.xml
<!-- swagger2 -->
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 -->
<dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>2.7.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui -->
<dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger-ui</artifactId><version>2.7.0</version>
</dependency>
4.2. @EnableSwagger2
在TestCtl的类上加上@EnableSwagger2
@RestController
@RequestMapping(value = "/simple")
@EnableSwagger2
public class TestCtl {…
}
4.3. 测试
打开地址:http://127.0.0.1:8080/swagger-ui.html
可以看到当前可用的url接口
测试 /simple/select-all-with-page接口的分页功能,设置查询功能
返回结果如下
5.代码
上文的详细代码见github代码,请尽量使用tag v0.2,不要使用master,因为master一直在变,不能保证文章中代码和github上的代码一直相同
Spring Boot系列六 Spring boot集成mybatis、分页插件pagehelper相关推荐
- (转)淘淘商城系列——MyBatis分页插件(PageHelper)的使用以及商品列表展示
http://blog.csdn.net/yerenyuan_pku/article/details/72774381 上文我们实现了展示后台页面的功能,而本文我们实现的主要功能是展示商品列表,大家要 ...
- 解决使用mybatis分页插件PageHelper的一个报错问题
解决使用mybatis分页插件PageHelper的一个报错问题 参考文章: (1)解决使用mybatis分页插件PageHelper的一个报错问题 (2)https://www.cnblogs.co ...
- Mybatis分页插件PageHelper使用教程(图文详细版)
Mybatis分页插件PageHelper使用教程(图文详细版) 1.配置 2.后台代码 controller类 html页面 html页面效果图 1.配置 小编的项目是springBoot项目,所以 ...
- MyBatis分页插件PageHelper使用练习
转载自:http://git.oschina.net/free/Mybatis_PageHelper/blob/master/wikis/HowToUse.markdown 1.环境准备: 分页插件p ...
- MyBatis学习总结(17)——Mybatis分页插件PageHelper
2019独角兽企业重金招聘Python工程师标准>>> 如果你也在用Mybatis,建议尝试该分页插件,这一定是最方便使用的分页插件. 分页插件支持任何复杂的单表.多表分页,部分特殊 ...
- 【MyBatis】MyBatis分页插件PageHelper的使用
转载自 https://www.cnblogs.com/shanheyongmu/p/5864047.html 好多天没写博客了,因为最近在实习,大部分时间在熟悉实习相关的东西,也没有怎么学习新的东西 ...
- MyBatis 分页插件 PageHelper:是如何拦截SQL进行分页
目录 Springboot项目集成 分页插件参数介绍 如何选择配置这些参数 场景一 场景二 场景三 场景四 场景五 PageHelper的使用 PageHelper实现原理1: interceptor ...
- Mybatis分页插件PageHelper简单使用
转载自:https://www.cnblogs.com/ljdblog/p/6725094.html 引言 对于使用Mybatis时,最头痛的就是写分页,需要先写一个查询count的select语句, ...
- mybatis分页插件pageHelper简单实用
转载自 http://blog.csdn.net/Smile_Miracle/article/details/53185655 工作的框架spring springmvc mybatis3 首先使用分 ...
最新文章
- Asp.net 2.0 C#实现压缩/解压功能
- CCHP分布式能源技术在数据中心IDC的应用
- string的内存管理问题
- MybatisPlus代码生成器配置
- 何可欣(为奥运冠军名字作诗)
- Linux的实际操作:文件目录类的实用指令(rm mv)
- lombok原理_听说学会用 Lombok 就可以让你早点下班?(你还不看)
- (29)VHDL实现时钟分频
- CCF201412-5 货物调度【费用流】(100分解题链接)
- 转行软件测试,简历怎么包装成1年工作经验的测试工程师
- FlashFXP5.4
- d3dx9_42.dll缺少
- 电源防反接和防倒灌 - 使用MOS 管和运放实现理想二极管
- 游戏模块分析总结(4)之系统篇
- 抖音算法推荐机制详解!(科普向)
- sklearn 增量学习
- 计算机数制详解及相互转换(二进制、八进制、十进制、十六进制)
- 通用二维码生成 API 接口
- 不得不爱:中国十大绝色美景图
- 2011腾讯海笔 大概题型(欢迎讨论)