前言:?本博客主要是记录自己学习的过程,方便日后查看,当然也希望能够帮到大家。?
一, 说明:
SpringBoot 2.7.0 整合MyBatis-Plus 3.5.2详细教程,并整合Alibaba Druid数据源,使用MySQL(版本5.7)数据库,使用hutool开源工具.
1.MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。官网地址:戳我学习MyBatis-Plus
2.Druid由阿里团队研发,后捐赠给Apache基金会,Druid是一个高效的数据查询系统,主要解决的是对于大量的基于时序的数据进行聚合查询。数据可以实时摄入,进入到Druid后立即可查,同时数据是几乎是不可变。通常是基于时序的事实事件,事实发生后进入Druid,外部系统就可以对该事实进行查询。官网地址:戳我学习Druid
3.Hutool是国内程序员在工作中总结和积累而成的一套小而全的工具类库,相比于Guava,它更符合国内开发者的需求。Hutool首次发布于2014年,最新版本为5.6.5,到目前为止已经在github上收获了1.9万个赞。官网地址:戳我学习Hutool
二, 项目开始:
1.搭建项目
为方便编写后续整合项目,直接搭建微服务式目录结构,新建父Maven项目如下图:

如上图目录结构说明:
Spring Boot-demo
├── common-demo-- 工具类及通用代码模块
├── mybatisplus-demo -- 整合MyBatisPlus模块
├── sms-demo -- 整合阿里云短信模块(后续更新)
└── other-- 整合其他模块(后续更新)
1.引入相关依赖:
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.7.0</spring-boot.version>
<fastjson.version>1.2.73</fastjson.version>
<druid.version>1.2.11</druid.version>
<mybatisPlus.version>3.5.2</mybatisPlus.version>
<mysql.version>5.1.47</mysql.version>
<pagehelper.version>1.4.2</pagehelper.version>
<validation.version>2.7.0</validation.version>
<hutool.version>5.4.1</hutool.version>
<lang3.version>3.12.0</lang3.version>
</properties>
<dependencyManagement>
<dependencies>
<!--spring boot-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--fastjson-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<!--druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>${druid.version}</version>
</dependency>
<!--mybatisPlus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatisPlus.version}</version>
</dependency>
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<!--validation-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<version>${validation.version}</version>
</dependency>
<!--hutool-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>${hutool.version}</version>
</dependency>
<!--lang3-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${lang3.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
注:包含基础依赖,直接引入项目即可,后续继续增加其他依赖。
2.Cmmon-demo-- 工具类及通用代码模块介绍
Cmmon目录结构如下图:

Cmmon-demo
├── enums-- 枚举类包
├── page -- 分页对象类包
├── response -- 响应类包
└── other-- 其他包(后续更新)
引入相关依赖:
dependencies>
<!--validation-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<!--lang3-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<!--hutool-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
</dependency>
<!--mybatisPlus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
</dependencies>
enums枚举类:
package com.wisesliu.enums;
import java.util.HashMap;
import java.util.Map;
/**
* @author jixia
* @date 2022/6/16 20:26
* @description 全局异常枚举
*/
public enum GlobalErrorCode {
SUCCESS(200, "操作成功"),
FAIL(-2, "操作失败"),
UNKNOWN(-1, "未知的错误"),
;
private int errorCode;
private String errorMsg;
private static final Map<Integer, GlobalErrorCode> errorCodes = new HashMap<>();
static {
for (GlobalErrorCode errorCode : GlobalErrorCode.values()) {
errorCodes.put(errorCode.getErrorCode(), errorCode);
}
}
GlobalErrorCode(int errorCode, String errorMsg) {
this.errorCode = errorCode;
this.errorMsg = errorMsg;
}
public static GlobalErrorCode valueOf(int code) {
GlobalErrorCode globalErrorCode = errorCodes.get(code);
if (globalErrorCode != null) {
return globalErrorCode;
}
return UNKNOWN;
}
public int getErrorCode() {
return errorCode;
}
public String getErrorMsg() {
return errorMsg;
}
}
page分页类对象:
(1)前端请求分页类:
/**
* @author jixia
* @date 2022/6/16 20:48
* @description 前端传参分页对象
*/
public class FrontPage<T> {
/**
* 每页显示条数
*/
@NotNull(message = "每页显示条数不能为空")
private Integer size;
/**
* 当前页数
*/
@NotNull(message = "当前页数不能为空")
private Integer current;
/**
* 排序的字段,多个逗号分割
*/
private String order;
/**
* 排序方式 true 升序 false 降序
*/
private Boolean asc;
public Integer getSize() {
return size;
}
public void setSize(Integer size) {
this.size = size;
}
public Integer getCurrent() {
return current;
}
public void setCurrent(Integer current) {
this.current = current;
}
public String getOrder() {
return order;
}
public void setOrder(String order) {
this.order = order;
}
public Boolean getAsc() {
return asc;
}
public void setAsc(Boolean asc) {
this.asc = asc;
}
/**
* 构造mybatisPlus封装的Page对象
*
* @return
*/
public Page<T> getPage() {
Page<T> page = new Page<>();
page.setCurrent(this.current);
page.setSize(this.size);
// 多排序字段处理
if (StringUtils.isNotBlank(this.order)) {
List<OrderItem> orders = new ArrayList<>();
List<String> orderList = ListUtil.toList(this.order.split(","));
for (String str : orderList) {
OrderItem orderItem = new OrderItem();
orderItem.setColumn(str);
orderItem.setAsc(Objects.nonNull(this.asc) ? this.asc : false);
orders.add(orderItem);
}
page.setOrders(orders);
}
return page;
}
}
(2)后端相应分页类:
/**
* @author jixia
* @date 2022/6/16 20:29
* @description 后端响应分页对象
*/
public class CustomPage<T> {
/**
* 当前页数
*/
private Long current;
/**
* 每页显示数量
*/
private Long size;
/**
* 总页数
*/
private Long total;
/**
* 总条数
*/
private Long records;
/**
* 数据列表
*/
private List<T> rows;
public Long getCurrent() {
return current;
}
public void setCurrent(Long current) {
this.current = current;
}
public Long getSize() {
return size;
}
public void setSize(Long size) {
this.size = size;
}
public Long getRecords() {
return records;
}
public void setRecords(Long records) {
this.records = records;
}
public List<T> getRows() {
return rows;
}
public void setRows(List<T> rows) {
this.rows = rows;
}
public Long getTotal() {
return total;
}
public void setTotal(Long total) {
this.total = total;
}
public CustomPage(Page<T> page) {
this.current = page.getCurrent();
this.size = page.getSize();
this.records = page.getTotal();
this.rows = page.getRecords();
this.total = page.getPages();
}
}
response后端响应类对象:
(1)基础响应类对象:
/**
* @author jixia
* @date 2022/6/16 20:24
* @description 接口响应基础类
*/
public class BaseResponse {
private Integer status = 200;
private String message;
public BaseResponse() {
}
public BaseResponse(Integer status, String message) {
this.status = status;
this.message = message;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public static BaseResponse success(String moreInfo) {
int status = GlobalErrorCode.SUCCESS.getErrorCode();
return new BaseResponse(status, moreInfo);
}
public static BaseResponse success() {
int status = GlobalErrorCode.SUCCESS.getErrorCode();
String msg = GlobalErrorCode.SUCCESS.getErrorMsg();
return new BaseResponse(status, msg);
}
public static BaseResponse error(GlobalErrorCode errorCode, String moreInfo) {
int status = errorCode.getErrorCode();
return new BaseResponse(status, moreInfo);
}
public static BaseResponse error(GlobalErrorCode errorCode) {
int status = errorCode.getErrorCode();
String msg = errorCode.getErrorMsg();
return new BaseResponse(status, msg);
}
public static BaseResponse error(String moreInfo) {
int status = GlobalErrorCode.FAIL.getErrorCode();
return new BaseResponse(status,moreInfo);
}
}
(1)返回响应类对象:
/**
* @author jixia
* @date 2022/6/16 20:32
* @description 接口响应类
*/
public class ObjectRestResponse<T> extends BaseResponse {
T data;
private ObjectRestResponse() {
}
private ObjectRestResponse(int status, String msg, T data) {
super(status, msg);
this.data = data;
}
private ObjectRestResponse(int status, String msg) {
super(status, msg);
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public static <T> ObjectRestResponse success(String moreInfo, T data) {
int status = GlobalErrorCode.SUCCESS.getErrorCode();
return new ObjectRestResponse<>(status, moreInfo, data);
}
public static <T> ObjectRestResponse success(T data) {
int status = GlobalErrorCode.SUCCESS.getErrorCode();
String msg = GlobalErrorCode.SUCCESS.getErrorMsg();
return new ObjectRestResponse<>(status, msg, data);
}
public static <T> ObjectRestResponse error(GlobalErrorCode errorCode, String moreInfo, T data) {
int status = errorCode.getErrorCode();
return new ObjectRestResponse<>(status, moreInfo, data);
}
public static <T> ObjectRestResponse error(GlobalErrorCode errorCode, T data) {
int status = errorCode.getErrorCode();
String msg = errorCode.getErrorMsg();
return new ObjectRestResponse<>(status, msg, data);
}
}
3.mybatisplus-demo模块
mybatisplus目录结构如下图:

mybatisplus-demo
├── config-- 配置类类包
├── entity--实体类包
├── mapper-- 数据操作接口类包
├── service-- 数据操作实现接口类包
├── controller-- 端点接口类包
└── -- 其他包(后续更新)
引入相关依赖:
<dependencies>
<!--web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--test-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--fastjson-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
<!--druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
</dependency>
<!--mybatisPlus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!---->
<dependency>
<artifactId>common-demo</artifactId>
<groupId>com.wisesliu</groupId>
<version>1.0.0</version>
</dependency>
</dependencies>
详细配置文件:application.yml
server:
port: 8001
spring:
application:
name: mybatisPlus-demo-server
#配置数据源
datasource:
username: root
password: 123456
url: jdbc:mysql://127.0.0.1:3306/test?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=false
driver-class-name: com.mysql.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
# 连接池的配置信息
druid:
# 初始化大小,最小,最大
initial-size: 5
min-idle: 5
maxActive: 20
# 配置获取连接等待超时的时间
maxWait: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
timeBetweenEvictionRunsMillis: 60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
# 打开PSCache,并且指定每个连接上PSCache的大小
poolPreparedStatements: true
maxPoolPreparedStatementPerConnectionSize: 20
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
filters: stat
# 通过connectProperties属性来打开mergeSql功能;慢SQL记录
connectionProperties: druid.stat.mergeSql\=true;druid.stat.slowSqlMillis\=5000
# 配置DruidStatFilter
web-stat-filter:
enabled: true
url-pattern: "/*"
exclusions: "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*"
# 配置DruidStatViewServlet
stat-view-servlet:
enabled: true
url-pattern: "/druid/*"
# IP白名单(没有配置或者为空,则允许所有访问)
allow: 127.0.0.1
# IP黑名单 (存在共同时,deny优先于allow)
deny: 192.168.1.73
# 禁用HTML页面上的“Reset All”功能
reset-enable: false
# 登录名
login-username: druid
# 登录密码
login-password: druid
mybatis-plus:
#外部化xml配置
#config-location: classpath:mybatis-config.xml
#指定外部化 MyBatis Properties 配置,通过该配置可以抽离配置,实现不同环境的配置部署
#configuration-properties: classpath:mybatis/config.properties
#xml扫描,多个目录用逗号或者分号分隔(告诉 Mapper 所对应的 XML 文件位置)
#MyBaits 别名包扫描路径,通过该属性可以给包中的类注册别名
#type-aliases-package:
#如果配置了该属性,则仅仅会扫描路径下以该类作为父类的域对象
#type-aliases-super-type: java.lang.Object
#枚举类 扫描路径,如果配置了该属性,会将路径下的枚举类进行注入,让实体类字段能够简单快捷的使用枚举属性
#type-enums-package: com.baomidou.mybatisplus.samples.quickstart.enums
#项目启动会检查xml配置存在(只在开发时候打开)
check-config-location: true
configuration:
# 是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN(下划线命名) 到经典 Java 属性名 aColumn(驼峰命名) 的类似映射
map-underscore-to-camel-case: false
# 全局地开启或关闭配置文件中的所有映射器已经配置的任何缓存,默认为 true
cache-enabled: false
#懒加载
#aggressive-lazy-loading: true
#NONE:不启用自动映射 PARTIAL:只对非嵌套的 resultMap 进行自动映射 FULL:对所有的 resultMap 都进行自动映射
#auto-mapping-behavior: partial
#NONE:不做任何处理 (默认值)WARNING:以日志的形式打印相关警告信息 FAILING:当作映射失败处理,并抛出异常和详细信息
#auto-mapping-unknown-column-behavior: none
#如果查询结果中包含空值的列,则 MyBatis 在映射的时候,不会映射这个字段
call-setters-on-nulls: true
# 这个配置会将执行的sql打印出来,在开发或测试的时候可以用
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
db-config:
#表名下划线命名默认true
table-underline: true
#id类型
id-type: auto
#是否开启大写命名,默认不开启
#capital-mode: false
#逻辑已删除值,(逻辑删除下有效) 需要注入逻辑策略LogicSqlInjector 以@Bean方式注入
logic-not-delete-value: 0
#逻辑未删除值,(逻辑删除下有效)
logic-delete-value: 1
mapper-locations: classpath*:/mapper/*.xml
数据表t_user
CREATE TABLE `t_user` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '用户id',
`username` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`password` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`fullname` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '用户姓名',
`mobile` varchar(11) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '手机号',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = DYNAMIC;
config
/**
* @author jixia
* @date 2022/6/16 20:22
* @description 分页插件配置
*/
@Configuration
public class MyBatisPlusConfig {
/**
* 分页插件
* @return
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
注:分页配置类,必须实现,详细查看官方文档:戳我学习MyBatis-Plus
entity

entity
├── form-- 表单提交类
├── param--请求参数类
└── -- 对象类
form类
/**
* @author jixia
* @date 2022/6/16 20:43
* @description 用户提交对象
*/
@Data
public class UserForm implements Serializable {
/**
* 用户名
*/
@NotBlank
private String username;
/**
* 密码
*/
private String password;
/**
* 真实名
*/
@NotBlank
private String fullname;
/**
* 手机号
*/
@NotBlank
private String mobile;
private static final long serialVersionUID = -8978461117607917157L;
}
param类
/**
* @author jixia
* @date 2022/6/16 20:47
* @description 用户查询参数
*/
@Data
public class UserParam implements Serializable {
/**
* 用户名
*/
private String username;
/**
* 真实名
*/
private String fullname;
/**
* 手机号
*/
private String mobile;
}
user类
/**
* @author jixia
* @date 2022/6/16 20:54
* @description 系统用户
*/
@Data
@TableName("t_user")
public class User implements Serializable {
/**
* ID
*/
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/**
* 用户名
*/
@TableField("username")
private String username;
/**
* 密码
*/
@TableField("password")
private String password;
/**
* 真实名
*/
@TableField("fullname")
private String fullname;
/**
* 手机号
*/
@TableField("mobile")
private String mobile;
private static final long serialVersionUID = 4791568101260386736L;
}
mapper
/**
* @author jixia
* @date 2022/6/16 20:46
* @description
*/
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
service
/**
* @author jixia
* @date 2022/6/16 20:47
* @description
*/
public interface UserService extends IService<User> {
}
serviceImpl
/**
* @author jixia
* @date 2022/6/16 20:47
* @description
*/
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}
controller
/**
* @author jixia
* @date 2022/6/16 20:48
* @description
*/
@RestController
@RequestMapping("/user")
public class UserController {
@Resource
private UserService userService;
/**
* 分页查询用户
*
* @param page
* @param param
* @return
*/
@GetMapping("/page")
public ObjectRestResponse<CustomPage<User>> page(@Valid FrontPage<User> page, UserParam param) {
QueryWrapper<User> wrapper = new QueryWrapper<>();
if (StringUtils.isNotBlank(param.getUsername())) {
wrapper.lambda().like(User::getUsername, param.getUsername());
}
if (StringUtils.isNotBlank(param.getFullname())) {
wrapper.lambda().like(User::getFullname, param.getFullname());
}
if (StringUtils.isNotBlank(param.getMobile())) {
wrapper.lambda().like(User::getMobile, param.getMobile());
}
Page<User> pageList = userService.page(page.getPage(), wrapper);
return ObjectRestResponse.success(new CustomPage<>(pageList));
}
/**
* 添加用户
*
* @param form
* @return
*/
@GetMapping("add")
public ObjectRestResponse add(UserForm form) {
User user = new User();
BeanUtils.copyProperties(form, user);
user.setPassword(StringUtils.isNotBlank(user.getPassword()) ? user.getPassword() : IdUtil.simpleUUID());
userService.save(user);
return ObjectRestResponse.success("操作成功", null);
}
}
启动类
**
* @author jixia
* @date 2022/6/16 20:15
* @description
*/
@SpringBootApplication
public class MybatisPlusApplication {
public static void main(String[] args) {
SpringApplication.run(MybatisPlusApplication.class, args);
}
}
3.Druid效果:
1.Druid访问地址:
http://127.0.0.1:8001/druid/login.html
登录效果:

SQL执行监控效果:

4.查询效果:
请求地址:
http://127.0.0.1:8001/user/page?current=1&size=10
请求方式::
GET
参数::
current:当前页
size:分页数量
完整代码地址:正在搭建中,后续公布。
注:此工程包含多个module,本文所用代码均在mybatisplus-demo模块下
后记:?本次分享到此结束,本博主水平有限,难免有错误或遗漏之处,望大家指正和谅解,欢迎评论留言。?