Mybatis-plugs
🍑 A mybatis tool that simplifys code
👉 https://gitee.com/wdyun/mybatis-plugs 👈
👉 mybatis-plugs 👈
📚简介
mybatis-plugs是基于mybatis开发的一款增强的持久层框架。
只需在springboot项目中引入依赖mybatis-plugs-spring-boot-starter
即可实现mybatis的CRUD简化操作,不用在书写基本的增删改查sql
🍺目的
mybatis-plugs为简化代码,提高效率而生!
🐮特性
- 不对mybatis做任何修改 只做mybatis的扩展增强。
- 代码自动生成,根据表名可快速生成xxxMapper.java、xxxService.java、xxxServiceImpl.java、xxxController.java、xxxMapper.xml。
- 依赖少,仅仅依赖 mybatis-plugs-spring-boot-starter
- 自动填充创建时间,更新时间,创建人等信息。
- 内置基于Mybatis物理分页的分页插件。
- 自动记录sql执行的时间,方便定位慢查询。
- 代码简洁,方便理解。
- 内置接口拦截器,通过注解确定是否拦截请求。
- 支持通过注解实现逻辑删除。
📦快速开始
我们将通过一个简单的 Demo 来阐述 MyBatis-Plugs 的强大功能,在此之前,我们假设您已经:
a.拥有 Java 开发环境、相应 IDE以及mysql数据库
b.熟悉 Spring Boot
c.熟悉 Maven
如果从零开始用 MyBatis-Plugs来实现该表的增删改查我们需要做什么呢?
👉 1.创建表
现有一张 sys_user 表,其对应的数据库 Sql 脚本如下:
CREATE TABLE sys_user (
id bigint NOT NULL COMMENT '主键ID',
name varchar(30) COMMENT '姓名',
age int COMMENT '年龄',
phone varchar(11) COMMENT '电话',
PRIMARY KEY (id)
)
👉 2.创建springboot项目
使用 idea 创建SpringBoot项目
第一步:
第二步:
第三步:选择LomBok插件
项目基本结构
👉 3.配置Maven
在项目的pom.xml文件中加入mybatis-plugs的Maven依赖:mybatis-plugs-spring-boot-starter
<dependency>
<groupId>com.enbatis</groupId>
<artifactId>mybatis-plugs-spring-boot-starter</artifactId>
<version>最新版本</version>
</dependency>
👉4.配置yml
修改 application.properties为application.yml
新增 开发环境: application-dev.yml
新增 测试环境: application-test.yml
新增 生产环境: application-pro.yml
小说明
1.开发环境为我们进行开发所使用的配置
2.测试环境为测试人员进行软件测试所使用的配置
3.生产环境为上线部署所使用的配置
application.yml中配置为:
spring:
profiles:
active: dev
server:
port: 8080
tips:
spring:
profiles:
active: dev
指定所使用的环境
server:
port: 8080
指定项目所启动的端口为8080端口
application-dev.yml内容如下:
mybatis:
mapper-locations: classpath:/mapping/*.xml
type-aliases-package: com.panpan.housesale.entity
configuration:
map-underscore-to-camel-case: true
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://127.0.0.1:3306/test_db?useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
username: root
password: 111111
driver-class-name: com.mysql.cj.jdbc.Driver
filters: stat,wall
initialSize: 5
minIdle: 5
maxActive: 20
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
#配置监控统计拦截的filters,stat:监控统计、log4j:日志记录、wall:防御sql注入
#如果允许时报错 java.lang.ClassNotFoundException: org.apache.log4j.Priority
#则导入 log4j 依赖即可,Maven 地址: https://mvnrepository.com/artifact/log4j/log4j
maxPoolPreparedStatementPerConnectionSize: 20
useGlobalDataSourceStat: true
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
👉5.修改启动类
在启动类上加上Mapper扫描的注解
@MapperScan("com.xxxxx.xxxxx.mapper")
🍊代码生成器
我们通过数据库表可以快速生成entity,controller,mapper,service,serviceImpl,mapping.xml
生成代码需要连接数据库,所以我们需要进行数据库的连接,只需要通过配置数据库基本信息,利用mybatis-plugs的代码生成类 CodeGenerator2 即可
👉1.配置代码生成器
在启动类的同级目录下,建立生成器类 CodeGenerate
public class CodeGenerate {
private static String url="jdbc:mysql://127.0.0.1:3306/test?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&useSSL=false";
private static String user="root";
private static String psd="111111";
private static String filePath="D://generate_code//";
public static void main(String[] args) {
CodeGenerator2 codeGenerator2=new CodeGenerator2(url,user,psd,filePath);
codeGenerator2.generate(CodeGenerate.class);
}
}
注释:
url: 数据库连接url
root: 数据库用户名
psd: 数据库密码
filePath: java代码生成位置(防止代码覆盖所以我们不会自动生成到对应的代码位置)
CodeGenerator2: mybatis-plugs代码核心生成器
👉2.使用方法
1.执行main方法
2.在控制台输入作者以及要生成代码的表
3.输入完成之后点击回车
4.当输出以下信息表示代码生成成功
5.去代码生成的位置查看生成的代码
👉3.建立代码包
建立代码包:entity、controller、mapper、service、impl以及xml的文件夹
👉4.复制代码
将生成的代码复制到对应的文件夹
👉5.启动项目
启动项目 访问 http://localhost:8080/v1/sys_user/list 查询所有用户列表
🐮CRUD 接口
说明:通过封装mybatis的 BaseService接口即可快速实现数据库的CRUD操作
泛型 T 为任意实体对象;参数 Serializable 为任意类型主键 Mybatis-Plugs 不推荐使用复合主键约定每一张表都有自己的唯一 id 主键;对象 Wrapper 为 条件构造器。
1.插入接口
1.1单条插入
/**
* 插入一条记录
* @param entity 传入的插入对象
* @return T
*/
T insert(T entity);
使用方法:在serviceImpl层写代码示例如下
SysUser user = new SysUser();
user.setName("张三");
user.setAge(32);
user.setPhone("13615425135");
super.insert(user);
1.2批量插入
/**
* 批量插入
* @param entityList
* @return
*/
int saveBatch(List<T> entityList);
使用方法:在serviceImpl层写代码示例如下
List<SysUser> sysUserList = new ArrayList<>();
for (int i = 0; i <10 ; i++) {
SysUser sysUser = new SysUser();
sysUser.setName("张三"+i);
sysUser.setAge(30+i);
sysUser.setPhone("1361542513"+i);
sysUserList.add(sysUser);
}
super.saveBatch(sysUserList);
2.删除接口
2.1单个删除
/**
* 根据id删除一条数据
* @param id 传入的查询ID
* @return 删除条数
*/
int deleteById(Serializable id);
使用方式:在serviceImpl层写代码示例如下
super.deleteById(12000012);
2.2批量删除
/**
* 批量删除
* @param wrapper
* @return
*/
int delete(Wrapper<T> wrapper);
使用方式:在serviceImpl层写代码示例如下
Wrapper wrapper = new Wrapper<SysUser>();
wrapper.eq("age",30);
wrapper.like("name","张三");
super.delete(wrapper);
说明:关于条件构造器会专门讲解。
3 修改接口
3.1单个修改
/**
* 根据id更新一条数据
* @param bean 传入的更新对象
* @return 返回更新条数
*/
int updateById(T bean);
使用方式:在serviceImpl层写代码示例如下
SysUser sysUser = new SysUser();
sysUser.setId(1234561114L);
sysUser.setPhone("13615425135");
sysUser.setAge(36);
super.updateById(sysUser);
3.2批量修改
/**
* 批量修改
* @param entityList
* @return
*/
int updateBatchById(List<T> entityList);
使用方式:在serviceImpl层写代码示例如下
List<SysUser> sysUserList = new ArrayList<>();
SysUser sysUser = new SysUser();
sysUser.setId(111100001101L);
sysUser.setAge(35);
sysUserList.add(sysUser);
SysUser sysUser2 = new SysUser();
sysUser2.setId(111100001102L);
sysUser2.setAge(32);
sysUserList.add(sysUser);
super.updateBatchById(sysUserList);
4.列表查询接口
/**
* 查询列表数据
* @param wrapper 查询条件
* @return 集合
*/
List<T> list(Wrapper<T> wrapper);
使用方式:在serviceImpl层写代码示例如下
Wrapper wrapper = new Wrapper<SysUser>();
wrapper.like("name","张三");
List<SysUser> list = super.list(wrapper);
5.分页查询
/**
* 分页查询
* @param page
* @param wrapper
* @return
*/
Page<T> page(Page<T> page, Wrapper<T> wrapper);
使用方式:在controller层写代码示例如下
@PostMapping("/page")
public ResultReturn<Page<SysUser>> getPage(@RequestBody SysUser user){
return success(sysUserService.page( getPage(),new Wrapper(user)));
}
说明:controller需要继承BaseController
6查询单条
/**
* 根据id获取
* @param id 对象ID
* @return 对象
*/
T getById(Serializable id);
使用方式:在controller层写代码示例如下
@GetMapping("/{id}")
public ResultReturn<SysUser> get(@PathVariable("id") Long id) {
return success(sysUserService.getById(id));
}
7.查询数量
/**
* 查询count
* @param wrapper 查询条件
* @return 数量
*/
int selectCount(Wrapper<T> wrapper);
使用方式:在serviceImpl层写代码示例如下
Wrapper wrapper = new Wrapper<SysUser>();
wrapper.like("name","张三");
int count = super.selectCount(wrapper);
🐮 条件构造器Wrapper
1 eq构造
如果我们想快速查询数据库表sys_user 的姓名为 “Tom” 如何进行操作呢?
回答:只需service调用list 传入 条件构造器Wrapper Wrapper调用 eq 方法,下面的方法即为 查询姓名是Tom的SysUser列表
sysUserService.list(new Wrapper<>(sysUser).eq("name","Tom"));
2 ne构造
如果我们想快速查询数据库表sys_user 的姓名不是 “Tom” 如何进行操作呢?
回答:只需service调用list 传入 条件构造器Wrapper Wrapper调用 ne 方法,下面的方法即为 查询姓名不是Tom的SysUser列表
sysUserService.list(new Wrapper<>(sysUser).ne("name","Tom"));
3 like构造
如果我们想根据姓名模糊查询,怎么操作呢?
回答:只需service调用list 传入 条件构造器Wrapper Wrapper调用 like 方法,下面的方法即为 根据姓名“Tom”模糊查询
sysUserService.list(new Wrapper<>(sysUser).like("name","Tom"));
4 in构造
如果我们想查询姓名是“Tom”,“Jack”,“June”怎么操作呢?
回答:只需service调用list 传入 条件构造器Wrapper Wrapper调用 in 方法,传入ArrayList即可
List arrayList=new ArrayList<>();
arrayList.add("Tom");
arrayList.add("Jack");
arrayList.add("June");
sysUserService.list(new Wrapper<>(sysUser).in("name",arrayList));
扩展:
以上只列出部分条件构造器的方法,我们还有notNull(非空查询)、isNull(空值查询)、setSqlSelect(固定列查询)等等, 更多请查看 mybatis-plugs
🐮 登录认证
Mybatis-Plugs内部封装了JWT token认证,做登录功能时可直接进行使用。
1.创建JWT
Mybatis-Plugs提供了JwtUtil工具类来进行token的创建,具体的方法来介绍下:
/**
* 前三个参数为自己用户token的一些信息比如id,权限,名称等。不要将隐私信息放入(大家都可以获取到)
* @param map 需要加密的信息
* @param security 加密字符串
* @param expire 失效时间 毫秒
* @return
*/
public static String createJwt(Map<String,Object> map,String security,long expire) {
//添加构成JWT的参数
JwtBuilder builder = Jwts.builder()
.setHeaderParam("typ", "JWT")
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis()+expire))
.setClaims(map)
.signWith(generalKey(security),SignatureAlgorithm.HS256);
//生成JWT
return builder.compact();
}
如果不传失效时间会默认24小时,我们提供了一个重载的方法
/**
* 创建JWT 默认失效时间是24小时
* @param map 需要加密的信息
* @param base64Security 加密字符串
* @return
*/
public static String createJwt(Map<String, Object> map, String base64Security) {
return createJwt(map,base64Security,EXPIRE);
}
具体如何使用?请参照一下代码:
//获取登录用户名
String username =user.getUsername();
String password= MD5Util.generate(user.getPassword());
List<SysUser> list=list(new Wrapper().eq("username",username).eq("password",password));
Optional<SysUser> first= list.stream().filter(dbUser->dbUser.getUsername().equals(username)&&dbUser.getPassword().equals(password)).findFirst();
if (first.isPresent()){
user.setUsername(username);
SysUser sysUser= first.get();
Map<String,Object> userMap = new HashMap<>();
userMap.put("userId",sysUser.getId()+"");
userMap.put("name",sysUser.getName());
userMap.put("companyId",sysUser.getCompanyId());
userMap.put("username",sysUser.getUsername());
userMap.put("effective", System.currentTimeMillis()+(120*60*1000));
String token= JwtUtil.createJwt(userMap, JwtUtil.LOGIN_BASE);
response.addHeader("authorization",token);
Cookie cookie = new Cookie("authorization",token);
cookie.setDomain(domain);
cookie.setPath("/");
response.addCookie(cookie);
SysUser user1= first.get();
SysUserVO vo = new SysUserVO();
BeanUtils.copyProperties(user1,vo);
vo.setAuthorization(token);
vo.setImgHead(sysUser.getAvatarUrl());
return ResultReturn.success(vo);
}
2.解析JWT
Mybatis-Plugs提供了JwtUtil工具类来进行token的解析,具体的方法来介绍下:
/**
* 解密
* @param jsonWebToken token字符串
* @param security 加密字符串
* @return
*/
public static Claims parseJwt(String jsonWebToken, String security) {
try {
Jws<Claims> claimsJws = Jwts.parserBuilder()
.setSigningKey(Keys.hmacShaKeyFor(security.getBytes(StandardCharsets.UTF_8)))
.build().parseClaimsJws(jsonWebToken);
return claimsJws.getBody();
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
}
3.封装登录实体
登录成功之后,可以用token获取到登录实体Account,用来获取登录用户,具体方法如下:
public static Account account(String token,String security){
Claims claims= JwtUtil.parseJwt(token,security);
String userId= (String)claims.get("userId");
String username= (String)claims.get("username");
Integer companyId= (Integer)claims.get("companyId");
Account account = new Account();
account.setId(Long.parseLong(userId));
account.setUsername(username);
if(null!=companyId){
account.setCompanyId(Long.parseLong(Integer.toString(companyId)));
}
return account;
}
其中token是jwt生成的token,security为加密字符串,token可以从head或者cookie里面获取。
具体的使用方式见如下代码:
Account account = JwtUtil.account(request.getHeader("Authorization"),"xxxx");
🐮 拦截器
1.介绍
Mybatis-plugs的拦截器有记录请求方法执行时间、过滤非登录用户请求的功能,在controller里面使用注解即可拦截未登录请求。
使用方法:自定义拦截器并继承类:com.enbatis.mybatisplugs.commons.Interceptor.Interceptor
实例代码如下:
@Component
public class ReqInterceptor extends Interceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception{
return super.preHandle(request,response,handler);
}
}
接下来是注册拦截器,新建类WebConfigurer 并实现WebMvcConfigurer接口,代码如下:
@Configuration
public class WebConfigurer implements WebMvcConfigurer {
@Autowired
private ReqInterceptor interceptor;
/**
* @Description 这个方法是用来配置静态资源的,比如html,js,css,等等
* @Param [registry]
* @return void
**/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
}
/**
* @Description 这个方法用来注册拦截器,我们自己写好的拦截器需要通过这里添加注册才能生效
* @Date 9:34 2022/2/7
* @Param [registry]
* @return void
**/
@Override
public void addInterceptors(InterceptorRegistry registry) {
// addPathPatterns("/**") 表示拦截所有的请求,
registry.addInterceptor(interceptor).addPathPatterns("/**");
}
}
配置完成即可实现Mybatis-Plugs拦截器的功能。
2.拦截请求
Controller方法不加任何注解或者加注解 @Login(handler = Handler.INTERCEPT)即可起到拦截请求的功能,如果用户未登录就访问接口,系统会抛出未登录的信息。
3.放行请求
有一部分请求是不需要登录就直接能访问的,比如说注册接口,登录接口等等,这时候使用注解@Login(handler = Handler.PASS)即可放行请求,即不需要登录即可访问,代码示例如下:
注册接口:
@Login(handler = Handler.PASS)
@PostMapping("/register")
public ResultReturn registerUser(@RequestBody SysUserVO sysUser){
sysUser.setCompanyId(0L);
return sysUserService.registerUser(sysUser);
}
登录接口:
@Login(handler = Handler.PASS)
@PostMapping("/login")
public ResultReturn login(@RequestBody SysUserVO vo){
return sysUserService.login(vo,request,response);
}
🐮 枚举转换
有时候数据库里面存的是数字类型,但是在实体类里面我们要使用枚举类,这种情况Mybatils-Plugs提供了比较方便快捷的方式来实现需求。
1.定义枚举类
先自定义枚举类并实现com.enbatis.mybatisplugs.enums.BaseEnum接口,代码如下:
import com.enbatis.mybatisplugs.enums.BaseEnum;
public enum StatusEnum implements BaseEnum<StatusEnum,Integer> {
ORDERED(0,"已下单"),
PAYED(1,"已付款"),
DELIVER(2,"代发货"),
DELIVERED(3,"已发货"),
RECEIVED(4,"已收货"),
OK(5,"订单完成");
private final Integer value;
private final String description;
StatusEnum(Integer value, String description) {
this.value = value;
this.description = description;
}
public StatusEnum getEnumByValue(Long value) {
StatusEnum[] enums = StatusEnum.values();
for (StatusEnum e : enums) {
if (e.getValue().equals(value)) {
return e;
}
}
return null;
}
@Override
public Integer getValue() {
return value;
}
@Override
public String getDescription() {
return description;
}
}
2.实体类引用枚举
需要在实体类里面将字段更改为枚举类型,如下:
/**
* 订单状态(
*/
private StatusEnum status;
3.增加配置文件
需要在配置文件里面添加对枚举转换的类:com.enbatis.mybatisplugs.plugin.parser
.AutoEnumTypeHandler
代码如下:
mybatis:
mapper-locations: classpath:/mapping/*.xml
type-aliases-package: com.panpan.housesale.entity
configuration:
map-underscore-to-camel-case: true
#log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
default-enum-type-handler: com.enbatis.mybatisplugs.plugin.parser.AutoEnumTypeHandler
通过这三个步骤的操作,就可以实现,数据库字段类型与枚举类型的匹配。