MyBatis 拦截器 - 自动设置时间

更多MyBatis实战内容,请参考:MyBatis - 实战指南

1. 场景

在设计数据库字段时,往往会有表示创建时间或者更新时间的字段,假如名字分别叫create_timeupdate_time。如果在每个表的insert或update时,都要手动设置这些字段,则会很麻烦。

通过MyBatis拦截器,就可省去这些重复的步骤。拦截器能帮我们自动设置时间。

2. 实现方法

固定字段

假如说,数据库只管的每个table中,创建和更新时间都是一样的,这样是最方便的,也比较统一。

针对这种情况,可以直接写个通用的拦截器:

@Intercepts({
        @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})
})
public class CustomInterceptor implements Interceptor {
    private static final Logger LOGGER = LoggerFactory.getLogger(EnvInterceptor.class);

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
        Object object = invocation.getArgs()[1];
        //sql类型
        SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();
        if (SqlCommandType.INSERT.equals(sqlCommandType)) {
            //插入操作时,自动插入env
            Field fieldCreate = object.getClass().getDeclaredField("create_time");
            fieldCreate.setAccessible(true);
            fieldCreate.set(object, new Date());
        }else{
            if (SqlCommandType.UPDATE.equals(sqlCommandType)) {
                //update时,自动更新updated_at
                Field fieldUpdate = object.getClass().getDeclaredField("updated_time");
                fieldUpdate.setAccessible(true);
                fieldUpdate.set(object, new Date());
            }
        }
        return invocation.proceed();
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {

    }
}

注解形式

首先,实现自定义注解:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface CreateTime {

    String value() default "";
}

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface UpdateTime {

    String value() default "";
}

然后将自定义注解添加到对应的Date类型字段上:

@Data
public class Category {

    private Integer id;

    private String name;

    private String descr;

    @CreateTime
    private Date createTime;

    @UpdateTime
    private Date updateTime;

}

实现自定义插件:

/**
 * 自定义 Mybatis 插件,自动设置 createTime 和 updatTime 的值。
 * 拦截 update 操作(添加和修改)  
 */
@Intercepts({ @Signature(type = Executor.class, method = "update", args = { MappedStatement.class, Object.class }) })
public class CustomInterceptor implements Interceptor {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @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();

        for (Field field : declaredFields) {
            if (field.getAnnotation(CreateTime.class) != null) {
                if (SqlCommandType.INSERT.equals(sqlCommandType)) { // insert 语句插入 createTime
                    field.setAccessible(true);
                    field.set(parameter, new Date());
                }
            }

            if (field.getAnnotation(UpdateTime.class) != null) { // insert 或 update 语句插入 updateTime
                if (SqlCommandType.INSERT.equals(sqlCommandType) || SqlCommandType.UPDATE.equals(sqlCommandType)) {
                    field.setAccessible(true);
                    field.set(parameter, new Date());
                }
            }
        }

        return invocation.proceed();
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
    }
}

原理是:

  1. Object parameter = invocation.getArgs()[1]; 获取执行对象
  2. 通过反射获取对象所有的Field
  3. 遍历所有Field,查看是否有指定注解
  4. 如果有@CreateTime或者@UpdateTime注解,则设置最新时间

注册拦截器

最后,需要将拦截器注册到插件中




    
        
        
    

你可能感兴趣的:(MyBatis 拦截器 - 自动设置时间)