前面已经介绍了Mybatis-plus基本用法,今天为大家分享一些Mybatis-plus高级应用
- 逻辑删除
- 自动注入
- 枚举类型处理
- Sql注入器
- 多租户
表结构
CREATE TABLE `sys_role` ( `id` varchar(64) NOT NULL COMMENT '主键', `code` varchar(64) NOT NULL DEFAULT '' COMMENT '角色编码', `name` varchar(64) NOT NULL DEFAULT '' COMMENT '角色名', `type` char(2) NOT NULL COMMENT '角色类型,1:管理员,2:普通', `tenant_code` varchar(64) NOT NULL DEFAULT '' COMMENT '租户编码', `create_user` varchar(64) NOT NULL DEFAULT '' COMMENT '创建用户', `create_time` datetime NOT NULL COMMENT '创建时间', `update_user` varchar(64) NOT NULL DEFAULT '' COMMENT '更新用户', `update_time` datetime NOT NULL COMMENT '更新时间', `is_del` char(1) NOT NULL DEFAULT '0' COMMENT '是否删除,0:未删除,1:删除', PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='角色';
逻辑删除
全局配置
在配置文件中增加如下配置
mybatis-plus: global-config: db-config: logic-delete-field: isDel#全局逻辑删除字段值 3.3.0开始支持,详情看下面。 logic-delete-value: 1 # 逻辑已删除值(默认为 1) logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
局部配置
在实体类删除字段上增加@TableLogic注解
/** 是否删除,0:未删除,1:删除 */@TableLogicprivate String isDel;
全局配置和局部配置实现的结果是一样的,下面针对局部配置做一下测试
@Autowiredprivate RoleMapper roleMapper;@Testpublic void logicDel() { roleMapper.deleteById("1");}
从结果可以看出角色id为1数据的is_del被设置为1
使用Mybatis-plus自带方法删除、更新和查找都会where条件后面加上删除字段
以查询为例看一下效果
@Test void loginDel2() { roleMapper.selectList(null);}
从打印的sql中可以看出,在where后面添加了is_del='0'限定,所以要查询所有数据可以采用自定义sql实现
自动填充
在项目开发中,表中经常会定义一些公共的字段,例如:修改人,创建人。这时候我们可以采用 MyBatis-Plus 中
的字段自动填充功能去实现。
- 在实体类属性上增加@TableField(fill = FieldFill.INSERT_UPDATE)注解,如下所示
@Data@TableName("sys_role")public class Role { /** 创建人 */ @TableField(fill = FieldFill.INSERT) private String createUser; /** 创建时间 */ @TableField(fill = FieldFill.INSERT) private Date createTime; /** 更新人 */ @TableField(fill = FieldFill.INSERT_UPDATE) private String updateUser; /** 更新时间 */ @TableField(fill = FieldFill.INSERT_UPDATE) private Date updateTime; /** 是否删除,0:未删除,1:删除 */ @TableLogic private String isDel;}
TableField默认有四个
- DEFAULT:默认不处理
- INSERT:插入时填充字段
- UPDATE:更新时填充字段
- INSERT_UPDATE:插入和更新时填充字段
- 定义处理器
@Componentpublic class MyMetaObjectHandler implements MetaObjectHandler { public static String CREATEUSER_NAMEINBEAN = "createUser"; public static String CREATETIME_NAMEINBEAN = "createTime"; public static String UPDATEUSER_NAMEINBEAN = "updateUser"; public static String UPDATETIME_NAMEINBEAN = "updateTime"; @Override public void insertFill(MetaObject metaObject) { boolean createUser = metaObject.hasSetter(CREATEUSER_NAMEINBEAN); if (createUser) { this.strictInsertFill(metaObject, CREATEUSER_NAMEINBEAN, String.class, "admin"); } boolean createTime = metaObject.hasSetter(CREATETIME_NAMEINBEAN); if (createTime) { this.strictInsertFill(metaObject, CREATETIME_NAMEINBEAN, LocalDateTime.class, LocalDateTime.now()); } boolean updateUser = metaObject.hasSetter(UPDATEUSER_NAMEINBEAN); if (updateUser) { this.strictInsertFill(metaObject, UPDATEUSER_NAMEINBEAN, String.class, "admin"); } boolean updateTime = metaObject.hasSetter(UPDATETIME_NAMEINBEAN); if (updateTime) { this.strictInsertFill(metaObject, UPDATETIME_NAMEINBEAN, LocalDateTime.class, LocalDateTime.now()); } } @Override public void updateFill(MetaObject metaObject) { boolean updateUser = metaObject.hasSetter(UPDATEUSER_NAMEINBEAN); if (updateUser) { this.strictInsertFill(metaObject, UPDATEUSER_NAMEINBEAN, String.class, "amdin"); } boolean updateTime = metaObject.hasSetter(UPDATETIME_NAMEINBEAN); if (updateTime) { this.strictInsertFill(metaObject, UPDATETIME_NAMEINBEAN, LocalDateTime.class, LocalDateTime.now()); } }}
- 测试
@Testvoid update() { // 更新id为2角色的名字为测试2 Role role = new Role(); role.setName("测试2"); role.setId("2"); roleMapper.updateById(role);}
在执行更新操作时自动加上更新人和更新时间
枚举类型处理器
自mybatis3.1.0开始,如果你无需使用原生枚举,可配置默认枚举来省略扫描通用枚举配置 默认枚举配置
- 定义枚举类,主要有两种方式
方法一:采用继承IEnum实现
@Getter@AllArgsConstructorpublic enum RoleType implements IEnum { ADMIN("1"), COMMON("2"); private String type; @Override public Serializable getValue() { return type; }}
方法二:注解方式,在枚举类需要解析的属性上增加@EnumValue注解
@Getter@AllArgsConstructorpublic enum RoleType { ADMIN("1"), COMMON("2"); @EnumValue//标记数据库存的值是type private String type;}
- 定义实体类
@Data@TableName("sys_role")public class Role { /** 角色类型 */ private RoleType type;}
- 配置扫描的枚举包路径
mybatis-plus: typeEnumsPackage: com.yanyu.spring.mybatisplus.enums
从结果可以看出查询出的角色类型自动转换成了枚举ADMIN
Sql注入
当Mybatis-plus自带的原生方法不能满足我们的需求,我们可以利用sql注入器自定义sql
实现步骤:
- 创建自定义的类
public class DeleteByCodeMethod extends AbstractMethod { @Override public MappedStatement injectMappedStatement(Class> mapperClass, Class> modelClass, TableInfo tableInfo) { // 执行的slq String sql = "delete from "+ tableInfo.getTableName() +" where code = #{code}"; // Mapper接口方法名 String method = "deleteByCode"; SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass); return addDeleteMappedStatement(mapperClass, method, sqlSource); }}
- 创建注入器
@Componentpublic class MySqlInject extends DefaultSqlInjector { @Override public List getMethodList(Class> mapperClass) { List methodList = super.getMethodList(mapperClass); methodList.add(new DeleteByCodeMethod()); return methodList; }}
- 在Mapper中加入自定义方法
public interface RoleMapper extends BaseMapper { int deleteByCode(@Param("code") String code);}
- 测试
@Testvoid deleteByCode() { // 删除编码为code的角色 roleMapper.deleteByCode("test");}
从结果看,我们自定义的根据编码删除数据执行成功
Mybatis-plus官方为我们提供了三种自定义类
- InsertBatchSomeColumn:批量新增数据,自选字段insert
- AlwaysUpdateSomeColumnById:根据id更新固定字段
- LogicDeleteByIdWithFill:根据id逻辑删除,并带字段填充功能
以InsertBatchSomeColumn为例,简单的演示一下怎么使用
- 在注入器中加入InsertBatchSomeColumn自定义类
@Componentpublic class MySqlInject extends DefaultSqlInjector { @Override public List getMethodList(Class> mapperClass) { List methodList = super.getMethodList(mapperClass); methodList.add(new DeleteByCodeMethod()); /** * 不是逻辑删除的字段包括在内 */ methodList.add(new InsertBatchSomeColumn(t -> !t.isLogicDelete())); return methodList; }}
- 在Mapper中加入自定义方法
public interface RoleMapper extends BaseMapper { int insertBatchSomeColumn(List list);}
- 测试
@Testvoid insertBatchSomeColumn() { // 测试批量插入角色1和角色2 Role role1 = new Role(); role1.setCode("ROLE_1"); role1.setName("角色1"); role1.setType(RoleType.ADMIN); Role role2 = new Role(); role2.setCode("ROLE_2"); role2.setName("角色2"); role2.setType(RoleType.ADMIN); List roles = new ArrayList<>(Arrays.asList(role1,role2)); roleMapper.insertBatchSomeColumn(roles);}
多租户
租户实现
Mybatis-plus多租户依赖于分页插件,下面我们将简单介绍如何实现租户解析
- 定义租户解析器
@Beanpublic PaginationInterceptor paginationInterceptor() throws IOException { PaginationInterceptor paginationInterceptor = new PaginationInterceptor(); TenantSqlParser tenantSqlParser = new TenantSqlParser(); tenantSqlParser.setTenantHandler(new TenantHandler() { @Override public Expression getTenantId(boolean select) { return new StringValue("00000"); } @Override public String getTenantIdColumn() { return "tenant_code"; } @Override public boolean doTableFilter(String tableName) { /** * 是否加租户信息,false->加,true->不加 */ return false; } }); paginationInterceptor.setSqlParserList(Arrays.asList(tenantSqlParser)); return paginationInterceptor;}
- 测试
@Testpublic void tenant() { // 查询id为1的角色 roleMapper.selectById("1");}
从结果看,sql执行时在查询条件中自动为我们加上了租户判断
特定sql过滤
在开发中有的方法不需要限定租户标识,实现方式有两种
- 方式一:通过在分页插件中自定义过滤器,具体实现如下所示
@Beanpublic PaginationInterceptor paginationInterceptor() throws IOException { PaginationInterceptor paginationInterceptor = new PaginationInterceptor(); TenantSqlParser tenantSqlParser = new TenantSqlParser(); tenantSqlParser.setTenantHandler(new TenantHandler() { @Override public Expression getTenantId(boolean select) { return new StringValue("00000"); } @Override public String getTenantIdColumn() { return "tenant_code"; } @Override public boolean doTableFilter(String tableName) { /** * 是否加租户信息,false->加,true->不加 */ return false; } }); paginationInterceptor.setSqlParserList(Arrays.asList(tenantSqlParser)); paginationInterceptor.setSqlParserFilter(new ISqlParserFilter() { /** * true 不增加,false 增加 * @param metaObject * @return */ @Override public boolean doFilter(MetaObject metaObject) { MappedStatement ms = SqlParserHelper.getMappedStatement(metaObject); if("具体方法".equals(ms.getId())) { return true; } return false; } }); return paginationInterceptor;}
- 方式二:在不需要限定租户的方法上加入
public interface RoleMapper extends BaseMapper { @SqlParser(filter = true) int getByCode(String code);}
如果有哪里写得不对的,还请各位小友指正,只有不断试错,才能慢慢提高。如果你觉得对你有帮助,请点赞+关注,谢谢!!!!!!