SpringBoot与MybatisPlus3.X整合示例(十六)
包含 分页、逻辑删除、自定义全局操作 等绝大部分常用功能的使用示例,相当于大整合的完整示例
pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.49</version>
<scope>test</scope>
</dependency>
<!-- for testing -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>application.yml
# DataSource Config
spring:
datasource:
driver-class-name: org.h2.Driver
url: jdbc:h2:tcp://192.168.180.115:19200/~/mem/test
username: root
password: test
# Logger Config
logging:
level:
com.mp.deluxe: debug
mybatis-plus:
# 扫描 mapper.xml
mapper-locations: classpath:/mapper/*Mapper.xml
configuration:
jdbc-type-for-null: 'null'配置类
public interface MyBaseMapper<T> extends BaseMapper<T> {
/**
* 自定义通用方法
*/
Integer deleteAll();
int myInsertAll(T entity);
/**
* 如果要自动填充,@{@code Param}(xx) xx参数名必须是 list/collection/array 3个的其中之一
*
* @param batchList
* @return
*/
int mysqlInsertAllBatch(@Param("list") List<T> batchList);
}
@Configuration
@MapperScan("com.mp.deluxe.mapper")
public class MybatisPlusConfig {
/**
* 1.分页插件
* 2.多租户
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor(){
return new OptimisticLockerInterceptor();
}
/**
* 自定义 SqlInjector
* 里面包含自定义的全局方法
*/
@Bean
public MyLogicSqlInjector myLogicSqlInjector() {
return new MyLogicSqlInjector();
}
}
public class TestTypeHandler extends BaseTypeHandler<String> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
ps.setString(i, "TestTypeHandler set {" + parameter + "}");
}
@Override
public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
String string = rs.getString(columnName);
return "TestTypeHandler(rs columnName) get {" + string + "}";
}
@Override
public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
String string = rs.getString(columnIndex);
return "TestTypeHandler(rs columnIndex) get {" + string + "}";
}
@Override
public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
String string = cs.getString(columnIndex);
return "TestTypeHandler(cs columnIndex) get {" + string + "}";
}
}
@Data
@Accessors(chain = true)
public class User {
private Long id;
private String name;
private Integer age;
@TableField(typeHandler = TestTypeHandler.class)
private String email;
@Version
private Integer version;
@TableLogic(value = "0", delval = "1")
@TableField(select = false)
private Integer deleted;
@TableField(value = "create_time", fill = FieldFill.INSERT)
private Timestamp createTime;
}
Mapper层
public interface UserMapper extends MyBaseMapper<User> {
/**
* 自定义分页查询
*
* @param userPage 单独 user 模块使用的分页
* @return 分页数据
*/
UserPage selectUserPage(UserPage userPage);
List<User> findList(@Param("user") User user);
}方法层
public class DeleteAll extends AbstractMethod {
@Override
public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
/* 执行 SQL ,动态 SQL 参考类 SqlMethod */
String sql = "delete from " + tableInfo.getTableName();
/* mapper 接口方法名一致 */
String method = "deleteAll";
SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);
return this.addDeleteMappedStatement(mapperClass, method, sqlSource);
}
}
public class MyInsertAll extends AbstractMethod {
@Override
public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
String sql = "insert into %s %s values %s";
StringBuilder fieldSql = new StringBuilder();
fieldSql.append(tableInfo.getKeyColumn()).append(",");
StringBuilder valueSql = new StringBuilder();
valueSql.append("#{").append(tableInfo.getKeyProperty()).append("},");
tableInfo.getFieldList().forEach(x->{
fieldSql.append(x.getColumn()).append(",");
valueSql.append("#{").append(x.getProperty()).append("},");
});
fieldSql.delete(fieldSql.length()-1, fieldSql.length());
fieldSql.insert(0, "(");
fieldSql.append(")");
valueSql.insert(0, "(");
valueSql.delete(valueSql.length()-1, valueSql.length());
valueSql.append(")");
SqlSource sqlSource = languageDriver.createSqlSource(configuration, String.format(sql, tableInfo.getTableName(), fieldSql.toString(), valueSql.toString()), modelClass);
return this.addInsertMappedStatement(mapperClass, modelClass, "myInsertAll", sqlSource, new NoKeyGenerator(), null, null);
}
}
public class MysqlInsertAllBatch extends AbstractMethod {
@Override
public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
final String sql = "<script>insert into %s %s values %s</script>";
final String fieldSql = prepareFieldSql(tableInfo);
final String valueSql = prepareValuesSqlForMysqlBatch(tableInfo);
final String sqlResult = String.format(sql, tableInfo.getTableName(), fieldSql, valueSql);
SqlSource sqlSource = languageDriver.createSqlSource(configuration, sqlResult, modelClass);
return this.addInsertMappedStatement(mapperClass, modelClass, "mysqlInsertAllBatch", sqlSource, new NoKeyGenerator(), null, null);
}
private String prepareFieldSql(TableInfo tableInfo) {
StringBuilder fieldSql = new StringBuilder();
fieldSql.append(tableInfo.getKeyColumn()).append(",");
tableInfo.getFieldList().forEach(x -> {
fieldSql.append(x.getColumn()).append(",");
});
fieldSql.delete(fieldSql.length() - 1, fieldSql.length());
fieldSql.insert(0, "(");
fieldSql.append(")");
return fieldSql.toString();
}
private String prepareValuesSqlForMysqlBatch(TableInfo tableInfo) {
final StringBuilder valueSql = new StringBuilder();
valueSql.append("<foreach collection=\"list\" item=\"item\" index=\"index\" open=\"(\" separator=\"),(\" close=\")\">");
valueSql.append("#{item.").append(tableInfo.getKeyProperty()).append("},");
tableInfo.getFieldList().forEach(x -> valueSql.append("#{item.").append(x.getProperty()).append("},"));
valueSql.delete(valueSql.length() - 1, valueSql.length());
valueSql.append("</foreach>");
return valueSql.toString();
}
}
model层
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
public class UserPage extends Page<User> {
private static final long serialVersionUID = 7246194974980132237L;
private Integer selectInt;
private String selectStr;
public UserPage(long current, long size) {
super(current, size);
}
}
其他类
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(MyMetaObjectHandler.class);
@Override
public void insertFill(MetaObject metaObject) {
LOGGER.info("start insert fill ....");
//避免使用metaObject.setValue()
this.setInsertFieldValByName("createTime", new Timestamp(System.currentTimeMillis()), metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
LOGGER.info("nothing to fill ....");
}
}
public class MyLogicSqlInjector extends DefaultSqlInjector {
/**
* 如果只需增加方法,保留MP自带方法
* 可以super.getMethodList() 再add
* @return
*/
@Override
public List<AbstractMethod> getMethodList(Class<?> mapperClass) {
List<AbstractMethod> methodList = super.getMethodList(mapperClass);
methodList.add(new DeleteAll());
methodList.add(new MyInsertAll());
methodList.add(new MysqlInsertAllBatch());
methodList.add(new SelectById());
return methodList;
}
}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.mp.deluxe.mapper.UserMapper">
<select id="selectUserPage" resultType="com.mp.deluxe.model.UserPage">
select *
from user
<trim prefix="where" prefixOverrides="AND">
<if test="selectInt != null">
age = #{selectInt}
</if>
<if test="selectStr != null">
AND name = #{selectStr}
</if>
AND deleted = 0
</trim>
</select>
<!-- verify github #1532-->
<select id="findList" parameterType="com.mp.deluxe.entity.User" resultType="com.mp.deluxe.entity.User">
select * from user where name like concat(concat('%', #{user.name}), '%')
</select>
</mapper>测试类
@SpringBootTest
class DeluxeApplicationTests {
@Resource
private UserMapper mapper;
@Test
public void testPage() {
// System.out.println("------ 自定义 xml 分页 ------");
// UserPage selectPage = new UserPage(1, 5).setSelectInt(20);
// UserPage userPage = mapper.selectUserPage(selectPage);
// Assert.assertSame(userPage, selectPage);
// System.out.println("总条数 ------> " + userPage.getTotal());
// System.out.println("当前页数 ------> " + userPage.getCurrent());
// System.out.println("当前每页显示数 ------> " + userPage.getSize());
// print(userPage.getRecords());
System.out.println("------ baseMapper 自带分页 ------");
Page<User> page = new Page<>(1, 5);
IPage<User> userIPage = mapper.selectPage(page, new QueryWrapper<User>().eq("age", 20));
Assert.assertSame(userIPage, page);
System.out.println("总条数 ------> " + userIPage.getTotal());
System.out.println("当前页数 ------> " + userIPage.getCurrent());
System.out.println("当前每页显示数 ------> " + userIPage.getSize());
print(userIPage.getRecords());
}
@Test
public void testDelAll() {
mapper.deleteAll();
}
@Test
public void testInsert() {
User u = new User().setEmail("122@qq.com").setVersion(1).setDeleted(0);
mapper.insert(u);
u.setAge(18);
mapper.updateById(u);
u = mapper.selectById(u.getId());
Assert.assertEquals("version should be updated",2, u.getVersion().intValue());
}
@Test
public void testSelect() {
System.out.println(mapper.selectById(1L));
}
private <T> void print(List<T> list) {
if (!CollectionUtils.isEmpty(list)) {
list.forEach(System.out::println);
}
}
@Test
public void myInsertAll(){
long id =1008888L;
User u = new User().setEmail("122@qq.com").setVersion(1).setDeleted(0).setId(id);
mapper.myInsertAll(u);
User user = mapper.selectById(id);
Assert.assertNotNull(user);
Assert.assertNotNull(user.getCreateTime());
}
@Test
public void myInsertBatch(){
long id = 1009991;
List<User> batchList = new ArrayList<>(2);
batchList.add(new User().setId(id++).setEmail("111@qq.com").setVersion(1).setDeleted(0));
batchList.add(new User().setId(id).setEmail("112@qq.com").setVersion(1).setDeleted(0));
mapper.mysqlInsertAllBatch(batchList);
User user = mapper.selectById(1009991);
Assert.assertNotNull(user);
Assert.assertNotNull(user.getCreateTime());
}
@Test
public void verifyGithub1532(){
mapper.findList(new User().setName("a")).forEach(System.out::println);
}
}部分方法的测试结果
2019-11-02 16:16:46.170 WARN 6088 --- [ main] c.b.m.core.injector.AbstractMethod : [com.mp.deluxe.mapper.UserMapper.selectById] Has been loaded by XML or SqlProvider or Mybatis's Annotation, so ignoring this injection for [class com.baomidou.mybatisplus.core.injector.methods.SelectById]
_ _ |_ _ _|_. ___ _ | _
| | |\/|_)(_| | |_\ |_)||_|_\
/ |
3.2.0
2019-11-02 16:16:46.366 INFO 6088 --- [ main] com.mp.deluxe.DeluxeApplicationTests : Started DeluxeApplicationTests in 3.38 seconds (JVM running for 5.204)
------ baseMapper 自带分页 ------
2019-11-02 16:16:46.680 INFO 6088 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
2019-11-02 16:16:46.799 INFO 6088 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
2019-11-02 16:16:46.873 DEBUG 6088 --- [ main] c.m.deluxe.mapper.UserMapper.selectPage : ==> Preparing: SELECT COUNT(1) FROM user WHERE deleted = 0 AND (age = ?)
2019-11-02 16:16:46.893 DEBUG 6088 --- [ main] c.m.deluxe.mapper.UserMapper.selectPage : ==> Parameters: 20(Integer)
2019-11-02 16:16:46.916 DEBUG 6088 --- [ main] c.m.deluxe.mapper.UserMapper.selectPage : ==> Preparing: SELECT id,create_time,name,version,email,age FROM user WHERE deleted=0 AND (age = ?) limit ?
2019-11-02 16:16:46.928 DEBUG 6088 --- [ main] c.m.deluxe.mapper.UserMapper.selectPage : ==> Parameters: 20(Integer), 5(Long)
2019-11-02 16:16:46.946 DEBUG 6088 --- [ main] c.m.deluxe.mapper.UserMapper.selectPage : <== Total: 5
总条数 ------> 13
当前页数 ------> 1
当前每页显示数 ------> 5
User(id=2, name=Jack, age=20, email=test2@baomidou.com, version=1, deleted=null, createTime=null)
User(id=3, name=Jack, age=20, email=test2@baomidou.com, version=1, deleted=null, createTime=null)
User(id=4, name=Jack, age=20, email=test2@baomidou.com, version=1, deleted=null, createTime=null)
User(id=5, name=Jack, age=20, email=test2@baomidou.com, version=1, deleted=null, createTime=null)
User(id=6, name=Jack, age=20, email=test2@baomidou.com, version=1, deleted=null, createTime=null)
SpringBoot与MybatisPlus3.X整合示例(十六)的更多相关文章
- SpringBoot与PageHelper的整合示例详解
SpringBoot与PageHelper的整合示例详解 1.PageHelper简介 PageHelper官网地址: https://pagehelper.github.io/ 摘要: com.gi ...
- SpringBoot与MybatisPlus3.X整合之通用枚举(十二)
一 通用枚举 解决了繁琐的配置,让 mybatis 优雅的使用枚举属性! 自3.1.0开始,可配置默认枚举处理类来省略扫描通用枚举配置 默认枚举配置 升级说明: 3.1.0 以下版本改变了原生默认行为 ...
- SpringBoot与MybatisPlus3.X整合之字段类型处理器(八)
pom.xml <dependencies> <dependency> <groupId>org.springframework.boot</groupId& ...
- SpringBoot与MybatisPlus3.X整合之动态表名 SQL 解析器(七)
pom.xml <dependencies> <dependency> <groupId>org.springframework.boot</groupId& ...
- SpringBoot | 第二十六章:邮件发送
前言 讲解了日志相关的知识点后.今天来点相对简单的,一般上,我们在开发一些注册功能.发送验证码或者订单服务时,都会通过短信或者邮件的方式通知消费者,注册或者订单的相关信息.而且基本上邮件的内容都是模版 ...
- 二十六:Struts2 和 spring整合
二十六:Struts2 和 spring整合 将项目名称为day29_02_struts2Spring下的scr目录下的Struts.xml文件拷贝到新项目的scr目录下 在新项目的WebRoot-- ...
- 【Visual C++】游戏开发五十六 浅墨DirectX教程二十三 打造游戏GUI界面(一)
本系列文章由zhmxy555(毛星云)编写,转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/16384009 作者:毛星云 ...
- 跟我学SpringCloud | 第十六篇:微服务利剑之APM平台(二)Pinpoint
目录 SpringCloud系列教程 | 第十六篇:微服务利剑之APM平台(二)Pinpoint 1. Pinpoint概述 2. Pinpoint主要特性 3. Pinpoint优势 4. Pinp ...
- Spring Boot 2.X(十六):应用监控之 Spring Boot Actuator 使用及配置
Actuator 简介 Actuator 是 Spring Boot 提供的对应用系统的自省和监控功能.通过 Actuator,可以使用数据化的指标去度量应用的运行情况,比如查看服务器的磁盘.内存.C ...
随机推荐
- .NET之Hangfire快速入门和使用
前言: 定时任务调度问题,是一个老生常谈的问题.网上有许多定时任务调度的解决方案,对于我而言很早以前主要是使用Window计划和Window服务来做任务定时执行,然后就开始使用定时任务调度框架Quar ...
- freemarker模版引擎技术总结
FreeMarker语言概述 FreeMarker是一个模板引擎,一个基于模板生成文本输出的通用工具,使用纯Java编写. FreeMarker被设计用来生成HTML Web页面,特别是基于MVC模式 ...
- Linux系列之yum安装
yum是Linux系统的安装必备神器,简直不要太方便.但是新系统一般是不自带yum工具的,所以需要手动安装一下. 环境:centos7 新建一个目录用来保存yum安装包 mkdir install 进 ...
- Kubernetes 系列(三):Kubernetes使用Traefik Ingress暴露服务
一.Kubernetes 服务暴露介绍 从 kubernetes 1.2 版本开始,kubernetes提供了 Ingress 对象来实现对外暴露服务:到目前为止 kubernetes 总共有三种暴露 ...
- WKWebView针对于Cordova的IOS平台性能提升
使用cordova做跨平台开发已久,针对于Android的性能与页面渲染问题仍然让人头疼,因为仍然有一部分人使用性能一般的手机,版本在 4.2-4.4之间,甚至都无法支持HTML5的flex布局,使得 ...
- c++ 对特定进程的内存监控
在工具实现的过程中,遇到了内存爆了的问题,部分模型的规模可以达到10的100次方方甚至1000次方.(工具的主要算法涉及到了递归,递归深度会很深,所以也用到了ulimit修改栈空间来缓解爆栈的问题,治 ...
- nginx的负载均衡实战
前言 nginx是一个高性能的HTTP和反向代理的服务器.它有三个最基本的功能,一是当做web服务器.二是作为反向代理服务器.三是提供负载均衡(在反向代理基础上),由于它占有内存小,并发能力强,所以在 ...
- .NET Core使用gRPC打造服务间通信基础设施
一.什么是RPC rpc(远程过程调用)是一个古老而新颖的名词,他几乎与http协议同时或更早诞生,也是互联网数据传输过程中非常重要的传输机制. 利用这种传输机制,不同进程(或服务)间像调用本地进程中 ...
- Bitset改进你的程序质量
1:Bitset介绍 BitSet 是用于存储二进制位和对二进制进行操作的 Java 数据结构, 此类实现了一个按需增长的位向量.位 set 的每个组件都有一个 boolean 值.用非负的整数将 B ...
- [NOIp2011] luogu P1313 计算系数
继续水博客,待会回去上术学. 题目描述 给定一个多项式 (by+ax)k(by+ax)^k(by+ax)k ,请求出多项式展开后 xn×ymx^n \times y^mxn×ym 项的系数. Solu ...