现在很多项目都用 mybaits 来做,这里不讨论 hibernate 与 mybaits 的谁好用的问题,因地制宜去做,今天我们来聊一下一个国产的框架 Mybatis-Plus。
以前小编经常用 mybatis 来做开发,然后自己再写一个单表的自动化生成工作,虽然也是很简便,但是代码还是挺多,后面用 TK,到现在用 MP,都是挺好的东西,重复造轮子的活小编是不干的,没必要。
今天咱们就来讲一下 Mybatis-Plus 3.4.0 版本如何使用多租户及自动新增创建人,创建时间等。在开始之前,针对前后端分离的架构来说,先说说小编是怎么设计的。
1:系统登陆,获取基础的用户信息并把租户 ID(tenant),用户 ID(userId),用户名称(userName)放到一个地方去,如 localstorage 等,具体你自己定义。
2:每次访问后端服务的从缓存的地方获取这些信息,并放到 Header 里面,要注意一点,由于 Header 不能存放中文,此时你需要对中文进行 URL 编码。
3:后端每次进行操作的时候,根据需要从 Header 里面获取信息进行属性填充或者租户的判断。
基础包引用
目前 mybaits-plus 的最新版已经达到了 3.4.0,今天我们就用最新版来操作
<!-- mybatisplus配置 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.0</version>
</dependency>
复制代码
多租户判断
多租户的判断的原理说起来非常简单,就是基于 mybatis 的拦截器来操作,在进行新增,修改,删除的时候,从某一个固定的地方获取租户 ID,并插入到指定的 SQL 里面去。在 Mybatis-Plus 里面用的是分页拦截器进行填充,参考一下我这边的写法,并且已经标注注意的事项。
备注:在进行插件的增加的时候,一定要注意如果分页插件与多租户插件同时应用,一定要先写多租户拦截器。
/**
* 添加分页插件支持
* @author 互联网应用架构
* @return PaginationInterceptor
*/
@Bean
public MybatisPlusInterceptor paginationInterceptor() {
final MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 新增多租户拦截器
interceptor.addInnerInterceptor(new TenantLineInnerInterceptor(new TenantLineHandler() {
/**
* 获取租户ID
* @author 林溪
* @return 租户ID
*/
@Override
public Expression getTenantId() {
return new LongValue(HeaderUtils.getTenantId());
}
/**
* 判断哪些表不需要尽心多租户判断,返回false表示都需要进行多租户判断
* @author 林溪
* @param tableName
* @return
*/
@Override
public boolean ignoreTable(String tableName) {
return false;
}
}));
// 新增MYSQL分页拦截器
// 一定要先设置租户判断后才进行分页拦截设置
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
复制代码
这样就完成了一个分页插件及多租户的插件的新增,有时候有些表不需要进行多租户的判断的时候,自己在 ignoreTable 这个方法里面新增判断即可。
自动填充数据
自动填充数据来源于小编的表中有创建人 ID,创建人姓名,创建时间,更新人 ID,更新人姓名,更新时间,删除状态,先给大伙看看我的这些字段。
// 创建人id
@TableField(value = "created_id", fill = FieldFill.INSERT)
private Long createdId;
// 创建人名称
@TableField(value = "created_name", fill = FieldFill.INSERT)
private String createdName;
// 创建时间
@TableField(value = "created_date", fill = FieldFill.INSERT)
private Date createdDate;
// 更新人id
@TableField(value = "updated_id", fill = FieldFill.UPDATE)
private Long updatedId;
// 更新人名称
@TableField(value = "updated_name", fill = FieldFill.UPDATE)
private String updatedName;
// 更新时间
@TableField(value = "updated_date", fill = FieldFill.UPDATE)
private Date updatedDate;
// 0:未删除;1已删除
@TableField(value = "deleted_status", fill = FieldFill.INSERT)
private int deletedStatus;
复制代码
这些字段在新增或者更新的时候,如果每次都要去手动操作,那就比较繁琐,写起来太辛苦了,Mybatis-Plus 目前提供了一个解决方案给我们,一个字段填充的接口 MetaObjectHandler,我们只需要新建一个类来继承这个接口,并处理即可。
/**
* All rights Reserved, Designed By 林溪
* Copyright: Copyright(C) 2016-2020
* Company 林溪开源
*/
package com.modules.boots.mp.mysql;
import java.util.Date;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.bases.common.constant.BaseConstant;
import com.bases.common.utils.HeaderUtils;
import lombok.extern.slf4j.Slf4j;
/**
* 字段自动填充
* @author:林溪
* @date:2020年9月9日
*/
@Slf4j
@Component
public class FiledsFillingHandler implements MetaObjectHandler {
/**
* 新增数据的时候,自动进行数据填充
* @author 林溪
* @param metaObject
* @return
*/
@Override
public void insertFill(MetaObject metaObject) {
log.info("开始进行新增字段数据填充");
final Object createdId = getFieldValByName("createdId", metaObject);
final Object createdName = getFieldValByName("createdName", metaObject);
final Object createdDate = getFieldValByName("createdDate", metaObject);
final Object deletedStatus = getFieldValByName("deletedStatus", metaObject);
if (createdId == null) {
this.setFieldValByName("createdId", HeaderUtils.getUserId(), metaObject);
}
if (createdName == null) {
this.setFieldValByName("createdName", HeaderUtils.getUserName(), metaObject);
}
if (createdDate == null) {
this.setFieldValByName("createdDate", new Date(), metaObject);
}
if (deletedStatus == null) {
this.setFieldValByName("deletedStatus", BaseConstant.UNDELETE, metaObject);
}
}
/**
* 更新数据的时候,自动进行数据填充
* @author 林溪
* @param metaObject
* @return
*/
@Override
public void updateFill(MetaObject metaObject) {
log.info("开始进行更新字段数据填充");
final Object updatedId = getFieldValByName("updatedId", metaObject);
final Object updatedName = getFieldValByName("updatedName", metaObject);
final Object updatedDate = getFieldValByName("updatedDate", metaObject);
if (updatedId == null) {
this.setFieldValByName("updatedId", HeaderUtils.getUserId(), metaObject);
}
if (updatedName == null) {
this.setFieldValByName("updatedName", HeaderUtils.getUserName(), metaObject);
}
if (updatedDate == null) {
this.setFieldValByName("updatedDate", new Date(), metaObject);
}
}
}
复制代码
这里有一点可能要注意一下,就是针对实体类中那些需要进行新增或者更新的字段,需要手动加入一个注解,这样就可以实现在新增或者更新的时候,进行数据的自动填充了
// 新增的时候进行填充
fill = FieldFill.INSERT
// 更新的时候进行填充
fill = FieldFill.UPDATE
// 新增/更新的时候进行填充
fill = FieldFill.INSERT_UPDATE
复制代码
总结
这里还是要说一下,不重复造轮子,对我们 IT 的开发者来说,很多时候都喜欢自己写,这样子比较有成就感,但是小编认为,花时间去读懂别的思想及设计还是非常重要的,对于已经存在的东西,小编认为三步走:读懂设计,用起来,按需改造。
评论