mybaits攔截器+自定義註解

来源:https://www.cnblogs.com/qingfengsuixin/archive/2019/03/26/10598394.html
-Advertisement-
Play Games

實現目的:為了存儲了公共字典表主鍵的其他表在查詢的時候不用關聯查詢(所以攔截位置位於mybaits語句查詢得出結果集後) 項目環境 :springboot+mybaits 實現步驟:自定義註解——自定義實現mybaits攔截器——註冊mybaits攔截器 一、自定義註解 1.1 代碼示例 @Targ ...


實現目的:為了存儲了公共字典表主鍵的其他表在查詢的時候不用關聯查詢(所以攔截位置位於mybaits語句查詢得出結果集後)

項目環境 :springboot+mybaits

實現步驟:自定義註解——自定義實現mybaits攔截器——註冊mybaits攔截器

一、自定義註解

1.1  代碼示例

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.FIELD})//
@Retention(RetentionPolicy.RUNTIME)//該註解不僅被保存到class文件中,jvm載入class文件之後,仍然存在;
@Inherited//允許子類繼承父類的註解。 (子類中可以獲取並使用父類註解)
@Documented//指明修飾的註解,可以被例如javadoc此類的工具文檔化,只負責標記,沒有成員取值。
/**
* 該自定義註解用於所查詢語句中欄位包含字典表主鍵 並需要將主鍵同時對照成字典表對應的名稱
* 將該註解放置在名稱列,參數為字典表主鍵存儲列的名字
* @ClassName: DictReplace 
* 描述: TODO  用於字典名稱欄位預設為空,則空則認為字典id欄位名為 字典名稱字典.substring(0,length()-4) 若不為空則認定字典id欄位名稱為參數值
* 作者cy
* 時間 2019年3月26日 上午9:02:47 
*
*/
public @interface DictReplace {

String dictIdFieldName() default "";    

}

@Target 註解

功能:指明瞭修飾的這個註解的使用範圍,即被描述的註解可以用在哪裡。

ElementType的取值包含以下幾種: 

  • TYPE:類,介面或者枚舉
  • FIELD:域,包含枚舉常量
  • METHOD:方法
  • PARAMETER:參數
  • CONSTRUCTOR:構造方法
  • LOCAL_VARIABLE:局部變數
  • ANNOTATION_TYPE:註解類型
  • PACKAGE:包

@Retention 註解

功能:指明修飾的註解的生存周期,即會保留到哪個階段。

RetentionPolicy的取值包含以下三種:

  • SOURCE:源碼級別保留,編譯後即丟棄。
  • CLASS:編譯級別保留,編譯後的class文件中存在,在jvm運行時丟棄,這是預設值。
  • RUNTIME: 運行級別保留,編譯後的class文件中存在,在jvm運行時保留,可以被反射調用。

@Documented 註解

功能:指明修飾的註解,可以被例如javadoc此類的工具文檔化,只負責標記,沒有成員取值。

@Inherited註解

功能:允許子類繼承父類中的註解。

 

1.2  使用場景

        @TableField("runtime_platform")
        private Integer runtimePlatform;
        
        @DictReplace//字典替換註解
        @TableField(exist = false)        
        private String runtimePlatformName;        

 

 

二、自定義mybaits攔截器並註冊

  2.1  代碼示例

 

import java.util.List;
import java.util.Properties;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import com.msunsoft.base.common.factory.ConstantFactory;
import com.msunsoft.base.common.interceptor.annotation.DictReplace;
import com.msunsoft.base.spring.SpringContextHolder;
import com.msunsoft.base.util.ToolUtil;
import org.apache.ibatis.executor.resultset.ResultSetHandler;
import java.lang.reflect.Field;
import java.sql.Statement;
/**
 * 字典替換攔截器,當註解方法被執行後攔截並修改查詢後的結果
* @ClassName: DictReplaceInteceptor 
* 描述: TODO
* 作者
* 時間 2019年3月25日 下午7:23:41 
*
 */
@Intercepts({    
    @Signature(type = ResultSetHandler.class,method = "handleResultSets", args = { Statement.class }) 
    })  
public class DictReplaceInteceptor implements Interceptor{
    private Properties properties; 
    private SpringContextHolder spring;//實現  ApplicationContextAware 介面的類包含獲取spring容器中的bean的靜態方法    
    
