spring boot 實現mybatis攔截器


spring boot 實現mybatis攔截器

項目是個報表系統,服務端是簡單的Java web架構,直接在請求參數里面加了個query id參數,就是mybatis mapper的query id,剛好對接接口的請求參數,沒有使用接口模式。

基於這種特性,分頁使用了PageHelper插件,但是只使用獲取指定范圍記錄這部分,查詢的總條數是自己實現的(插件的總條數,需要創建查詢對象實現),直接在查詢后多發送一次數據庫請求,使用自定義的攔截器,攔截查詢的請求(默認注入一個參數,等於指定值),在正常的SQL前后 拼接上 "select count(1) coun from (" +sql+")",直接在數據庫中,查詢結果集的條數。如下:

if ( mapParam.get("count") != null && mapParam.get("count").toString().equalsIgnoreCase("sum")) {
                // 從StatementHandler中取出查詢的SQL
                String sql = (String) metaStatementHandler.getValue("delegate.boundSql.sql");
                
                sql = "select count(1) coun from ( " + sql + " )";
                // 將修改的SQL放回StatementHandler中
                metaStatementHandler.setValue("delegate.boundSql.sql", sql);
}

mybatis的 攔截器配置如下:

<plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor">
            <!-- 支持通過Mapper接口參數來傳遞分頁參數 -->
            <property name="supportMethodsArguments" value="true"/>
            <property name="rowBoundsWithCount" value="true"/>
            <property name="reasonable" value="true"/>
        </plugin>
        <!-- mybatis寫出sql記錄控件(攔截器) -->
        <!-- 自己寫的那個攔截器 -->
        <plugin interceptor="com.xx.SqlInterceptorCount">
            <!-- 方言 -->
            <property name="dialect" value="oracle"/>
        </plugin>
        
    </plugins>

Java使用如下:

// 從數據庫查詢
result = QueryMapper.getObjFromDB(paras.get("qdi"),paras);
// 查詢當前sql 的總條數
total = QueryMapper.getQdiSum(paras.get("qdi"),paras);

查 total 的時候,給paras,默認注入一個count參數。

paras.put("count", "sum");
hashMap = (HashMap)session.selectList(qdi, paras).get(0);

用起來還是很酸爽的。

 

--------------朴素的分割線------------------

進入主題

為迎合時代的發展,領導的召喚,項目架構改版,遷入springboot,方便統一管理(監控)

程序員就開干了啊。。。

 

。。。

。。。

。。。

。。。

。。。

// 程序員揮汗如雨中

幾天后,springboot的項目開發完了,但是遇到個問題,mybatis的攔截器不生效,配置如下:

mybatis:
  mapper-locations: classpath:mapper/*.xml

事實上,並沒有配置,不過可以加個mybatis的配置文件,像這樣,如下:

mybatis:
  mapper-locations: classpath:mapper/*.xml
  configuration:
    interceptions: cn.utstarcom.statplatform7.interceptor.SqlInterceptorCount
  config-location: classpath:mybatis-config.xml

mbatis-config.xml 內容如下:

<plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor">
            <!-- 支持通過Mapper接口參數來傳遞分頁參數 -->
            <property name="supportMethodsArguments" value="true"/>
            <property name="rowBoundsWithCount" value="true"/>
            <property name="reasonable" value="true"/>
        </plugin>
        <!-- mybatis寫出sql記錄控件(攔截器) -->
        <!-- 自己寫的那個攔截器 -->
        <plugin interceptor="com..SqlInterceptorCount">
            <!-- 方言 -->
            <property name="dialect" value="oracle"/>
        </plugin>
       
    </plugins>

攔截器內容如下:

@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
public class SqlInterceptorCount implements Interceptor {

    private Logger logger = LoggerFactory.getLogger(SqlInterceptorCount.class);
    private static final ObjectFactory DEFAULT_OBJECT_FACTORY = new DefaultObjectFactory();
    private static final ObjectWrapperFactory DEFAULT_OBJECT_WRAPPER_FACTORY = new DefaultObjectWrapperFactory();
    private static final ReflectorFactory DEFAULT_REFLECTOR_FACTORY = new DefaultReflectorFactory();

    @Override
    public Object intercept(Invocation invocation) throws Throwable {

        try {
            StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
            MetaObject metaStatementHandler = MetaObject.forObject(statementHandler, DEFAULT_OBJECT_FACTORY,
                    DEFAULT_OBJECT_WRAPPER_FACTORY, DEFAULT_REFLECTOR_FACTORY);

//            HashMap mapParam = (HashMap) metaStatementHandler.getValue("delegate.boundSql.parameterObject");
            Object paramObject = metaStatementHandler.getValue("delegate.boundSql.parameterObject");
            if (paramObject instanceof Map) {
                HashMap paramMap = (HashMap)paramObject;
                if (paramMap.get("count") != null && paramMap.get("count").toString().equalsIgnoreCase("sum")) {
                    // get sql from StatementHandler
                    String sql = (String) metaStatementHandler.getValue("delegate.boundSql.sql");
                    sql = "select count(1) coun from ( " + sql + " )";
                    // set moidfy sql to StatementHandler
                    metaStatementHandler.setValue("delegate.boundSql.sql", sql);
                }
            }
        } catch (Exception e) {
            logger.error("throw exception and will not handle the mybatis sql");
        }
        // process the next query process
        return invocation.proceed();
    }

    /**
     *  
     * @param o
     * @return
     */ @Override public Object plugin(Object o) { return null; }

    @Override
    public void setProperties(Properties properties) {

    }
}

 

