若依框架避坑指南:自定义注解实现自动填充的5个常见问题

若依框架整合mybatis-plus以及自动生成代码工具和自动填充字段功能 使用mybatis-plus集成自动生成代码和自动填充字段功能 阅读详情

若依框架自定义注解实战:从零构建自动填充的完整方案与深度避坑

最近在重构一个基于若依框架的后台管理系统,团队里几位新加入的开发者不约而同地遇到了同一个问题:每次新增或修改数据时,都要手动去设置创建人、创建时间、更新人、更新时间这些字段。代码里到处都是重复的 setCreateBy(SecurityUtils.getUsername()) 和 setCreateTime(new Date()),不仅繁琐,还容易遗漏。更麻烦的是,当业务逻辑复杂起来,有些方法里可能忘了设置更新人,有些又设置了两次创建时间,导致数据一致性出现问题。

这种场景在若依项目的开发中太常见了。若依框架本身提供了强大的基础功能,但在自动填充这类通用逻辑上,它更倾向于把灵活性留给开发者。于是,自定义注解配合AOP切面就成了最优雅的解决方案——至少在理论上是这样。实际落地时,你会发现从注解定义、切面编写到集成使用,每一步都有不少细节需要注意,稍有不慎就会掉进坑里。

今天我就结合最近项目中的实际经验,详细聊聊如何为若依框架实现一套健壮的自定义注解自动填充机制,并重点剖析那些容易让人栽跟头的问题。无论你是刚开始接触若依的新手,还是已经用过一阵子但总感觉不够顺手的开发者,相信这些实战中的教训和解决方案都能给你带来实实在在的帮助。

1. 理解若依框架的数据实体与自动填充的本质

在开始动手之前,我们需要先搞清楚若依框架中数据实体的设计哲学。若依的实体类通常继承自 BaseEntity,这个基类已经为我们定义好了那些通用的字段:

public class BaseEntity implements Serializable {
    private static final long serialVersionUID = 1L;
    
    /** 创建者 */
    private String createBy;
    
    /** 创建时间 */
    private Date createTime;
    
    /** 更新者 */
    private String updateBy;
    
    /** 更新时间 */
    private Date updateTime;
    
    // 省略getter和setter方法
}

注意:虽然很多项目都使用这个结构,但你的实际项目中的 BaseEntity 可能会有所不同。有些团队会添加租户ID、逻辑删除标记等字段,所以在实现自动填充前,一定要先确认你的基类结构。

自动填充的核心目标很简单:在数据插入或更新时,自动为这些字段赋予正确的值,而不需要开发者在每个业务方法中手动设置。这听起来像是AOP的完美应用场景——通过切面在方法执行前后拦截,修改参数或返回值。但若依框架本身已经集成了Spring生态,这意味着我们需要考虑如何让自定义的AOP切面与若依已有的组件和谐共处。

一个常见的误解是认为只需要写个注解和切面就万事大吉了。实际上,你需要考虑:

  • 切面的执行时机(Before、After还是Around?)
  • 如何获取当前登录用户信息
  • 如何处理嵌套调用和事务边界
  • 与MyBatis的拦截器如何分工协作

我见过不少团队一开始只实现了一个最简单的版本,随着业务复杂度的增加,各种边缘情况开始暴露出来,最终不得不重构整个方案。所以,与其事后补救,不如一开始就设计得周全一些。

2. 自定义注解的设计:不仅仅是添加和修改

设计自定义注解时,大多数人的第一反应是模仿网上常见的例子,定义一个 @AutoFill 注解,然后通过属性区分是新增还是修改操作。这确实能解决问题,但在实际项目中,我们往往需要更精细的控制。

2.1 注解的语义设计

先来看一个经过实战检验的注解设计:

package com.yourproject.common.annotation;

import java.lang.annotation.*;

