博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Mybatis 插件实现动态设置参数
阅读量:5342 次
发布时间:2019-06-15

本文共 3402 字,大约阅读时间需要 11 分钟。

原文地址:

博客地址:

一、背景

笔者在搭建架构时,通常会利用泛型对 dao 层 和 service 层公共的代码(增删改)进行抽取,但是遇到一个尴尬的问题,就是实体类中的时间设置。

解决办法有很多,简单的方法就是在 web 层接收实体类参数后直接设置时间即可。但是,web 层理论上只是调用 service 层代码而已,设置时间的操作应该放在 service 层来实现,且设置时间又是一个简单的、重复性的操作,因此在网上查阅了一些资料,个人感觉比较友好的方式就是使用 Mybatis 插件。

本文介绍使用 Mybatis 插件动态设置参数。

二、Mybatis 插件简单介绍

Mybatis 提供 Interceptor 接口,配合 @Intercepts 注解可以拦截如下 4 个对象的方法调用:

Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)ParameterHandler (getParameterObject, setParameters)ResultSetHandler (handleResultSets, handleOutputParameters)StatementHandler (prepare, parameterize, batch, update, query)

其关系如下图:

image

解释:

1) Executor 是 Mybatis 的内部执行器,它负责调用 StatementHandler 操作数据库,并把结果集通过 ResultSetHandler 进行自动映射,另外,它还处理了二级缓存的操作。

2) StatementHandler 是 Mybatis 直接和数据库执行 sql 脚本的对象,另外,它也实现了 Mybatis 的一级缓存。

3) ParameterHandler 是 Mybatis 实现 sql 入参设置的对象。

4) ResultSetHandler 是 Mybatis 把 ResultSet 集合映射成 POJO 的接口对象。

本篇不陈述 Mybatis 的内部原理,感兴趣的读取请自行查阅相关资料。

三、案例演示

案例主要演示如何编写 Mybatis 自定义插件来实现动态设置时间参数,解决上文提到的问题。

3.1 自定义注解

@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 类型成员变量上。

@Datapublic class Category {    private Integer id;    private String name;    private String descr;    @CreateTime    private Date createTime;    @UpdateTime    private Date updateTime;}

3.2 自定义插件

/** * 自定义 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) {    }}

3.3 注册插件

通过这三个步骤就解决问题了。

四、参考资料

转载于:https://www.cnblogs.com/moonlightL/p/9177511.html

你可能感兴趣的文章
lintcode83- Single Number II- midium
查看>>
移动端 响应式、自适应、适配 实现方法分析(和其他基础知识拓展)
查看>>
selenium-窗口切换
查看>>
使用vue的v-model自定义 checkbox组件
查看>>
[工具] Sublime Text 使用指南
查看>>
Hangfire在ASP.NET CORE中的简单实现方法
查看>>
Algorithm——何为算法?
查看>>
Web服务器的原理
查看>>
小强升职计读书笔记
查看>>
常用的107条Javascript
查看>>
#10015 灯泡(无向图连通性+二分)
查看>>
忘记root密码,怎么办
查看>>
linux设备驱动归纳总结(三):1.字符型设备之设备申请【转】
查看>>
《黑客与画家》 读书笔记
查看>>
bzoj4407: 于神之怒加强版
查看>>
mysql统计一张表中条目个数的方法
查看>>
ArcGIS多面体(multipatch)解析——引
查看>>
css3渐变画斜线 demo
查看>>
JS性能DOM优化
查看>>
设计模式 单例模式 使用模板及智能指针
查看>>