最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

一  mybatis的攔截器

1.1  攔截器介紹

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

1.2  語法介紹

1.注解@Intercepts

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

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

屬性:Signature(注解)

@Signature:要攔截的具體方法

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

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

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

2.介紹:

Executor:攔截執(zhí)行器的方法,例如 update、query、commit、rollback 等??梢杂脕韺崿F(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;
    }
 
    /**
     * 通過該方法決定要返回的對象是目標對象還是對應(yīng)的代理
     * 不要想的太復(fù)雜,一般就兩種情況:
     * <p>
     * 1. return target;  直接返回目標對象,相當于當前Interceptor沒起作用,不會調(diào)用上面的intercept()方法
     * 2. return Plugin.wrap(target, this);  返回代理對象,會調(diào)用上面的intercept()方法
     *
     * @param target 目標對象
     * @return 目標對象或者代理對象
     */
    @Override
    public Object plugin(Object target) {
        System.out.println("==================dssssssssss");
        return Plugin.wrap(target, this);
    }
 
    /**
     * 用于獲取在Configuration初始化當前的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 = "";
            }
 
        }
        // 對特殊字符進行轉(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)的值替換進去 按順序把?替換成對應(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的方法詳解的詳細內(nèi)容,更多關(guān)于mybatis @Interceptor攔截sql的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java分布式鎖理論(redis、zookeeper))案例詳解

    Java分布式鎖理論(redis、zookeeper))案例詳解

    zookeeper有個節(jié)點路徑的概念,節(jié)點路徑不能重復(fù),保證了唯一性,這篇文章給大家介紹Java分布式鎖理論(redis、zookeeper)?案例詳解,感興趣的朋友跟隨小編一起看看吧
    2024-01-01
  • 基于Eclipce配置Spring Boot過程圖解

    基于Eclipce配置Spring Boot過程圖解

    這篇文章主要介紹了基于Eclipce配置Spring Boot過程圖解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-03-03
  • mybatis調(diào)用mysql存儲過程(返回參數(shù),單結(jié)果集,多結(jié)果集)

    mybatis調(diào)用mysql存儲過程(返回參數(shù),單結(jié)果集,多結(jié)果集)

    本文主要介紹了mybatis調(diào)用mysql存儲過程(返回參數(shù),單結(jié)果集,多結(jié)果集),文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • Java調(diào)用新浪api通過Ip查詢地區(qū)

    Java調(diào)用新浪api通過Ip查詢地區(qū)

    這篇文章主要介紹了Java調(diào)用新浪接口通過Ip查詢地區(qū),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-05-05
  • Java JSON提取工具JsonExtractor的使用

    Java JSON提取工具JsonExtractor的使用

    本文主要介紹了Java JSON提取工具JsonExtractor的使用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-05-05
  • JavaWeb 實現(xiàn)驗證碼功能(demo)

    JavaWeb 實現(xiàn)驗證碼功能(demo)

    在 WEB-APP 中一般應(yīng)用于:登錄、注冊、買某票、秒殺等場景,大家都接觸過這個驗證碼操作,今天小編通過實例代碼給大家講解javaweb實現(xiàn)驗證碼功能,需要的朋友參考下
    2017-02-02
  • 基于spring+quartz的分布式定時任務(wù)框架實現(xiàn)

    基于spring+quartz的分布式定時任務(wù)框架實現(xiàn)

    在Spring中的定時任務(wù)功能,最好的辦法當然是使用Quartz來實現(xiàn)。這篇文章主要介紹了基于spring+quartz的分布式定時任務(wù)框架實現(xiàn),有興趣的可以了解一下。
    2017-01-01
  • 聊聊Spring?Boot如何配置多個Kafka數(shù)據(jù)源

    聊聊Spring?Boot如何配置多個Kafka數(shù)據(jù)源

    這篇文章主要介紹了Spring?Boot配置多個Kafka數(shù)據(jù)源的相關(guān)知識,包括生產(chǎn)者、消費者配置,本文結(jié)合實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2023-10-10
  • java基于servlet編寫上傳下載功能 類似文件服務(wù)器

    java基于servlet編寫上傳下載功能 類似文件服務(wù)器

    這篇文章主要為大家詳細介紹了java基于servlet編寫上傳下載功能,類似文件服務(wù)器,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-07-07
  • 淺析java貪心算法

    淺析java貪心算法

    這篇文章簡單主要介紹了java貪心算法,包含貪心算法的基本思路,性質(zhì),以及實現(xiàn)示例,有需要的小伙伴參考下
    2015-02-02

最新評論

绥江县| 平定县| 凤阳县| 嘉黎县| 南投县| 伊通| 天津市| 游戏| 马公市| 谢通门县| 抚远县| 灵丘县| 西吉县| 潮安县| 普兰店市| 阳泉市| 浑源县| 廊坊市| 西宁市| 兰考县| 瑞金市| 涞水县| 龙里县| 凤台县| 边坝县| 奉化市| 神木县| 黄浦区| 太仆寺旗| 彭山县| 阜城县| 文山县| 行唐县| 沾化县| 巴彦淖尔市| 滕州市| 潞西市| 藁城市| 日照市| 双流县| 精河县|