手撕「字段自动填充」的2种方案

SpringBoot 公共字段自动填充技巧 在 Spring Boot 开发中,实体类常包含公共字段(如创建时间、更新时间、创建人、更新人、删除标记等),这类字段在增删改查时重复赋值,不仅冗余还易出错。以下是3 种高效的公共字段自动填充技巧优先选Jackson或Fastjson 2:覆盖绝大多数企业级场景,性能和功能平衡;快速开发 / Android 选Gson:零配置上手,学习成本低;Kotlin 项目选Moshi:原生适配,空安全友好;无依赖简单场景选org.json:无需额外引入包,够用即可。 阅读详情

01 引言

上一期,我们介绍了Mybatis-Plus的自动填充功能,用起来简直不要太爽。我们能不能去自己实现呢?

这一期,我们将介绍两种方案实现字段的自动填充:

  • 基于Mybatis的拦截器
  • 基于AOP的自定义注解

02 基于Mybaits的拦截器

我们先看看官方给的解释:

主要拦截的接口:

  • org.apache.ibatis.executor.Executor:SQL执行
  • org.apache.ibatis.executor.parameter.ParameterHandler:参数处理
  • org.apache.ibatis.executor.resultset.ResultSetHandler:结果集
  • org.apache.ibatis.executor.statement.StatementHandler:声明

截图中括号里面表示每一个接口的方法。

2.1 拦截器的使用

主要的注解包括:@org.apache.ibatis.plugin.Intercepts、@org.apache.ibatis.plugin.Signature

官方案例:

// ExamplePlugin.java
@Intercepts({@Signature(
  type= Executor.class,
  method = "update",
  args = {MappedStatement.class,Object.class})})
public class ExamplePlugin implements Interceptor {
  @Override
  public Object intercept(Invocation invocation) throws Throwable {
    // implement pre processing if need
    Object returnObject = invocation.proceed();
    // implement post processing if need
    return returnObject;
  }
}

可以看出:一个@Intercepts注解可以控制多个@Signature

  • type:表示拦截的接口的class
  • method:表示拦截接口的某个方法
  • args:方法的参数

这几个参数都可以通过org.apache.ibatis.plugin.Invocation获取到。

2.2 定制自动填充的拦截器

自动填充,我们只需要在SQL执行之前,填充好数据即可。所以这里我们拦截的是org.apache.ibatis.executor.Executor的update方法。

为了演示方便,这里只针对实体的updateTime字段处理,使用了硬编码。要想按照配置或者随意指定,可以配置自定义注解打标签,这里然后统一处理即可。

@Intercepts({@Signature(
        type = Executor.class,
        method = "update",
        args = {MappedStatement.class,Object.class}
)})
@Component
public class AutoFillInterceptor implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        Object[] args = invocation.getArgs();
        MappedStatement ms = (MappedStatement) args[0];
        Map<String, Object> entityMap = (Map<String, Object>)args[1];
        Object entity = entityMap.get("param1");

        // 获取SQL操作类型
        String sqlCommandType = ms.getSqlCommandType().name();
        // UPDATE操作填充
        if ("UPDATE".equals(sqlCommandType)) {
            Class<?> clazz = entity.getClass();
            Field updateTimeField = ReflectionUtils.findField(clazz, "updateTime", LocalDateTime.class);
            updateTimeField.setAccessible(true);
            updateTimeField.set(entity, LocalDateTime.now());
        }
        return invocation.proceed();
    }
}

拦截器的核心就是拿到数据库实体,然后通过反射技术实现参数的赋值。案例中直接使用了Spring提供的ReflectionUtils工具类直接事半功倍。

拦截器中只处理了UPDATE的命令类型,使用者可以根据情况追加。

参数的获取,是根据方法的定义的顺序依次获取的。这里要说明的是:Object.class对应的结果是一个Map,这个是通过打断点看到的结果,使用者可以自行调整。

在测试过程中发现:param1和userInfo是一样的值,修改两个任意一个都会被赋值。所以案例选择了parm1这个没有特殊含义的字段。

2.3 测试以及结果

客户端:

