目录
一、maven依赖
<!-- mybatis-plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.2</version>
</dependency>
完整springboot maven依赖
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.2</version>
<relativePath/>
</parent>
<groupId>com.mx</groupId>
<artifactId>mybatis-plus-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<name>mybatis-plus-demo</name>
<properties>
<java.version>1.8</java.version>
<mybatis.plus.version>3.4.2</mybatis.plus.version>
</properties>
<dependencies>
<!-- Spring -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<scope>compile</scope>
<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-web</artifactId>
<scope>compile</scope>
<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-log4j2</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- mybatis-plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis.plus.version}</version>
</dependency>
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
二、通过Mybatis-Plus生成器生成代码
1、生成代码
生成代码可参考我的另一篇博文:Mybatis plus代码生成器
然后将生成后的代码以及mapper.xml拷贝到对应的工程内:
2、配置mybatis - @MapperScan、分页插件
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Mybatis-Plus配置
*
* @author luohq
* @date 2021-02-01
*/
@Configuration
@MapperScan("com.mx.demo.mapper")
public class MybatisPlusConfig {
/**
* 新的分页插件,
* 一缓和二缓遵循mybatis的规则,
* 需要设置 MybatisConfiguration#useDeprecatedExecutor = false
* 避免缓存出现问题(该属性会在旧插件移除后一同移除)
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
@Bean
public ConfigurationCustomizer configurationCustomizer() {
return configuration -> configuration.setUseDeprecatedExecutor(false);
}
}
3、spring application配置
server:
port: 8080
# =========================================================================
# ============================ mysql数据源连接配置 ==========================
# =========================================================================
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/db_msg_push?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&nullCatalogMeansCurrent=true
username: root
password: root
type: com.zaxxer.hikari.HikariDataSource
hikari:
# 连接池最少空闲连接数(默认10)
minimum-idle: 10
# 连接池中允许的最大连接数(默认10),推荐的公式:(core_count * 2) + effective_spindle_count
maximum-pool-size: 20
# 一个连接idle状态的最大时长(毫秒,>=10s,默认10分钟),超时则被释放(retired)
idle-timeout: 600000
# 等待连接池分配连接的最大时长(毫秒,>=250ms,默认30秒),超过这个时长还没可用的连接则发生SQLException
connection-timeout: 30000
# JDBC4支持conn.isValid(int timeout),可禁用该属性
# connection-test-query: SELECT 1
# 验证连接aliveness(即每次从连接池获取connection前调用conn.isValid(timeout)的超时时间)的超时时长
# (毫秒,>=250ms,默认5s,需要小于connection-timeout,若小于250ms则重置为5s)
validation-timeout: 5000
# 连接只读数据库时配置为true, 保证安全
read-only: false
# 一个连接的生命时长(毫秒),超时而且没被使用则被释放(retired)(>=30s,默认30分钟)
# 建议设置比数据库超时时长少30秒,参考MySQL wait_timeout(默认28800s,即8小时)参数(show variables like '%timeout%';)
max-lifetime: 1800000
# 设置是否自动提交事务
auto-commit: true
# 连接池名称
pool-name: LuoHikariCP
# =========================================================================
# ============================ mybatis配置 ================================
# =========================================================================
mybatis:
mapperLocations: classpath:mapper/*.xml
typeAliasesPackage: com.mx.demo.model.entity
三、使用Mybatis-Plus
查看生成代码发现Mapper继承了BaseMapper,Service都继承了IService,这两个基类都内置了一些常规的CRUD操作,对于单表的操作基本不需要再自定义mapper.xml了,而对于一些复杂的连接查询,还是可以通过自定义mapper.xml来进行的。
并且在新版本的Mybatis-Plus中支持Java8 Lamba表达式,即可以通过Lamba表达式进行column名称的设置,避免了最开始的字面量(字符串)设置;
以下为几个简单示例:
package com.mx.demo.service.impl;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mx.demo.enums.RespCodeEnum;
import com.mx.demo.mapper.MsgPushMapper;
import com.mx.demo.model.entity.MsgPush;
import com.mx.demo.model.entity.MsgTarget;
import com.mx.demo.model.param.FindMsgPushParam;
import com.mx.demo.model.param.MsgPushParam;
import com.mx.demo.model.param.PageBaseParam;
import com.mx.demo.model.result.RespResult;
import com.mx.demo.service.IMsgPushService;
import com.mx.demo.service.IMsgTargetService;
import com.mx.demo.utils.CommonUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;
/**
* <p>
* 消息推送 服务实现类
* </p>
*
* @author luohq
* @since 2021-01-31
*/
@Service
public class MsgPushServiceImpl extends ServiceImpl<MsgPushMapper, MsgPush> implements IMsgPushService {
@Resource
private IMsgTargetService msgTargetService;
@Override
public RespResult addMsgPush(MsgPushParam msgPushParam) {
/** 保存msgPush */
MsgPush msgPush = this.convertMsgPush(msgPushParam);
//执行保存操作
Boolean success = this.save(msgPush);
/** 保存消息目标 */
List<MsgTarget> msgTargetList = this.convertMsgTargetList(msgPush, msgPushParam);
//执行批量保存操作
success = this.msgTargetService.saveBatch(msgTargetList);
return RespResult.buildWith(success);
}
@Override
public RespResult<MsgPush> findMsgPushList(FindMsgPushParam param) {
//(create_time >= #{startCreateTime} and create_time <= #{endCreateTime})
//and (id = #{id} or msg_content like concat('%', #{msgContent}, '%'))
LambdaQueryWrapper queryWrapper = Wrappers.<MsgPush>lambdaQuery()
.ge(ObjectUtils.isNotNull(param.getStartCreateTime()), MsgPush::getCreateTime, param.getStartCreateTime())
.le(ObjectUtils.isNotNull(param.getEndCreateTime()), MsgPush::getCreateTime, param.getEndCreateTime())
.and(lqw -> lqw.eq(ObjectUtils.isNotNull(param.getId()), MsgPush::getId, param.getId())
.or().like(ObjectUtils.isNotEmpty(param.getMsgContent()), MsgPush::getMsgContent, param.getMsgContent()));
/* 以下为原QueryWrapper,需要使用字面量,且字面量需通过大量常量进行维护
QueryWrapper queryWrapper = Wrappers.query().eq("id", 1L).like("msg_content", "hello");
QueryWrapper queryWrapper = Wrappers.query()
.eq("id", 1L).or().like("msg_content", "hello")
.and(wrapper -> wrapper.ge("update_time", param.getStartUpdateTime()).le("update_time", param.getEndUpdateTime()))
.and(wrapper -> wrapper.ge("create_time", param.getStartCreateTime()).le("create_time", param.getEndCreateTime()));
*/
List<MsgPush> msgPushList = this.list(queryWrapper);
return RespResult.buildSuccessRows(msgPushList);
}
@Override
public RespResult<MsgPush> findMsgPushPage(FindMsgPushParam param) {
//设置分页及排序参数
Page page = this.convertPage(param);
//构建查询条件
Wrapper queryWrapper = this.buildListQueryMapper(param);
//执行分页查询
IPage<MsgPush> pageResult = this.page(page, queryWrapper);
//转换分页查询结果
return RespResult.buildSuccessRows(pageResult.getRecords(), pageResult.getTotal());
}
/**
* 转换mp分页参数
*
* @param pageBaseParam
* @return
*/
private Page convertPage(PageBaseParam pageBaseParam) {
Page page = new Page<>();
page.setCurrent(pageBaseParam.getPage());
page.setSize(pageBaseParam.getRows());
page.addOrder(CommonUtils.convertSortOrderItem(pageBaseParam));
return page;
}
/**
* 构建查询条件
*
* @param param
* @return
*/
private Wrapper buildListQueryMapper(FindMsgPushParam param) {
//id = #{id} and msg_content like concat('%', #{msgContent}, '%'))
//and create_time >= #{startCreateTime} and create_time <= #{endCreateTime}
return Wrappers.<MsgPush>lambdaQuery()
.eq(ObjectUtils.isNotNull(param.getId()), MsgPush::getId, param.getId())
.like(ObjectUtils.isNotEmpty(param.getMsgContent()), MsgPush::getMsgContent, param.getMsgContent())
.ge(ObjectUtils.isNotNull(param.getStartCreateTime()), MsgPush::getCreateTime, param.getStartCreateTime())
.le(ObjectUtils.isNotNull(param.getEndCreateTime()), MsgPush::getCreateTime, param.getEndCreateTime());
}
@Override
public RespResult updateMsgPush(MsgPush msgPush) {
//Boolean success = this.updateById(msgPush);
Boolean success = this.update(Wrappers.<MsgPush>lambdaUpdate()
//通过UpdateWrapper.set操作设置对应的set语句
.set(StringUtils.isNotBlank(msgPush.getMsgContent()), MsgPush::getMsgContent, msgPush.getMsgContent())
.set(ObjectUtils.isNotNull(msgPush.getPushType()), MsgPush::getPushType, msgPush.getPushType())
.set(ObjectUtils.isNotNull(msgPush.getPushResult()), MsgPush::getPushResult, msgPush.getPushResult())
.set(MsgPush::getUpdateTime, LocalDateTime.now())
//设置update where条件
.eq(MsgPush::getId, msgPush.getId()));
return RespResult.buildWith(success);
}
@Override
public RespResult getMsgPush(FindMsgPushParam param) {
//MsgPush msgPush = this.getById(msgPushParam.getId());
MsgPush msgPush = this.getOne(Wrappers.<MsgPush>lambdaQuery()
//通过select设置待查询的column列表
.select(MsgPush::getId, MsgPush::getMsgContent, MsgPush::getPushType, MsgPush::getPushResult)
//设置查询where条件
.eq(ObjectUtils.isNotNull(param.getId()), MsgPush::getId, param.getId()));
return RespResult.buildSuccessData(msgPush);
}
@Override
public RespResult deleteMsgPush(Long id) {
//根据ID删除记录
Boolean success = this.removeById(id);
//Boolean success = this.remove(Wrappers.<MsgPush>lambdaQuery());
return RespResult.buildWith(success);
}
/**
* 转换MsgPush对象
*
* @param msgPushParam
* @return
*/
private MsgPush convertMsgPush(MsgPushParam msgPushParam) {
//转换msgPush对象
MsgPush msgPush = new MsgPush();
msgPush.setPushType(msgPushParam.getPushType());
msgPush.setMsgContent(msgPushParam.getMsgContent());
msgPush.setPushResult(RespCodeEnum.SUCCESS.getCode());
msgPush.setCreateTime(LocalDateTime.now());
msgPush.setUpdateTime(LocalDateTime.now());
return msgPush;
}
/**
* 转换MsgTarget对象列表
*
* @param msgPush
* @param msgPushParam
* @return
*/
private List<MsgTarget> convertMsgTargetList(MsgPush msgPush, MsgPushParam msgPushParam) {
return msgPushParam.getTargetTopic().stream()
.map(targetTopic -> {
MsgTarget msgTarget = new MsgTarget();
msgTarget.setPushId(msgPush.getId());
msgTarget.setTargetTopic(targetTopic);
msgTarget.setPushResult(RespCodeEnum.SUCCESS.getCode());
msgTarget.setQos(msgPushParam.getQos());
msgTarget.setUpdateTime(LocalDateTime.now());
msgTarget.setCreateTime(LocalDateTime.now());
return msgTarget;
}).collect(Collectors.toList());
}
}