基于Mybatis-Plus实现自动化操作创建时间和修改时间 - caijwjava的博客 - CSDN博客

引入

在实际开发中,总会避免不了操作数据库,而在数据库中每个表都会有create_timeupdate_time字段记录操作时间,我们在操作这两个时间的时候也可能会出现不一致的情况,或者说这两个字段实际上应该是系统生成的,而不是用户去手动处理,于是想着在新增和修改操作的时候能让系统自动处理这两个字段。

实战

1.导入pom文件

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.4.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.1.1</version>
        </dependency>
        <!--        <dependency>-->
        <!--            <groupId>org.mybatis.spring.boot</groupId>-->
        <!--            <artifactId>mybatis-spring-boot-starter</artifactId>-->
        <!--            <version>2.0.1</version>-->
        <!--        </dependency>-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

注意
1.1.实现代码中是基于Mybatis-plus实现;
1.2.如果不使用Mybatis-Plus可以使用注释掉的依赖

2.实现SQL拦截器

@Intercepts(value = {@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})})
public class SqlInterceptor extends AbstractSqlParserHandler implements Interceptor {

    /**
     * 创建时间
     */
    private static final String CREATE_TIME = "createTime";
    /**
     * 更新时间
     */
    private static final String UPDATE_TIME = "updateTime";

    @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();
        if (parameter.getClass().getSuperclass() != null) {
            Field[] superField = parameter.getClass().getSuperclass().getDeclaredFields();
            declaredFields = ArrayUtils.addAll(declaredFields, superField);
        }
        // mybatis plus判断
        boolean plus= parameter.getClass().getDeclaredFields().length == 1 && parameter.getClass().getDeclaredFields()[0].getName().equals("serialVersionUID");

        //兼容mybatis plus
        if (plus) {
            Map<String, Object> updateParam = (Map<String, Object>) parameter;
            Class<?> updateParamType = updateParam.get("param1").getClass();
            declaredFields = updateParamType.getDeclaredFields();
            if (updateParamType.getSuperclass() != null) {
                Field[] superField = updateParamType.getSuperclass().getDeclaredFields();
                declaredFields = ArrayUtils.addAll(declaredFields, superField);
            }
        }
         String fieldName = null;
        for (Field field : declaredFields) {
           fieldName = field.getName();
            if (Objects.equals(CREATE_TIME, fieldName)) {
                if (SqlCommandType.INSERT.equals(sqlCommandType)) {
                    field.setAccessible(true);
                    field.set(parameter, new Timestamp(System.currentTimeMillis()));
                }
            }
            if (Objects.equals(UPDATE_TIME, fieldName)) {
                if (SqlCommandType.INSERT.equals(sqlCommandType) || SqlCommandType.UPDATE.equals(sqlCommandType)) {
                    field.setAccessible(true);
                    //兼容mybatis plus的update
                    if (plus) {
                        Map<String, Object> updateParam = (Map<String, Object>) parameter;
                        field.set(updateParam.get("param1"), new Timestamp(System.currentTimeMillis()));
                    } else {
                        field.set(parameter, new Timestamp(System.currentTimeMillis()));
                    }
                }
            }
        }
        return invocation.proceed();
    }
    
    @Override
    public Object plugin(Object target) {
        if (target instanceof Executor) {
            return Plugin.wrap(target, this);
        }
        return target;
    }

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

注意
2.1.这里写死了CREATE_TIMEUPDATE_TIME 也是遵循约定大于配置的原则,而不需要再写例如字段上增加上增加注解之类的方式实现,让用户使用更加简洁。
2.2.这里继承了Mybatis-Plus中AbstractSqlParserHandler 就可以不用自己重复造轮子去解析SQL,如果不是使用Mybatis-Plus则只需要直接实现Mybatis中的Interceptor 接口,自己实现SQL拦截解析即可。

3.注入自定义SQL拦截器

@Configuration
@MapperScan(value = "com.xx.mapper")
public class MybatisPlusConfig {
    @Bean
    public SqlInterceptor sqlInterceptor() {
        return new SqlInterceptor();
    }
}

注意
3.1.如果想要让自定义的SQL拦截器生效,那么这一步必须有,即注入SqlInterceptor

4.工具类

public class ArrayUtils {

    /**
     * 两个数组相加
     * @param target
     * @param source
     * @return 相加后新的数组集合
     */
    public static Field[] addAll(Field[] target, Field[] source) {
        if (target != null) {
            List<Field> fieldTarget = Stream.of(target).collect(Collectors.toList());
            if (source != null) {
                List<Field> fieldsSource = Stream.of(source).collect(Collectors.toList());
                for (Field field : fieldsSource) {
                    fieldTarget.add(field);
                }
            }
            target = fieldTarget.toArray(new Field[fieldTarget.size()]);
            return target;
        }
        return target;
    }
}

总结

1.导入pom文件,引入相关依赖;
2.继承Mybatis-Plus中AbstractSqlParserHandler 抽象类,实现Mybatis的Interceptor接口,在对象转换成SQL之前赋指定的字段值;
3.想要自定义的SQL拦截器生效,那么就需要注入自定义SQL拦截器。


Original url: Access
Created at: 2019-08-13 19:01:09
Category: default
Tags: none

请先后发表评论
  • 最新评论
  • 总共0条评论