MyBatis-Plus实现公共字段自动填充功能详解

作者:小刘要努力(????_??)? 时间:2021-10-19 22:14:39 

1.问题分析

我们在开发中经常遇到多个实体类有共同的属性字段,例如在用户注册时需要设置创建时间、创建人、修改时间、修改人等字段,在用户编辑信息时需要设置修改时间和修改人等字段。这些字段属于公共字段,也就是很多表中都有这些字段,能不能对于这些公共字段在某个地方统一处理,来简化开发呢?

MyBatis-Plus实现公共字段自动填充功能详解

答案就是我们可是使用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) {
   }
}

来源:https://blog.csdn.net/weixin_44684272/article/details/126067864

标签:MyBatis-Plus,字段,填充
0
投稿

猜你喜欢

  • Java使用 try-with-resources 实现自动关闭资源的方法

    2022-01-09 06:54:46
  • Spring Security前后分离校验token的实现方法

    2023-06-26 17:00:30
  • C# WinForm制作异形窗体与控件的方法

    2023-11-07 11:09:28
  • idea的easyCode的 MybatisPlus模板的配置详解

    2022-04-18 21:01:29
  • springBoot Junit测试用例出现@Autowired不生效的解决

    2023-01-24 12:57:59
  • IDEA SpringBoot项目配置热更新的步骤详解(无需每次手动重启服务器)

    2023-11-12 00:22:41
  • Spring Boot常用注解(经典干货)

    2023-11-24 22:29:10
  • c#和net存取cookies操作示例

    2023-10-11 15:28:26
  • java 中sendredirect()和forward()方法的区别

    2021-11-07 18:39:28
  • 浅谈hibernate急迫加载问题(多重外键关联)

    2023-08-18 12:58:54
  • java为何不能多继承的原因详解

    2023-10-12 04:45:00
  • 深入理解java final不可变性

    2023-02-11 20:17:27
  • Java并发框架:Executor API详解

    2021-10-31 14:30:28
  • Java数据结构之优先级队列(PriorityQueue)用法详解

    2023-11-18 13:00:50
  • idea 打包maven项目忽略test文件的操作

    2021-10-16 07:21:14
  • java实现多文件上传至本地服务器功能

    2022-01-26 11:55:24
  • SpringBoot配置SSL同时支持http和https访问实现

    2023-04-25 19:42:45
  • 记一次springboot服务凌晨无故宕机问题的解决

    2023-07-25 04:50:23
  • JAVA序列化Serializable及Externalizable区别详解

    2022-04-04 10:49:09
  • Java反射机制基础详解

    2023-07-17 04:36:29
  • asp之家 软件编程 m.aspxhome.com