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

 更新时间:2022年08月01日 10:09:45   作者:小刘要努力(ง •̀_•́)ง  
在开发中经常遇到多个实体类有共同的属性字段,这些字段属于公共字段,也就是很多表中都有这些字段,能不能对于这些公共字段在某个地方统一处理,来简化开发呢?MyBatis-Plus就提供了这一功能,本文就来为大家详细讲讲

1.问题分析

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

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

到此这篇关于MyBatis-Plus实现公共字段自动填充功能详解的文章就介绍到这了,更多相关MyBatis-Plus字段自动填充内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • java判断integer是否为空的详细过程

    java判断integer是否为空的详细过程

    在java编写过程中,我们会使用到各种各样的表达式,在使用表达式的过程中,有哪些安全问题需要我们注意的呢?对java判断integer是否为空相关知识感兴趣的朋友一起来看看吧
    2023-02-02
  • Java双向链表倒置功能实现过程解析

    Java双向链表倒置功能实现过程解析

    这篇文章主要介绍了Java双向链表倒置功能实现过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-09-09
  • JDBC三层架构深入刨析

    JDBC三层架构深入刨析

    三层架构是一种软件设计架构,是一种组织代码的手段和方法,三层架构的优点是扩展性好,复用性高;缺点是步骤多,比较繁琐;代码多,效率降低
    2022-12-12
  • Java中的锁分类的详细介绍

    Java中的锁分类的详细介绍

    这篇文章主要介绍了Java中的锁分类的详细介绍,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-09-09
  • Spring Boot整合JWT的实现步骤

    Spring Boot整合JWT的实现步骤

    本文主要介绍了Spring Boot整合JWT,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-08-08
  • Spring @bean和@component注解区别

    Spring @bean和@component注解区别

    本文主要介绍了Spring @bean和@component注解区别,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-01-01
  • springboot整合swagger3和knife4j的详细过程

    springboot整合swagger3和knife4j的详细过程

    knife4j的前身是swagger-bootstrap-ui,取名knife4j是希望她能像一把匕首一样小巧,轻量,并且功能强悍,下面这篇文章主要介绍了springboot整合swagger3和knife4j的详细过程,需要的朋友可以参考下
    2022-11-11
  • springboot配置项目启动后自动打开浏览器访问项目方式

    springboot配置项目启动后自动打开浏览器访问项目方式

    这篇文章主要介绍了springboot配置项目启动后自动打开浏览器访问项目方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-01-01
  • Java单元测试工具之JUnit的使用

    Java单元测试工具之JUnit的使用

    本篇文章主要详细介绍单元测试工具JUnit的使用,文章中有详细的代码实例,有一定的参考价值,需要的朋友可以参考阅读
    2023-04-04
  • Spring Native实现0.059s启动一个SpringBoot项目

    Spring Native实现0.059s启动一个SpringBoot项目

    Spring Native是Spring框架的一个子项目,旨在提供一种将Spring应用程序编译为本地可执行文件的方法,从而提高启动时间和资源效率,本文主要介绍了Spring Native实现0.059s启动一个SpringBoot项目,感兴趣的可以了解一下
    2024-02-02

最新评论