欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

使用mybatis的@Interceptor實現(xiàn)攔截sql的方法詳解

 更新時間:2024年03月26日 11:37:33   作者:健康平安的活著  
攔截器是一種基于 AOP(面向切面編程)的技術(shù),它可以在目標(biāo)對象的方法執(zhí)行前后插入自定義的邏輯,本文給大家介紹了使用mybatis的@Interceptor實現(xiàn)攔截sql的方法,需要的朋友可以參考下

一  mybatis的攔截器

1.1  攔截器介紹

攔截器是一種基于 AOP(面向切面編程)的技術(shù),它可以在目標(biāo)對象的方法執(zhí)行前后插入自定義的邏輯。

1.2  語法介紹

1.注解@Intercepts

@Intercepts({@Signature(type = StatementHandler.class, method = “prepare”, args = {Connection.class, Integer.class})}),表示在 SQL 執(zhí)行之前進(jìn)行攔截處理。

@Intercepts 的作用:聲明這是一個攔截器。

屬性:Signature(注解)

@Signature:要攔截的具體方法

? 屬性: type-攔截接口(四種類型 ),

method-攔截的方法(update,insert,select),

args-重載時根據(jù)參數(shù)列表確定要攔截的方法。

2.介紹:

Executor:攔截執(zhí)行器的方法,例如 update、query、commit、rollback 等。可以用來實現(xiàn)緩存、事務(wù)、分頁等功能。

ParameterHandler:攔截參數(shù)處理器的方法,例如 setParameters 等??梢杂脕磙D(zhuǎn)換或加密參數(shù)等功能。

ResultSetHandler:攔截結(jié)果集處理器的方法,例如 handleResultSets、handleOutputParameters 等??梢杂脕磙D(zhuǎn)換或過濾結(jié)果集等功能。

StatementHandler:攔截語句處理器的方法,例如 prepare、parameterize、batch、update、query 等。可以用來修改 SQL 語句、添加參數(shù)、記錄日志等功能。

1.3  API接口

1.intercept:主要是寫我們具體業(yè)務(wù)邏輯,比如針對增刪改sql語句添加更新日期。

2.plugin:生成代理對象

3.setProperties:設(shè)置攔截器屬性

二  實現(xiàn)案例

2.1 結(jié)構(gòu)

2.2 代碼

package com.ljf.springboot.mybaits.demos.utils;
 
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.type.TypeHandlerRegistry;
import org.springframework.stereotype.Component;
 
import java.text.DateFormat;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Properties;
 
 
/**
 * 1. 打印mysql完整的執(zhí)行語句
 * 2. 打印mysql語句執(zhí)行時間
 * 這里我們攔截Executor里面的query和update方法
 */
@Component
@Intercepts({
        @Signature(
                method = "query",
                type = Executor.class,
                args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}
        ),
        @Signature(
                type = Executor.class,
                method = "update",
                args = {MappedStatement.class, Object.class}
        )
})
public class LogInterceptor implements Interceptor {
 
    /**
     * 是否顯示語句的執(zhí)行時間
     */
    public static final String PROPERTIES_KEY_ENABLE_EXECUTOR_TIME = "enableExecutorTIme";
    public static final String ENABLE_EXECUTOR_TIME = "0"; // 顯示
 