事實上,mybatis的配置文件和配置的 interceptions,不能使用(我當然知道是),啟動沒有問題,數據庫也可以操作,但是攔截器沒有生效

 

1、在又是一大圈的亂找,發現個說法,在攔截器上加個  @Component 注解就可以了。

然后,還是不行,這個更慘,只要查詢數據庫,都會返回個null ,又沒有報錯信息,只是個null

2、又是網上一通亂找,看到個說法:說攔截器只有 plugin方法執行了,intercept方法沒有執行

debug 一下,發現問題了,加上@Component 注解,plugin方法執行了,返回個null,知道為什么嗎,看下plugin的代碼:

@Override
    public Object plugin(Object o) {

        return null;
    }

我去

不返回null,返回什么

不返回null,返回什么

不返回null,返回什么

之后接簡單了,plugin 方法是實現 Interceptor 接口的時候,IDEA生成的方法,有個默認實現,返回null

改改:

 @Override
    public Object plugin(Object o) {

//        logger.info("Interceptor : SqlInterceptorCount is running, but this is plugin method not intercept method");
        /*
            use Intercepts annotation,intercept StatementHandler method prepare
         */
        if (o instanceof StatementHandler) { return Plugin.wrap(o, this); } return o;
    }

在傳入對象是 STATEMENTHandler的對象的時候,把方法轉發到intercept 方法,攔截器可以正常執行了。

 

結論就是:

  springboot下的mybatis攔截器,和單獨用mybatis的攔截器一樣,但是不需要配置,直接在攔截器前面加個@Component 注解,在plugin 方法中將請求轉發到intercept方法攔截即可,不需要其他配置。

完整代碼如下:

 

@Component
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
public class SqlInterceptorCount implements Interceptor {

    private Logger logger = LoggerFactory.getLogger(SqlInterceptorCount.class);
    private static final ObjectFactory DEFAULT_OBJECT_FACTORY = new DefaultObjectFactory();
    private static final ObjectWrapperFactory DEFAULT_OBJECT_WRAPPER_FACTORY = new DefaultObjectWrapperFactory();
    private static final ReflectorFactory DEFAULT_REFLECTOR_FACTORY = new DefaultReflectorFactory();

    @Override
    public Object intercept(Invocation invocation) throws Throwable {

        try {
            StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
            MetaObject metaStatementHandler = MetaObject.forObject(statementHandler, DEFAULT_OBJECT_FACTORY,
                    DEFAULT_OBJECT_WRAPPER_FACTORY, DEFAULT_REFLECTOR_FACTORY);

//            HashMap mapParam = (HashMap) metaStatementHandler.getValue("delegate.boundSql.parameterObject");
            Object paramObject = metaStatementHandler.getValue("delegate.boundSql.parameterObject");
            if (paramObject instanceof Map) {
                HashMap paramMap = (HashMap)paramObject;
                if (paramMap.get("count") != null && paramMap.get("count").toString().equalsIgnoreCase("sum")) {
                    // get sql from StatementHandler
                    String sql = (String) metaStatementHandler.getValue("delegate.boundSql.sql");
                    sql = "select count(1) coun from ( " + sql + " )";
                    // set moidfy sql to StatementHandler
                    metaStatementHandler.setValue("delegate.boundSql.sql", sql);
                }
            }
        } catch (Exception e) {
            logger.error("throw exception and will not handle the mybatis sql");
        }
        // process the next query process
        return invocation.proceed();
    }

    /**
     *  
     * @param o
     * @return
     */
     @Override
    public Object plugin(Object o) {

//        logger.info("Interceptor : SqlInterceptorCount is running, but this is plugin method not intercept method");
        /*
            use Intercepts annotation,intercept StatementHandler method prepare
         */
        if (o instanceof StatementHandler) { return Plugin.wrap(o, this); } return o;
    }

    @Override
    public void setProperties(Properties properties) {

    }
}

 


免責聲明!

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



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