MyBatis-Plus字段自动填充
小刘要努力(ง •̀_•́)ง 人气:01.问题分析
我们在开发中经常遇到多个实体类有共同的属性字段,例如在用户注册时需要设置创建时间、创建人、修改时间、修改人等字段,在用户编辑信息时需要设置修改时间和修改人等字段。这些字段属于公共字段,也就是很多表中都有这些字段,能不能对于这些公共字段在某个地方统一处理,来简化开发呢?
答案就是我们可是使用Mybatis Plus提供的公共字段自动填充功能。
2.实现步骤
Mybatis Plus公共字段自动填充,也就是在插入或者更新的时候为指定字段赋予指定的值,使用它的好处就是可以统一对这些字段进行处理,避免了重复代码。
实现步骤:
在实体类的属性上加入@TableField注解,指定自动填充的策略
@TableField(fill = FieldFill.INSERT)//插入时填充字段 private LocalDateTime createTime; @TableField(fill = FieldFill.INSERT_UPDATE)//插入、更新时填充字段 private LocalDateTime updateTime; @TableField(fill = FieldFill.INSERT)//插入时填充字段 private Long createUser; @TableField(fill = FieldFill.INSERT_UPDATE)//插入、更新时填充字段 private Long updateUser;
按照框架要求编写元数据对象处理器,在此类中统一为公共字段赋值,此类需要实现MetaObjectHandler接口
package com.lyq.reggie.common; import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.reflection.MetaObject; import org.springframework.stereotype.Component; import java.time.LocalDateTime; /** * 自定义元数据对象处理器 */ @Component @Slf4j public class MyMetaObjecthandler implements MetaObjectHandler { /** * 插入操作,自动填充 * @param metaObject */ @Override public void insertFill(MetaObject metaObject) { log.info("公共字段自动填充[insert]..."); log.info(metaObject.toString()); metaObject.setValue("createTime", LocalDateTime.now()); metaObject.setValue("updateTime",LocalDateTime.now()); metaObject.setValue("createUser", BaseContext.getCurrentId()); metaObject.setValue("updateUser",BaseContext.getCurrentId()); } /** * 更新操作,自动填充 * @param metaObject */ @Override public void updateFill(MetaObject metaObject) { log.info("公共字段自动填充[update]..."); log.info(metaObject.toString()); long id = Thread.currentThread().getId(); log.info("线程id为:{}",id); metaObject.setValue("updateTime",LocalDateTime.now()); metaObject.setValue("updateUser",BaseContext.getCurrentId()); } }
3. 实现字段全局填充
这个时候我们嫌弃每个表都需要加对应的注解,麻烦,这个时候我们就可以使用Mybatis Plus提供全局配置 sqlInjector 用于注入ISqlInjector接口的子类,实现自定义方法注入。
自定义自己的通用方法可以实现接口ISqlInjector也可以继承抽象类 AbstractSqlInjector 注入通用方法 SQL 语句 然后继承 BaseMapper 添加自定义方法,全局配置 sqlInjector 注入 MP 会自动将类所有方法注入到 mybatis 容器中。
首先我们需要增加一个配置类,将这个数据过滤器注册为bean
@Configuration public class MybatisPlusConfig { /* * @version V1.0 * Title: updateInterceptor * @author LiuYanQiang * @description 插入数据过滤器 * @createTime 2022/1/13 14:30 * @param [] * @return com.tfjybj.intelligentArticleSystem.config.MybatisPlusConfig.UpdateInterceptor*/ @Bean public UpdateInterceptor updateInterceptor() { return new UpdateInterceptor(); } }
再接着写拦截方法继承抽象类 AbstractSqlInjector 并且实现接口ISqlInjector来进行SQL的拦截实现公共字段的全局填充
package com.lyq.jsoup.config.MybatisPlusConfig; import com.baomidou.mybatisplus.extension.handlers.AbstractSqlParserHandler; import org.apache.commons.lang3.ArrayUtils; import org.apache.ibatis.executor.Executor; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.mapping.SqlCommandType; import org.apache.ibatis.plugin.*; import java.lang.reflect.Field; import java.sql.Timestamp; import java.util.Map; import java.util.Objects; import java.util.Properties; /** * @author : [LiuYanQiang] * @version : [v1.0] * @className : UpdateInterceptor * @description : [自动给创建时间个更新时间加值] * @createTime : [2022/1/12 9:09] * @updateUser : [LiuYanQiang] * @updateTime : [2022/1/12 9:09] * @updateRemark : [描述说明本次修改内容] */ @Intercepts(value = {@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})}) public class UpdateInterceptor extends AbstractSqlParserHandler implements Interceptor { /** * 创建时间 */ private static final String CREATE_TIME = "createTime"; /** * 更新时间 */ private static final String UPDATE_TIME = "updateTime"; @Override public Object intercept(Invocation invocation) throws Throwable { MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0]; // SQL操作命令 SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType(); // 获取新增或修改的对象参数 Object parameter = invocation.getArgs()[1]; // 获取对象中所有的私有成员变量(对应表字段) Field[] declaredFields = parameter.getClass().getDeclaredFields(); if (parameter.getClass().getSuperclass() != null) { Field[] superField = parameter.getClass().getSuperclass().getDeclaredFields(); declaredFields = ArrayUtils.addAll(declaredFields, superField); } // mybatis plus判断 boolean plus= parameter.getClass().getDeclaredFields().length == 1 && parameter.getClass().getDeclaredFields()[0].getName().equals("serialVersionUID"); //兼容mybatis plus if (plus) { Map<String, Object> updateParam = (Map<String, Object>) parameter; Class<?> updateParamType = updateParam.get(updateParam.keySet().iterator().next()).getClass(); declaredFields = updateParamType.getDeclaredFields(); if (updateParamType.getSuperclass() != null) { Field[] superField = updateParamType.getSuperclass().getDeclaredFields(); declaredFields = ArrayUtils.addAll(declaredFields, superField); } } String fieldName = null; for (Field field : declaredFields) { fieldName = field.getName(); if (Objects.equals(CREATE_TIME, fieldName)) { if (SqlCommandType.INSERT.equals(sqlCommandType)) { field.setAccessible(true); field.set(parameter, new Timestamp(System.currentTimeMillis())); } } if (Objects.equals(UPDATE_TIME, fieldName)) { if (SqlCommandType.INSERT.equals(sqlCommandType) || SqlCommandType.UPDATE.equals(sqlCommandType)) { field.setAccessible(true); //兼容mybatis plus的update if (plus) { Map<String, Object> updateParam = (Map<String, Object>) parameter; field.set(updateParam.get(updateParam.keySet().iterator().next()), new Timestamp(System.currentTimeMillis())); } else { field.set(parameter, new Timestamp(System.currentTimeMillis())); } } } } return invocation.proceed(); } @Override public Object plugin(Object target) { if (target instanceof Executor) { return Plugin.wrap(target, this); } return target; } @Override public void setProperties(Properties properties) { } }
加载全部内容