    @Override
    @SuppressWarnings(value = {"all"})
    public Object intercept(Invocation invocation) throws Throwable {
            //因為 handleResultSets  方法執行結束後可以收到一個list類型的數據結果集,所以雖然該方法的目的是用於結束本次攔截,執行預定方法(handleResultSets)方便下次攔截
            List<Object> results = (List<Object>)invocation.proceed();
            try{
          //自定義方法用於判斷對象是否為空
if(ToolUtil.isNotEmpty(results)){
            //ConstantFactory 是自定義的包含常用方法的一個類,現在用到的是它包含在其中的通過字典主鍵獲取字典名稱的方法 ConstantFactory constantFactory
= spring.getBean(ConstantFactory.class); Class<?> cls = results.get(0).getClass(); Field[] fields = cls.getDeclaredFields();// 獲取private修飾的成員變數 獲得某個類的所有聲明的欄位,即包括public、private和proteced,但是不包括父類的申明欄位。 for(Object result:results){ for (Field field : fields) { //獲取我們自定義的註解 DictReplace dictReplace = field.getAnnotation(DictReplace.class); if(dictReplace!=null){//如果存在這個註解 我們在執行後續方法 String dictIdFieldName = dictReplace.dictIdFieldName();//獲取註解屬性值 Field idField = null; if(ToolUtil.isNotEmpty(dictIdFieldName)){ idField = cls.getDeclaredField(dictIdFieldName);//獲取實體類對應欄位 }else{ String fieldName = field.getName();//獲取實體類欄位名稱 String idFieldName = fieldName.substring(0,fieldName.length()-4); idField = cls.getDeclaredField(idFieldName); } idField.setAccessible(true);//允許我們在用反射時訪問私有變數 Object dictId = idField.get(result);//從返回值中獲得欄位對應的 值 field.setAccessible(true); if(ToolUtil.isNotEmpty(dictId)){ field.set(result, constantFactory.getDictName( Long.valueOf(new String(dictId.toString())) ) ); //用字典id查詢出字典名稱 並替換結果集中的值 } } } } } }catch (Exception e) { e.printStackTrace(); }finally{ return results; } } @Override public Object plugin(Object target) { // 讀取@Signature中的配置,判斷是否需要生成代理類 if (target instanceof ResultSetHandler) { return Plugin.wrap(target, this);//返回代理 } else { return target; } } @Override public void setProperties(Properties properties) { this.properties = properties; } }

 

   2.2  攔截器部分知識點

  2.1.1  MyBatis 允許你在已映射語句執行過程中的某一點進行攔截調用。預設情況下,MyBatis 允許使用插件來攔截的方法調用包括:

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

  2.1.2  MyBatis攔截器的介面定義

    一共有三個方法intercept 、plugin 、setProperties

    setProperties()

    方法主要是用來從配置中獲取屬性。

    plugin()

    方法用於指定哪些方法可以被此攔截器攔截。

       intercept()

    方法是用來對攔截的sql進行具體的操作。

    註解實現

    MyBatis攔截器用到了兩個註解:@Intercepts@Signature

@Intercepts(
        {
                @Signature(type = Executor.class, method = "query",
                        args = {MappedStatement.class, Object.class,
                                RowBounds.class, ResultHandler.class}),
                @Signature(type = Executor.class, method = "query",
                        args = {MappedStatement.class, Object.class, RowBounds.class,
                                ResultHandler.class, CacheKey.class, BoundSql.class}),
        }
)

  type的值與類名相同,method與方法名相同,為了避免方法重載,args中指定了各個參數的類型和個數,可通過invocation.getArgs()獲取參數數組。

   2.1.3  Spring Boot整合

   方法一   

    如果是使用xml式配置攔截器,可在Mybatis配置文件中添加如下節點,屬性可以以如下方式傳遞

<plugins>
    <plugin interceptor="tk.mybatis.simple.plugin.XXXInterceptor">
        <property name="propl" value="valuel" />
        <property name="prop2" value="value2" />
    </plugin>
</plugins>

  方法二  

    如果在Spring boot中使用,則需要單獨寫一個配置類,如下:

@Configuration
public class MybatisInterceptorConfig {
    @Bean
    public String myInterceptor(SqlSessionFactory sqlSessionFactory) {
        ExecutorInterceptor executorInterceptor = new ExecutorInterceptor();
        Properties properties = new Properties();
        properties.setProperty("prop1","value1");
        executorInterceptor.setProperties(properties);
        return "interceptor";
    }
}

  OR

import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.msunsoft.base.common.interceptor.mybaits.DictReplaceInteceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@Configuration
@EnableTransactionManagement
@MapperScan("com.msunsoft.**.mapper")//Mapper介面掃描
public class DataSourceConfig {
    /**
     * 樂觀鎖mybatis插件
     */
   @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor() {
        return new OptimisticLockerInterceptor();
    }

    /**
     * mybatis-plus分頁插件
     */
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        return new PaginationInterceptor();
    }
    
    @Bean
    public DictReplaceInteceptor dictReplaceInteceptor(){
        return new DictReplaceInteceptor();
    }

}

  方法三

    在攔截器上加@Component註解

 

ps:

一、引用並參考

1.《深入理解mybatis原理》 MyBatis的架構設計以及實例分析

  https://blog.csdn.net/luanlouis/article/details/40422941      

2.關於mybatis攔截器,對結果集進行攔截

  https://www.cnblogs.com/SmallHan/articles/8127327.html

3.Springboot2(22)Mybatis攔截器實現

  https://blog.csdn.net/cowbin2012/article/details/85256360

二、涉及技術點

spring(註解、AOP) ,java反射與動態代理,mybaits(以上代碼示例用的是mybaits-Plus 3.0.6.jar),

 

 

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Spring ioc 叫控制反轉,也就是把創建Bean的動作交給Spring去完成。 spring ioc 流程大致為 定位-> 載入->註冊 先說幾個比較有意思的點 1.Spring中的通過IOC生成的Bean是存放在ConcurrentHashMap中的 2.通過xml配置SpringBean時 ...
  • 一、python中如何創建類? 1. 直接定義類 2. 通過type對象創建 在python中一切都是對象 在上面這張圖中,A是我們平常在python中寫的類,它可以創建一個對象a。其實A這個類也是一個對象,它是type類的對象,可以說type類是用來創建類對象的類,我們平常寫的類都是type類創建 ...
  • 題意 "題目鏈接" 題目鏈接 一種做法是直接用歐拉降冪算出$2^p \pmod{p 1}$然後矩陣快速冪。 但是今天學習了一下二次剩餘,也可以用通項公式+二次剩餘做。 就是我們猜想$5$在這個模數下有二次剩餘,拉個板子發現真的有。 然求出來直接做就行了 cpp include define Pair ...
  • 前幾天工作忙得焦頭爛額時,同事問了一下關於Map的特性,剎那間懵了一下,緊接著就想起來了一些關於Map的一些知識,因為只要涉及到Collection集合類時,就會談及Map類,因此理解好Map相關的知識是灰常重要的。 Collection集合類 與 Map類的層次結構,如下圖: Map是用來存儲 K ...
  • Mybatis-持久層的框架,功能是非常強大的,對於移動互聯網的高併發 和 高性能是非常有利的,相對於Hibernate全自動的ORM框架,Mybatis簡單,易於學習,sql編寫在xml文件中,和代碼分離,易於維護,屬於半ORM框架,對於面向用戶層面的互聯網業務性能和併發,可以通過sql優化解決一 ...
  • 題目: 給定一個單鏈表 L​1​​→L​2​​→⋯→L​n−1​​→L​n​​,請編寫程式將鏈表重新排列為 L​n​​→L​1​​→L​n−1​​→L​2​​→⋯。例如:給定L為1→2→3→4→5→6,則輸出應該為6→1→5→2→4→3。 輸入格式: 每個輸入包含1個測試用例。每個測試用例第1行給出 ...
  • java方法返回值與參數 例: public void a(int c){ //void 說明此方法沒有返回值,括弧里的叫參數,有數據類型和變數名組成,在方法里叫做形式參數簡稱形參。 } public int a(){ //這裡說明返回值是int整型,4位元組。 //返回關鍵字是return retu ...
  • 一、分散式鎖背景 a、什麼是鎖? 從使用場景定義:當存在多個線程可以同時改變某個變數時,就需要對變數或代碼塊做同步,使其在修改這種變數時能夠線性執行消除併發修改變數。 鎖的實現方式有多種,只要能滿足所有線程都能看得到這個鎖標記即可。 Java中常見的鎖: synchronized Reentrant ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...