    private boolean enableExecutorTime = false;
 
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        System.out.println("dddddd======");
        // 獲取執(zhí)行方法的MappedStatement參數(shù),不管是Executor的query方法還是update方法,第一個參數(shù)都是MappedStatement
        MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
        Object parameter = null;
        if (invocation.getArgs().length > 1) {
            parameter = invocation.getArgs()[1];
        }
        String sqlId = mappedStatement.getId();
        BoundSql boundSql = mappedStatement.getBoundSql(parameter);
        Configuration configuration = mappedStatement.getConfiguration();
        long sqlStartTime = System.currentTimeMillis();
        Object re = invocation.proceed();
        long sqlEndTime = System.currentTimeMillis();
        // 打印mysql執(zhí)行語句
        String sql = getSql(configuration, boundSql, sqlId);
        System.out.println(sql);
        // 打印mysql執(zhí)行時間
        if (enableExecutorTime) {
            String sqlTimeLog = sqlId + " 方法對應(yīng)sql執(zhí)行時間:" + (sqlEndTime - sqlStartTime) + " ms";
            System.out.println(sqlTimeLog);
        }
        return re;
    }
 
    /**
     * 通過該方法決定要返回的對象是目標(biāo)對象還是對應(yīng)的代理
     * 不要想的太復(fù)雜,一般就兩種情況:
     * <p>
     * 1. return target;  直接返回目標(biāo)對象,相當(dāng)于當(dāng)前Interceptor沒起作用,不會調(diào)用上面的intercept()方法
     * 2. return Plugin.wrap(target, this);  返回代理對象,會調(diào)用上面的intercept()方法
     *
     * @param target 目標(biāo)對象
     * @return 目標(biāo)對象或者代理對象
     */
    @Override
    public Object plugin(Object target) {
        System.out.println("==================dssssssssss");
        return Plugin.wrap(target, this);
    }
 
    /**
     * 用于獲取在Configuration初始化當(dāng)前的Interceptor時時候設(shè)置的一些參數(shù)
     *
     * @param properties Properties參數(shù)
     */
    @Override
    public void setProperties(Properties properties) {
        if (properties != null) {
            String executorTImeValue = properties.getProperty(PROPERTIES_KEY_ENABLE_EXECUTOR_TIME);
            if (executorTImeValue != null) {
                enableExecutorTime = executorTImeValue.equals(ENABLE_EXECUTOR_TIME);
            }
        }
    }
 
    private static String getSql(Configuration configuration, BoundSql boundSql, String sqlId) {
        return sqlId + " 方法對應(yīng)sql執(zhí)行語句:" + assembleSql(configuration, boundSql);
    }
 
    /**
     * 轉(zhuǎn)義正則特殊字符 ($()*+.[]?\^{}
     * \\需要第一個替換,否則replace方法替換時會有邏輯bug
     */
    private static String makeQueryStringAllRegExp(String str) {
        if (str != null && !str.equals("")) {
            return str.replace("\\", "\\\\").replace("*", "\\*")
                    .replace("+", "\\+").replace("|", "\\|")
                    .replace("{", "\\{").replace("}", "\\}")
                    .replace("(", "\\(").replace(")", "\\)")
                    .replace("^", "\\^").replace("$", "\\$")
                    .replace("[", "\\[").replace("]", "\\]")
                    .replace("?", "\\?").replace(",", "\\,")
                    .replace(".", "\\.").replace("&", "\\&");
        }
        return str;
    }
 
    /**
     * 獲取參數(shù)對應(yīng)的string值
     *
     * @param obj 參數(shù)對應(yīng)的值
     * @return string
     */
    private static String getParameterValue(Object obj) {
        String value;
        if (obj instanceof String) {
            value = "'" + obj.toString() + "'";
        } else if (obj instanceof Date) {
            DateFormat formatter = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.CHINA);
            value = "'" + formatter.format(new Date()) + "'";
        } else {
            if (obj != null) {
                value = obj.toString();
            } else {
                value = "";
            }
 
        }
        // 對特殊字符進(jìn)行轉(zhuǎn)義,方便之后處理替換
        return value != null ? makeQueryStringAllRegExp(value) : value;
    }
 
    /**
     * 組裝完整的sql語句 -- 把對應(yīng)的參數(shù)都代入到sql語句里面
     *
     * @param configuration Configuration
     * @param boundSql      BoundSql
     * @return sql完整語句
     */
    private static String assembleSql(Configuration configuration, BoundSql boundSql) {
        // 獲取mapper里面方法上的參數(shù)
        Object sqlParameter = boundSql.getParameterObject();
        // sql語句里面需要的參數(shù) -- 真實需要用到的參數(shù) 因為sqlParameter里面的每個參數(shù)不一定都會用到
        List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
        // sql原始語句(?還沒有替換成我們具體的參數(shù))
        String sql = boundSql.getSql().replaceAll("[\\s]+", " ");
        if (parameterMappings.size() > 0 && sqlParameter != null) {
            // sql語句里面的?替換成真實的參數(shù)
            TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
            if (typeHandlerRegistry.hasTypeHandler(sqlParameter.getClass())) {
                sql = sql.replaceFirst("\\?", getParameterValue(sqlParameter));
            } else {
                MetaObject metaObject = configuration.newMetaObject(sqlParameter);
                for (ParameterMapping parameterMapping : parameterMappings) {
                    // 一個一個把對應(yīng)的值替換進(jìn)去 按順序把?替換成對應(yīng)的值
                    String propertyName = parameterMapping.getProperty();
                    if (metaObject.hasGetter(propertyName)) {
                        Object obj = metaObject.getValue(propertyName);
                        sql = sql.replaceFirst("\\?", getParameterValue(obj));
                    } else if (boundSql.hasAdditionalParameter(propertyName)) {
                        Object obj = boundSql.getAdditionalParameter(propertyName);
                        sql = sql.replaceFirst("\\?", getParameterValue(obj));
                    }
                }
            }
        }
        return sql;
    }
}

