Mybatis 插件實現動態設置參數


原文地址:Mybatis 插件實現動態設置參數
博客地址:http://www.extlight.com

一、背景

筆者在搭建架構時,通常會利用泛型對 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 類型成員變量上。

@Data
public 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 注冊插件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <settings>
        <!-- 獲取數據庫自增主鍵值 -->
        <setting name="useGeneratedKeys" value="true"/>
        <!-- 使用列別名替換列名,默認為 true -->
        <setting name="useColumnLabel" value="true"/>
        <!-- 開啟駝峰命名轉換:Table(create_time) => Entity(createTime) -->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>

    <plugins>
        <plugin interceptor="com.extlight.plugin.CustomInterceptor">
        </plugin>
    </plugins>
</configuration>

通過這三個步驟就解決問題了。

四、參考資料


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM