MyBatis操作数据表时自动设置创建时间和更新时间

Coder马里奥 / 2024-06-05 / 原文

需求

     使用 MyBatis 插入或修改某条记录时,能自动设置数据表里的 create_time 和 update_time 字段,即自动给实体类对象的 createTime 和 updateTime 属性赋值。(如果使用 MyBatis-Plus,该功能很容易实现,现在针对的场景是仅使用 MyBatis)

解决方案

​    使用AOP的原理,在执行新增或修改前,用反射获取方法的第一个参数,给它的 createTime 和 updateTime 属性赋值 。(约定:方法的第一个参数是要操作的实体类)

代码

1、自定义注解:

/**
 * 标识 需要自动填充的方法
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoFill {
    OperationType value();
}

2、枚举类:指定方法类型是 insert 还是 update,insert 操作需要 同时设置 createTime 和 updateTime,update操作只设置 updateTime 。

/**
 * 操作类型
 */
public enum OperationType {
    UPDATE,
    INSERT
}

3、切面:

/**
 * 自定义切面 自动填充公共字段
 */
@Aspect
@Component
public class AutoFillAspect {

    /**
     * 切入点
     *   * com.example.mapper.*.*(..)  需要能定位到mapper接口的位置
     *   com.example.autofill.AutoFill  是上面写的自定义注解的路径
     */
    @Pointcut("execution(* com.example.mapper.*.*(..)) && @annotation(com.example.autofill.AutoFill)")
    public void autoFillPointCut() {
    }


    /**
     * 前置通知,insert update之前 填充时间
     */
    @Before("autoFillPointCut()")
    public void autoFill(JoinPoint joinPoint) throws Exception {
        //获取到当前被拦截的方法上的数据库操作类型
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();//方法签名对象
        AutoFill autoFill = signature.getMethod().getAnnotation(AutoFill.class);//获得方法上的注解对象
        OperationType operationType = autoFill.value();//获得数据库操作类型   insert  update
        // insert  update  方法参数是实体类 需要放在第一个
        // 获取实体参数对象
        Object[] args = joinPoint.getArgs();
        if (args == null || args.length == 0) {
            return;
        }
        Object entity = args[0];
        // 为 createTime 和 updateTime 属性赋值
        LocalDateTime localDateTime = LocalDateTime.now();
        if (operationType == OperationType.INSERT) {
            // insert 操作 两个时间都赋值
            Method setCreateTime = entity.getClass().getMethod(SET_CREATE_TIME, LocalDateTime.class);
            Method setUpdateTime = entity.getClass().getMethod(SET_UPDATE_TIME, LocalDateTime.class);
            setCreateTime.invoke(entity, localDateTime);
            setUpdateTime.invoke(entity, localDateTime);
        } else if (operationType == OperationType.UPDATE) {
            // update 操作 只设置更新时间
            Method setUpdateTime = entity.getClass().getMethod(SET_UPDATE_TIME, LocalDateTime.class);
            setUpdateTime.invoke(entity, localDateTime);
        }
    }
}

测试案例

实体类:

import lombok.Data;
import java.time.LocalDateTime;

@Data
public class User{
    private Long id;
    private String name;
    private LocalDateTime createTime;
    private LocalDateTime updateTime;
}

mapper接口:

/**
 * 添加用户
 */
@AutoFill(value = OperationType.INSERT)
Integer addUser(User user);

xml文件:

<insert id="addUser" parameterType="user" useGeneratedKeys="true" keyProperty="id">
    insert into user(name, create_time, update_time)
    values (#{name}, #{createTime}, #{updateTime})
</insert>

测试方法:

@Resource
private UserMapper userMapper;

void test(){
    User user = new User();
    user.setName("张三");  // 无需手动设置 createTime 和 updateTime 属性
    userMapper.addUser(user);
}