2.3 驗證效果

1.請求

2.日志結(jié)果

以上就是使用mybatis的@Interceptor實現(xiàn)攔截sql的方法詳解的詳細(xì)內(nèi)容,更多關(guān)于mybatis @Interceptor攔截sql的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Springboot項目對數(shù)據(jù)庫用戶名密碼實現(xiàn)加密過程解析

    Springboot項目對數(shù)據(jù)庫用戶名密碼實現(xiàn)加密過程解析

    這篇文章主要介紹了Springboot項目對數(shù)據(jù)庫用戶名密碼實現(xiàn)加密過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-06-06
  • Java中eq、ne、ge、gt、le、lt的含義詳細(xì)解釋

    Java中eq、ne、ge、gt、le、lt的含義詳細(xì)解釋

    Java中的比較運(yùn)算符包括eq(等于)、ne(不等于)、ge(大于或等于)、gt(大于)、le(小于或等于)和lt(小于),這些運(yùn)算符在控制流語句和條件語句中用于判斷條件是否滿足,從而決定程序的執(zhí)行路徑,需要的朋友可以參考下
    2024-11-11
  • SpringBoot中的分布式追蹤及使用詳解

    SpringBoot中的分布式追蹤及使用詳解

    隨著互聯(lián)網(wǎng)應(yīng)用程序的復(fù)雜性不斷增加,分布式系統(tǒng)已經(jīng)成為了許多企業(yè)級應(yīng)用程序的標(biāo)配,由于服務(wù)之間的調(diào)用關(guān)系錯綜復(fù)雜,很難追蹤到一個請求在整個系統(tǒng)中的執(zhí)行路徑和時間,為了解決這個問題,本文將介紹SpringBoot中的分布式追蹤技術(shù)及其使用方法
    2023-07-07
  • Java實現(xiàn)PIFrame窗體效果的示例代碼

    Java實現(xiàn)PIFrame窗體效果的示例代碼

    在很多現(xiàn)代應(yīng)用中,常常需要使用個性化的窗體外觀,擺脫傳統(tǒng)窗口邊框的限制,無邊框、透明、圓角和陰影效果使得窗體顯得更輕巧、更具視覺吸引力,同時允許用戶自由拖拽和??看绑w,所以本文給大家介紹了如何使用Java實現(xiàn)PIFrame窗體效果,需要的朋友可以參考下
    2025-03-03
  • 使用自定義注解進(jìn)行restful請求參數(shù)的校驗方式

    使用自定義注解進(jìn)行restful請求參數(shù)的校驗方式

    這篇文章主要介紹了使用自定義注解進(jìn)行restful請求參數(shù)的校驗方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • Java中Map的computeIfAbsent方法詳解

    Java中Map的computeIfAbsent方法詳解

    這篇文章主要介紹了Java的Map中computeIfAbsent方法詳解,在jdk1.8中Map接口新增了一個computeIfAbsent方法,這是Map接口中的默認(rèn)實現(xiàn)該方法是首先判斷緩存Map中是否存在指定的key的值,如果不存在,會調(diào)用mappingFunction(key)計算key的value,需要的朋友可以參考下
    2023-11-11
  • IDEA切換JDK版本超詳細(xì)操作步驟記錄

    IDEA切換JDK版本超詳細(xì)操作步驟記錄

    在我們項目開發(fā)的過程中可能會遇到JDK版本過高或者過低導(dǎo)致一些程序無法啟動,不兼容的問題,所以我們需要切換JDK的版本號,這篇文章主要給大家介紹了關(guān)于IDEA切換JDK版本的超詳細(xì)操作步驟,需要的朋友可以參考下
    2024-03-03
  • 關(guān)于JwtToken使用-重點(diǎn)看一下過期時間

    關(guān)于JwtToken使用-重點(diǎn)看一下過期時間

    這篇文章主要介紹了關(guān)于JwtToken使用-重點(diǎn)看一下過期時間,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-07-07
  • 關(guān)于@SpringBootApplication詳解

    關(guān)于@SpringBootApplication詳解

    這篇文章主要介紹了關(guān)于@SpringBootApplication的使用方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • Java中SimpleDateFormat日期格式轉(zhuǎn)換詳解及代碼示例

    Java中SimpleDateFormat日期格式轉(zhuǎn)換詳解及代碼示例

    這篇文章主要介紹了Java中SimpleDateFormat日期格式轉(zhuǎn)換詳解及代碼示例,具有一定借鑒價值,需要的朋友可以參考下。
    2017-12-12

最新評論