公共字段自动填充,你了解吗

本文介绍了如何在MybatisPlus中利用公共字段自动填充功能简化开发,并通过ThreadLocal解决跨请求ID获取问题。通过实例展示了如何配置实体类和自定义MetaObjectHandler来实现自动填充,以及如何利用ThreadLocal存储并获取当前登录用户ID。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

🍗公共字段自动填充

  • 🥨什么是公共字段

  • 前面我们在新增员工是,需要设置创建时间,修改时间,修改人等
    而我们在编辑员工时也需要设置创建时间,修改时间,修改人等这些相同的操作    
    
  • 这些字段就属于公共字段


  • 🥨为了解决每次都要重复进行这些操作,那有没有一种快捷高效的方法来简化我们的开发呢🥪?

  • 答案是肯定的
    我们可以使用MybatisPlus提供的公共字段自动填充功能    
    

  • 🍿那如何理解MybatisPlus公共字段自动填充呢?

  • MybatisPlus公共字段自动填充就是在插入或者修改操作时,为指定字段赋予指定的值
    
  • 优点

    • 统一对公共字段处理
    • 避免了重复的代码

  • 🍿了解到上面的知识那么我们该具体如何实现呢?

  • 1.在实体类的属性上面假如@TableField,指定自动填充策略
    2.编写元数据对象处理器,在此类中统一为公共字段赋值,此类需要实现MetaObjectHandler接口    
    

  • 🥡第一步代码演示
    @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;

  • 🥡第二部代码演示
/**
 * 自定义元数据对象处理器
 */
@Component  //让Spring来处理
@Slf4j
public class MyMetaObjectHandler implements MetaObjectHandler {
    /**
     * 插入操作自动填充
     * @param metaObject
     */
    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("公共字段自动填充[insert]");
        metaObject.setValue("createTime", LocalDateTime.now());
        metaObject.setValue("updateTime",LocalDateTime.now());
        metaObject.setValue("createUser",1L);
        metaObject.setValue("updateUser",1L);
    }

    /**
     * 更新操作自动填充
     * @param metaObject
     */
    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("公共字段自动填充[update]");
        metaObject.setValue("updateTime",LocalDateTime.now());
        metaObject.setValue("updateUser",1L);
    }
}

  • 不知道大家发现一个问题没?
  • 我这个设置的ID是设的固定的,这肯定是不对的
  • 大家想一想,我们之前是怎么获取ID的?
  • 是不是通过Request.getSession.getAttritube(“employee”)通过键或者id值的
  • 但是这里没有办法得到Request
  • 所以之前的那个方法在这是失效的

  • 🥡**那么我们又该怎么解决呢?**

  • ThreadLocal
        客服端每次发送http请求,对应的服务器端都会分配一个新的线程来处理
        某些类中的方法获取到的线程是同一个线程
    

  • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sjmbM42j-1654173413602)(C:\Users\Cx_330\AppData\Roaming\Typora\typora-user-images\image-20220602194453002.png)]


  • 🥡为解决上面的问题,我们可以分三步走,这个基于我写的reggie项目演示

    1. 创建一个类 里面创建ThreadLocal 并写出get/set方法
    2. 因为在每次修改或者更新都会经过我的过滤器,所以通过过滤器可以先获取当前用户登录的id
    3. 然后到 updateFill()方法中再通过get方法获取id就可以设置了

    /**
     * 基于ThreadLocal构建工具类 用于保存和获取当前登录用户的id
     */
    public class BaseContext {
        private static ThreadLocal<Long> threadLocal= new ThreadLocal<Long>();
        public static void setCurrnetId(Long id){
            threadLocal.set(id);
        }
        public static Long getCurrentId(){
            return threadLocal.get();
        }
    }
    

            //如果需要处理 先判断登陆状态 如果已登陆 则放行
            if(request.getSession().getAttribute("employee")!=null){
    
                Long empid = (Long) request.getSession().getAttribute("employee");
                BaseContext.setCurrnetId(empid);
    
                filterChain.doFilter(request,response);
                return;
            }
    

    public void updateFill(MetaObject metaObject) {
        log.info("公共字段自动填充[update]");
        Long empId = BaseContext.getCurrentId();
        metaObject.setValue("updateTime",LocalDateTime.now());
        metaObject.setValue("updateUser",empId);
    }