@Test
void contextLoads04() {
    UserInfo userInfo = new UserInfo();
    userInfo.setId(61);
    userInfo.setName("test");
    userInfoNativeMapper.updateByKey(userInfo);
}

服务:

public interface UserInfoNativeMapper {
    
    @Update("""
        <script>
            update user_info 
            <set>
                name=#{userInfo.name}, 
                <if test="userInfo.updateTime != null">
                    update_time=#{userInfo.updateTime} 
                </if>
            </set>
            where id=#{userInfo.id}
        </script>
    """)
    void updateByKey(@Param("userInfo") UserInfo userInfo);
}

这里使用了注解的方式,如果updateTime不为空,才会更新。

结果:

从结果看到,update_time字段已经被自动填充了。

03 基于AOP的自定义注解

自定义注解要实现的目标:

  • 标记需要填充的字段
  • 标记要拦截的方法(切点)

3.1 自定义注解

@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoFill {

    /**
     *  注解类型
     */
    FillTypeEnum type() default FillTypeEnum.FIELD;

    /**
     * 值
     */
    String value() default "";

    /**
     * 方法类的Class
     */
    Class<?> clazz() default Void.class;

    /**
     * 方法名
     */
    String methodName() default "";

}

/** 注解的类型 */
public enum FillTypeEnum {
    FIELD, METHOD
}

标记的位置通过FillTypeEnum指定:

  • FillTypeEnum.FIELD 标记字段,默认
  • FillTypeEnum.METHOD 标记方法

@AutoFill注解通过value指定填充的值,如果为空,则通过方法的class和对应的方法,最后调用填充值。

3.2 定义切面

Maven

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

切面

@Aspect
@Component
public class AutoFillAspect {