/**
 * 数据操作自动填充注解
 * 用于自动填充创建人、创建时间、更新人、更新时间等通用字段
 * 
 * @author yourname
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataAutoFill {
    
    /**
     * 操作类型
     */
    OperationType value() default OperationType.AUTO;
    
    /**
     * 是否忽略填充(用于特殊场景跳过自动填充)
     */
    boolean ignore() default false;
    
    /**
     * 指定用户信息字段名(当不从SecurityContext获取时使用)
     */
    String usernameField() default "";
    
    /**
     * 操作类型枚举
     */
    enum OperationType {
        /** 自动识别(根据参数判断) */
        AUTO,
        /** 插入操作 */
        INSERT,
        /** 更新操作 */
        UPDATE,
        /** 删除操作(逻辑删除时可能需要) */
        DELETE,
        /** 批量插入 */
        BATCH_INSERT,
        /** 批量更新 */
        BATCH_UPDATE
    }
}

这个设计比简单的 add() 和 edit() 布尔值更灵活。OperationType.AUTO 让切面可以智能判断操作类型,而 ignore() 属性为特殊场景提供了逃生通道。usernameField() 则解决了某些后台任务没有登录用户上下文的问题。

2.2 注解使用的常见陷阱

第一个坑:注解放置的位置

新手最容易犯的错误就是把注解加错了地方。看下面这个例子:

@Service
public class UserServiceImpl implements UserService {
    
    @Override
    @DataAutoFill(OperationType.INSERT)
    public int saveUser(User user) {
        // 业务逻辑
        return userMapper.insert(user);
    }
    
    // 错误示例:注解加在私有方法上
    @DataAutoFill(OperationType.UPDATE)
    private void internalUpdate(User user) {
        // 内部方法
    }
}

提示:Spring AOP默认使用JDK动态代理,这意味着它只能拦截public方法。如果你把注解加在private、protected或default方法上,切面是不会生效的。如果确实需要拦截非public方法,可以考虑使用AspectJ的编译时或加载时织入。

第二个坑:嵌套调用问题

这是AOP的经典问题,也是若依项目中经常遇到的:

@Service
public class OrderServiceImpl implements OrderService {
    
    @Override
    @DataAutoFill(OperationType.INSERT)
    public int createOrder(Order order) {
        // 这里会触发自动填充
        order.setStatus("PENDING");
        int result = orderMapper.insert(order);
        
        // 嵌套调用同一个类的方法
        updateOrderLog(order.getId());  // 这里不会触发AOP!
        return result;
    }
    
    @Override
    @DataAutoFill(OperationType.UPDATE)  
    public void updateOrderLog(Long orderId) {
        // 由于是内部调用,这个注解不会生效
        // 因为Spring AOP通过代理实现,内部调用不走代理
    }
}

解决这个问题有几种方案:

  1. 将需要AOP拦截的方法抽取到另一个Service中
  2. 使用 AopContext.current
公共字段自动填充步骤及出现的问题 1. **元数据处理器未配置**:需要在实体类中使用 `@TableField` 注解的 `fill` 属性来指定字段在什么情况下自动填充,并且需要实现 `MetaObjectHandler` 接口来定义填充规则。2. **自动填充规则未正确实现**:在 `MetaObjectHandler` 实现类中,需要正确实现 `insertFill` 和 `updateFill` 方法来指定字段的填充值。7. **缓存问题**:有时候,可能是由于缓存导致自动填充没有按预期工作。我的就是更换了最新版本。 阅读详情

相关推荐

【04自定义Mybatis框架】判断用XML还是注解方式

谢谢点赞与关注 文章目录前言一、前期准备1.创建Maven工程并导入相关坐标2.将工具类导入项目中2.1.解析主配置文件(XMLConfigBuilder)2.2数据源工具类DataSourceUtil2.3执行sql工具3.编写读取配置文件类(Resource)4.编写封装查询类(Mapper)5.编写核心配置类自定义mybatis(Configuration)6.实体类(User)二、基于XML的自定义mybatis框架1.编写持久层接口和IUserDao.xml1.1接口IUserDao1.2IU.

m0_58877630的博客 271

MyBatis-Flex实战指南:告别重复SQL,掌握增强框架的优雅与避坑

MyBatis作为半自动ORM框架,赋予了开发者对SQL的完全掌控,但频繁重复的单表增删改查让XML动态SQL成为项目中最沉重的维护成本。MyBatis-Flex应运而生,作为不替换MyBatis的增强框架,它通过BaseMapper、QueryWrapper与APT编译期列常量,把常见CRUD、分页、逻辑删除、乐观锁等横切行为从手写SQL中剥离。类型安全的查询表达式使列名错误在编译期即可暴露,注解驱动的字段行为让单表操作几乎无需XML,同时保留复杂报表的手写SQL能力。在Spring Boot工程中,这类