在“苍穹外卖”系统中实现公共字段自动填充功能,主要依赖于 Spring AOP(面向切面编程)和自定义注解。该功能的核心思想是在执行数据库操作前,通过拦截带有特定注解的方法,使用反射机制为实体类中的公共字段自动赋值,避免在每个业务逻辑中重复编写相同的赋值代码。 ### 实现步骤如下: #### 1. 定义自定义注解 `@AutoFill` 首先创建一个自定义注解,用于标记需要进行公共字段自动填充的方法。 ```java @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface AutoFill { } ``` #### 2. 创建切面类 `AutoFillAspect` 接下来编写一个切面类,使用 Spring AOP 拦截所有被 `@AutoFill` 注解标记的方法,并在方法执行前自动填充公共字段。 ```java @Aspect @Component @Slf4j public class AutoFillAspect { /** * 定义切入点:拦截所有 service 包下的方法,并且这些方法必须有 @AutoFill 注解 */ @Pointcut("execution(* com.sky.service.*.*(..)) && @annotation(com.sky.annotation.AutoFill)") public void autoFillPointcut() {} /** * 在目标方法执行前进行公共字段填充 */ @Before("autoFillPointcut()") public void autoFill(JoinPoint joinPoint) { log.info("开始公共字段自动填充"); // 获取方法参数中的实体对象 Object[] args = joinPoint.getArgs(); if (args == null || args.length == 0) { return; } // 假设第一个参数为实体对象 Object entity = args[0]; // 使用反射设置公共字段值 try { // 获取当前登录用户ID(示例) Long currentUserId = getCurrentUserId(); // 设置更新人字段 Method setUpdateUser = entity.getClass().getMethod("setUpdateUser", Long.class); setUpdateUser.invoke(entity, currentUserId); // 设置创建人字段(如果是新增操作) Method getCreateTime = entity.getClass().getMethod("getCreateTime"); if (getCreateTime.invoke(entity) == null) { Method setCreateUser = entity.getClass().getMethod("setCreateUser", Long.class); setCreateUser.invoke(entity, currentUserId); } } catch (Exception e) { log.error("公共字段填充失败", e); } } /** * 获取当前登录用户 ID(需结合项目实际获取方式) */ private Long getCurrentUserId() { // 示例返回固定值,实际应从 ThreadLocal 或 SecurityContext 中获取 return 1L; } } ``` #### 3. 在实体类中定义公共字段 确保实体类中包含常见的公共字段,如创建时间、创建人、更新时间、更新人等,并提供相应的 getter 和 setter 方法。 ```java public class Dish { private Long id; private String name; private LocalDateTime createTime; private LocalDateTime updateTime; private Long createUser; private Long updateUser; // Getter and Setter methods } ``` #### 4. 在 Service 层方法上添加 `@AutoFill` 注解 最后,在需要自动填充公共字段的业务方法上添加 `@AutoFill` 注解,Spring AOP 将会自动拦截并执行填充逻辑。 ```java @Service public class DishService { @AutoFill public void save(Dish dish) { // 执行保存逻辑 } @AutoFill public void update(Dish dish) { // 执行更新逻辑 } } ``` --- ### 注意事项 - **ThreadLocal 用户信息**:为了获取当前登录用户的信息,通常会使用 `ThreadLocal` 来存储用户上下文,确保线程安全[^3]。 - **异常处理**:在实际部署时,应完善日志记录和异常捕获机制,确保系统的健壮性。 - **性能优化**:如果数据量较大或并发较高,可以考虑对反射操作进行缓存,提升性能。 ---
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

C_x_330

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

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

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

打赏作者

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

抵扣说明:

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

余额充值