    @Around("@annotation(autoFill)")
    public Object around(ProceedingJoinPoint joinPoint, AutoFill autoFill) throws Throwable {
        FillTypeEnum type = autoFill.type();
        if (type == FillTypeEnum.METHOD) {
            // 拦截方法上的注解
            Object entity = joinPoint.getArgs()[0];
            Class<?> clazz = entity.getClass();

            // 获取所有的字段
            Field[] declaredFields = clazz.getDeclaredFields();
            int length = declaredFields.length;
            if (length > 0) {
                for (int i = 0; i < length; i++) {
                    Field field = declaredFields[i];
                    AutoFill annotation = field.getAnnotation(AutoFill.class);
                    if (annotation != null && annotation.type() == FillTypeEnum.FIELD) {
                        field.setAccessible(true);
                        String value = annotation.value();
                        if (StringUtils.hasText(value)) {
                            Class<?> fieldClazz = field.getType();
                            if (fieldClazz == LocalDateTime.class) {
                                field.set(entity, LocalDateTime.parse(value, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
                            }else if (fieldClazz == Integer.class) {
                                field.set(entity, Integer.valueOf(value));
                            }else {
                                field.set(entity, value);
                            }
                            continue;
                        }

                        Class<?> methodClazz = annotation.clazz();
                        String s = annotation.methodName();
                        Method method = methodClazz.getDeclaredMethod(s, null);
                        Object invoke = method.invoke(methodClazz, null);
                        field.set(entity, invoke);
                    }
                }
            }
        }
        return joinPoint.proceed();
    }
}

核心就是获取方法的参数,解析参数的需要填充的字段,然后通过value或者调用方法,自动赋值填充。

3.3 注解使用

字段标记:

方法标记:

3.4 测试以及结果

客户端和拦截器的相同,我们直接看结果:

从结果来看,达到了同样的效果。

通过注解标记方法有代码侵入性,可以使用切点的表达式,指定某一类方法即可。

04 小结

无论使用第三方还是自己手撕的代码,最终的结果都是为了解决重复的代码问题。小编以为第三方的自动填充具有一定的局限性,而自定义的更具有扩展性,可能更适合代码不怎么规范的公司,还可以扩展功能,大家更喜欢哪一种呢?

Mybatis Plus公共字段自动填充实战解析 在Java持久层开发中,公共字段管理是提升代码质量的关键环节。通过反射机制,ORM框架能够自动处理create_time、update_time等审计字段的赋值问题。Mybatis Plus的MetaObjectHandler接口实现了这一技术原理,开发者只需定义填充策略,即可减少30%以上的样板代码。该技术特别适用于电商订单系统等需要严格审计追踪的场景,结合@TableField注解的fill属性,可以灵活配置插入/更新时的字段填充行为。通过strict严格模式和多租户扩展,既能确保数据一致性,又能满足S 阅读详情

相关推荐

电动汽车充电设备标准化设计方案:电气原理图

80kW一体式一机一枪充电机电气原理 主电路拓扑见图1,配置1个250A直流充电连接装置,提供4个充电模块安装位置,根据充电功率需求可选配2~4个20kW充电模块。内置直流电能表和计费控制单元,实现计量计费和充电控制功能。 图1 80kW一体式一机一枪充电机主电路拓扑 ...

santirenpc的博客 1万+

MyBatis-Plus字段自动填充功能,update 方法导致自动填充失败问题

在使用 MyBatis-Plus 时,自动填充机制通过实现 MetaObjectHandler 接口来统一处理诸如 UPDATER 和 UPDATE_DATE 等公共字段。但在使用 update 方法时,不同的用法可能导致自动填充机制失效。

weixin_66212050的博客 1485

VisionMaster图像源配置全攻略:从本地图片到相机SDK的保姆级教程

本文详细解析了VisionMaster图像源配置的三种主流方式:本地图片、相机直连和SDK集成。从像素格式选择到工业相机触发控制,再到SDK开发实战,提供全面的技术指导和避坑建议,帮助开发者高效实现图像处理应用的部署与优化。

yhn45678901的博客 781

mybatis 自动填充时间字段

本例项目实践过程中,数据模型创建包含公共字段(创建时间createTime,最后更新时间last_updated_time),为了开发人员方便,打算自动填充时间公共字段;本例数据库采用oceanbase; 以下2种方式,可以处理以下场景问题 1. 从数据库表创建角度解决,表创建时给时间字段加上默认值,例如下面案例 CREATE TABLE TEST ( ID VARCHAR(100) DE...

Ronin_88的博客 4581

银河麒麟服务器操作系统V10 SP1:跨架构激活与设备更换无忧指南

本文详细解析了银河麒麟服务器操作系统V10 SP1的跨架构激活新特性。该特性彻底解除了授权与CPU架构的绑定,允许同一份授权在x86、ARM、龙芯等不同架构服务器间灵活使用。文章提供了从新设备激活到硬件更换后保持激活状态的全流程实战指南,并分享了内网环境部署等高级技巧,助力企业简化运维、提升硬件资源管理灵活性。

ff678的博客 353

Xilinx PL端DP显示接口开发实战(一)——环境搭建与硬件选型

本文详细介绍了Xilinx PL端DP显示接口开发的环境搭建与硬件选型实战经验。从Vivado和Vitis 2021.1版本的软件安装要点,到DP141和MCDP6000芯片的选型建议,再到DP1.4接口的RX/TX方向开发关键点,为开发者提供了全面的技术指导。文章还分享了IP核配置、BD原理图设计以及常见问题排查的实用技巧,帮助开发者高效完成Xilinx DP接口开发项目。

weixin_29250573的博客 177

【设计方案】MyBatisPlus自动填充审计字段

在MyBatisPlus中手动实现strictFill()方法,ThreadLocal结合Session管理上下文。

甜鲸鱼的博客 1380

本地部署llama3Chinese

这通常意味着你的构建环境可能不完整或者没有正确配置。通常是由 Visual Studio 的 C++ 工具提供的。(大模型对错误的解析)错误信息表明在尝试构建一个项目时,在 Windows 上,

m0_49343639的博客 1434

MyBatis Plus 中 update_time 字段自动填充失效的原因分析及解决方案

在使用时,通常我们会在数据库表中设置和两个字段,借助 MyBatis Plus 的自动填充功能来维护这些时间字段。但是,有时候你可能会遇到字段未自动更新的情况,哪怕代码中已经配置了。本文将针对这一问题,分析可能的原因,并提供详细的解决方案。如果你在Mapper.xml中自定义了update语句,那么 MyBatis Plus 不会触发自动填充逻辑。解决方案:方法 1:在 XML 中手动设置</update>方法 2user.setName("李四");原因现象解决方法使用了未更新使用。

weixin_44876263的博客 2145

STM32G474实战:数字LLC电源控制程序从零到跑通(附完整代码解析)

本文详细介绍了基于STM32G474微控制器开发数字LLC电源控制程序的完整实战流程。从硬件平台搭建、CubeMX工程配置,到核心控制逻辑、双速率中断框架、数字PID实现,再到Burst模式、状态机等高级策略与异常处理,提供了从零到跑通的系统化指南与代码解析,助力开发者掌握高效数字电源的程序编写与调试技巧。

s1t2u3的博客 1240

道路施工检测 (construction) - 基于Mapillary Vistas数据集的YOLOv11目标检测及UI界面实现

目标检测是计算机视觉的重要任务,目标是识别图像中的目标物体类别及其位置(用边界框表示)。两阶段检测器:如Faster R-CNN,准确度高但速度较慢单阶段检测器:如YOLO系列、SSD,速度快且精度相对较好,适合实时场景数据量:约25,000张高分辨率街景图标注类型:语义分割、实例分割、多类别检测类别示例:construction, road, car, person, traffic sign等格式:COCO风格JSON标注。

YOLO 497

【全家桶教学】Spring Boot 公共字段自动填充实战(含 MyBatis Plus/AOP 两种方案)

亲爱的读者们,公共字段自动填充就像给代码请了个贴心小秘书,让我们告别重复劳动,专注核心业务。记得去年帮表弟重构 OA 系统时,用这个技巧让代码整洁度提升了 50%,连他的项目经理都来取经。希望这篇文章能帮你们写出更优雅的代码,让开发效率翻倍!

潜意识Java的博客 1376

C++ getline函数详解与示例代码

每次调用函数时,会读取一行文本,并将其存储在字符串对象中。在循环中,我们检查读取到的文本是否为空行,如果是则跳出循环,否则输出读取到的文本。这个函数在处理用户输入、文件读取等场景中非常有用,希望能对您的C++编程有所帮助。函数是一个常用的字符串输入函数,可以用于从输入流中读取一行文本。首先,我们输出提示信息,要求用户输入一行文本。函数会等待用户输入,并将输入的文本存储在。函数从输入流中读取一行文本,并将其存储在字符串对象。这样,当用户输入制表符时,函数会停止读取。函数的用法,并提供相应的示例代码。

LogicGuruX的博客 829

protobuf自动填充字段数据

利用protobuf的反射机制进行字段值的自动填充

qq_37245700的博客 793

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

Mybatis-plus 自动填充 不生效或自动填充数据为null 原因及解决方案

mybatis-plus自动填充不生效 填充的数据为空 使用乐观锁自动填充失效 当字段从数据库查询出来时自动填充不生效问题

五更依旧朝花落的博客 2万+

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

Java开发 - 公共字段的自动填充

看来,解决问题时,方向一定要找对,斗则方向错了,怎么也不可能完成目标的。一开始博主想要用过滤器来完成,但是发现过滤器无法进行写操作,转而更换了方向,从元数据处理器下手,最后终于实现了公共字段填充。觉得不错,就给个赞吧。

CodingFire的博客 1952

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

MyBatis Plus时间字段自动填充实战

在日常开发中,我们经常需要记录数据的创建时间和更新时间。传统的做法是在每次插入或更新操作时手动设置这些时间字段,这种方式不仅繁琐,还容易遗漏。本文将介绍如何使用 MyBatis Plus 的自动填充功能来优雅地解决这个问题。首先在实体类的时间字段上添加 MyBatis Plus 的自动填充注解: 注解说明:创建自定义的元数据处理器来实现具体的填充逻辑: 核心方法说明:移除原本手动设置时间的代码:修改前: 修改后: 🔍 填充机制详解 创建记录时的填充过程 更新记录时的填充过程 🗂️ 数据库建议配置 虽

qq_40603125的博客 1043

mybatis-plus公共字段自动填充功能

这里是比较活泛的/*** 自定义sql字段填充器,自动填充创建修改相关字段*/@Override//为空则设置createUser//为空则设置insertTime@Override/*** 获取用户唯一id*/return -1L;//如果获取不到就返回-1return -1L;}*/

m0_61682705的博客 614

Java项目中实现公共字段自动填充值的方案

首先,定义一个包含公共字段的实体类,并使用JPA的注解来标识这些字段。Date;@Entity@Id首先,定义一个切面类,使用@Aspect注解标识,并在切面类中定义切点和通知。// 获取当前用户的方法,例如从SecurityContext中获取 return "currentUser";} }

xycxycooo的博客 628

SQL语句中公共字段如何自动填充

这篇文章主要给大家介绍了关于SQL语句中公共字段的自动填充方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧 前言 我们在设计数据库的时候一定会带上新增、更新的时间、操作者等审计信息。 之所以带这些信息是因为假如有一天公司的数据库被人为删了,尽管可能有数据库备份可以恢复数据。但是我们仍然需要追踪到这个事是谁干的,在什么时间干的,具体干了哪些事等等,方便定责和修补。但是我们变更每条数据都要去显式变更这些信息就十分繁琐,我们希望无感知的来处

yunduanaoligei的博客 428

基于 AOP + 反射实现公共字段自动填充

INSERT(新增)和UPDATE(修改)新增操作:需要填充createTimecreateUserupdateTimeupdateUser四个字段;修改操作:仅需要填充updateTimeupdateUser两个字段。/*** 数据库操作类型枚举*//*** 新增操作*/INSERT,/*** 修改操作*/UPDATE接下来定义一个自定义注解@AutoFill,该注解仅作用于方法,且在运行时有效,用于标记 Mapper 接口中需要进行公共字段自动填充的方法。

asad6的博客 644

SpringBoot结合MyBatisPlus的公共字段自动填充

MyBatisPlus公共自动填充,也就是在插入或更新的时候为指定字段赋予指定的值,常见的例子就是更新时间一般都是现在的时间,就可以将这个字段进行统一处理,使用它的好处就是可以统一对这些字段进行处理,避免了重复代码

qq_58291481的博客 1510

Mybatis-Plus 自动属性填充与自定义Insert into语句顺序&MyBatisPlus中使用 @TableField完成字段自动填充

TableField注解是MyBatisPlus提供的用于实体类字段的注解,用于配置字段的属性和行为。其中,我们可以通过设置fill属性来实现字段自动填充的功能。通过使用@TableField注解和自定义的MetaObjectHandler填充处理器,我们可以很方便地实现字段的自动填充功能。在MyBatisPlus中,这个功能可以简化我们的开发工作,提高代码的可维护性和可读性。希望本文对大家在使用MyBatisPlus进行开发时有所帮助!

qq_43842093的博客 3236

禁用Chrome自动填充

This post is a Community Wiki . 这篇文章是社区维基 。 Ed

CHCH998的博客 742

Mybaits-plus排除自动填充实体

版本 springboot 2.0.3 + mybatis-plus 3.0.5 场景 mybatis-plus开启了自动填充功能后,在insert 或update时就会自动填充实体中自动填充字段,但是有时候我们并需要字段填充,比如实体类中不需要createBy createTime updateBy updateTime 这样的字段,因为MP的自动填充功能是全局的,一旦开启自动填充功能后就会导...

Evian_Tian的博客 3035

Spring Boot MyBatis-Plus自动填充

通过注解和自定义,你可以轻松实现MyBatis-Plus的字段自动填充。关键在于理解不同填充方法的适用场景,并注意填充触发的条件。以下代码中:-- 文件资源begin[file_id] [int] IDENTITY(1,1) NOT NULL, -- 文件唯一id[file_name] [nvarchar] (255) NOT NULL, -- 文件名[file_extension] [nvarchar] (20) default '' NULL, -- 文件后缀。

BillKu的博客 855
上一篇: 甩掉手动赋值!MyBatis-Plus 自动填充实战秘籍
下一篇: 营销级二维码生成术:Java如何打造专属标识
智_永无止境
博客等级 码龄10年 803粉丝 406原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

智_永无止境

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值