weixin_31220401的博客 317

光模块基础知识【快速入门】02

光模块是用于交换机与设备之间传输的载体,是光纤通信系统中的核心器件。主要作用是发射端将设备的电信号转换成光信号。 光纤通道光模块和以太网光模块 光纤通道光模块 光纤通道(FC, Fiber Channel)是一种高速网络数据传输协议。光纤通道协议可以有序无损地传输原始数据,它主要用于在数据中心、电脑服务器、交换机与存储网络中进行数据传输。 FC光模块遵循FC协议,充当着光纤通道系统之间的接口,也是光纤存储网络设备间的接口。它们主要用于数据中心的光纤通道存储网络链接中。 FC光模块具有小型化和低.

Jin Hanquan的博客 3万+

uniapp自定义tabbar闪屏?3步搞定原生tabbar隐藏+自定义占位(附完整代码)

本文针对UniApp开发中自定义TabBar切换页面闪烁的痛点,提供了一套根治方案。通过隐藏原生TabBar并利用自定义组件进行视觉占位,巧妙结合原生切换的无闪烁优势与自定义设计的灵活性。文章详细解析了闪屏根源,并附上完整的page.json配置与代码实现,帮助开发者彻底解决此问题,提升小程序应用质感。

postgres8guard的博客 1531

solidworks实体显示线框

solidworks实体莫名其妙显示为有点虚的线框

qq_35858902的博客 1万+

3D Gaussian Splatting:用于实时的辐射场渲染

3D Gaussian Splatting:用于实时的辐射场渲染 3d gaussian splatting for real-time radiance field rendering

m0_51976564的博客 1万+

图解转置卷积原理

声明:本文大部分搬运自【机器学习】详解 转置卷积 (Transpose Convolution) 感谢博主花与人间事同,本人只是在博主原创文章上做补充以及添加一些自己的理解。 1 转置卷积的背景 通常,对图像进行多次卷积运算后,特征图的尺寸会不断缩小。而对于某些特定任务 (如图像分割和图像生成等),需将图像恢复到原尺寸再操作。这个将图像由小分辨率映射到大分辨率的尺寸恢复操作,称为上采样 (Upsample),如下图所示: 上采样方法有很多,详见【图像处理】详解 最近邻插值、线性插值、双线性插值、双三次插值

laonafahaodange的博客 5686

告别IMEI!手把手教你用UUID实现Android设备唯一标识(兼容Android 10-13)

本文详细探讨了在Android 10及以上版本中,如何构建合规且高可用的设备唯一标识方案以替代被限制访问的IMEI。文章深入分析了Android设备标识符的演变,并提供了基于UUID/GUID的完整实现策略,包括生成算法、多级持久化存储方案(如MediaStore)、权限处理以及版本兼容性实践,帮助开发者应对Android 10-13的隐私政策变化。

weixin_28339967的博客 576

实战案例四:Claude Code + Excel 技能处理表格数据

Excel 是商业世界中最通用的数据工具。无论是财务报表、销售数据还是项目计划,Excel 无处不在。本案例将展示如何利用 Claude Code 的 Excel 技能,自动化处理复杂的表格数据,告别繁琐的手工操作。

gaoxiang_120的专栏 475

脉冲变压器电感选型参数,结构原理,工艺与注意问题总结

脉冲变压器电感简称脉冲变压器,是一种特殊类型的变压器,主要用于处理脉冲信号。它的主要特性是能够在短时间内承受高电压和大电流。脉冲变压器主要用于开关电源、脉冲功率放大、雷达脉冲调制等领域。本文对脉冲变压器的工作原理,结构特点,工艺流程,选型参数及设计注意事项进行总结。

fydar的博客 1348

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

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

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

上一篇: Vue2 - 深入解析 vue-virtual-scroller 的长列表渲染优化机制
下一篇: 谷歌nano banana官方Prompt模板实战指南:六大风格创作全解析
人间清醒863
博客等级 码龄3年 33粉丝 1544原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值