互联网应用架构:专注编程教学,架构,JAVA,Python,微服务,机器学习等领域,欢迎关注,一起学习。
现在很多项目都用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,今天我们就用最新版来操作
com.baomidou
mybatis-plus-boot-starter
3.4.0
多租户判断
多租户的判断的原理说起来非常简单,就是基于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 tenantId = getFieldValByName("tenantId", metaObject);
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 (tenantId == null) {
this.setFieldValByName("tenantId", HeaderUtils.getTenantId(), 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的开发者来说,很多时候都喜欢自己写,这样子比较有成就感,但是小编认为,花时间去读懂别的思想及设计还是非常重要的,对于已经存在的东西,小编认为三步走:读懂设计,用起来,按需改造。
--END--
原创作品,抄袭必究
如需要源码,转发,关注后私信我
部分图片或代码来源网络,如侵权请联系删除,谢谢!