4趋箩、mybatis(oracle分頁)分頁攔截器

接上一節(jié),增加一個(gè)分頁攔截器來實(shí)現(xiàn)dao層的分頁邏輯
攔截器就是在不改變源碼的情況下谐算,改變mybatis源碼的一些行為。在sql語句執(zhí)行之前归露,把普通sql語句換成分頁語句即可洲脂。

分析:怎樣攔截
(1)確定攔截對象:
a: 確定什么樣的攔截對象---后綴為Page的方法
b: 攔截對象什么行為---需要分頁操作
c: 什么時(shí)候攔截---在mybatis執(zhí)行sql語句之前攔截,準(zhǔn)確點(diǎn)是獲取statement之前剧包,在mybatis的源碼中
(2)攔截下來做什么事:代替某個(gè)方法完成分頁功能恐锦,改進(jìn)原始的查詢語句
(3)攔截結(jié)束,交回主權(quán)

做這個(gè)攔截器之前疆液,復(fù)習(xí)了一下動態(tài)代理一铅。我們的目的是在分頁sql執(zhí)行之前加上我們自己的分頁邏輯,而且多次用到分頁堕油,所以用動態(tài)代理非常合適潘飘。此處我們的PageInterceptor 就是自定義的執(zhí)行邏輯肮之,其他工作交給jdk的Proxy,讓它生成代理類卜录,讓代理類執(zhí)行分頁戈擒。

例子中mybatis版本3.4.0

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Map;
import java.util.Properties;

import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
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 org.apache.ibatis.reflection.DefaultReflectorFactory;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;


/**
*@Component: 注入到spring boot容器中
 * @Intercepts分頁攔截器,type:要攔截的類的class對象暴凑,method:要攔截的方法峦甩,args:方法的參數(shù)
 */
@Component
@Intercepts({@Signature(type=StatementHandler.class,method="prepare",args={Connection.class, Integer.class})})
public class PageInterceptor implements Interceptor {
    
    private String test;
    
    private final static Logger logger = LoggerFactory.getLogger(PageInterceptor.class);
    
    // 攔截實(shí)現(xiàn)
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        StatementHandler statementHandler = (StatementHandler)invocation.getTarget();
        // 對statementHandler進(jìn)行封裝
        MetaObject metaObject = MetaObject.forObject(statementHandler, SystemMetaObject.DEFAULT_OBJECT_FACTORY, 
                SystemMetaObject.DEFAULT_OBJECT_WRAPPER_FACTORY, new DefaultReflectorFactory());
        MappedStatement mappedStatement = (MappedStatement)metaObject.getValue("delegate.mappedStatement");
        // 配置文件中SQL語句的ID
        String id = mappedStatement.getId();
        if(id.matches(".+Page$")) {
            BoundSql boundSql = statementHandler.getBoundSql();
            // 原始的SQL語句
            String sql = boundSql.getSql();
            logger.info("原始sql:" + sql);
            // 查詢總條數(shù)的SQL語句
            String countSql = "select count(*) from (" + sql + ")a";
            logger.info("查詢總條數(shù)sql:" + countSql);
            Connection connection = (Connection)invocation.getArgs()[0];
            PreparedStatement countStatement = connection.prepareStatement(countSql);
            ParameterHandler parameterHandler = (ParameterHandler)metaObject.getValue("delegate.parameterHandler");
            parameterHandler.setParameters(countStatement);
            ResultSet rs = countStatement.executeQuery();
            
            Map<?,?> parameter = (Map<?,?>)boundSql.getParameterObject();
            Page page = (Page)parameter.get("page");
            if(rs.next()) {
                page.setTotalNumber(rs.getInt(1));
            }
            // 改造后帶分頁查詢的SQL語句
//          String pageSql = sql + " limit " + page.getDbIndex() + "," + page.getDbNumber();
            String pageSql = "select * from (select t1.*, rownum rn from (" + sql + 
                    ") t1 ) t2 where rn > " + page.getDbIndex() +" and rn <= " + page.getDbEnd();
            logger.info("分頁sql:" + pageSql);
            metaObject.setValue("delegate.boundSql.sql", pageSql);
        }
        return invocation.proceed();
    }

    @Override
    public Object plugin(Object target) {
        logger.info(this.test);
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
    }
}

mybatis源碼說明:target被代理對象,Plugin.wrap(target, this)返回的是動態(tài)生成的代理對象

Paste_Image.png

getSignatureMap(interceptor):通過注解獲取要攔截的類现喳,方法等凯傲。

Paste_Image.png

先通過setProperties拿到配置文件里的屬性值,再通過plugin方法對攔截的對象進(jìn)行過濾嗦篱,最后通過intercept方法執(zhí)行攔截的邏輯冰单。

Paste_Image.png
Paste_Image.png
Paste_Image.png
Paste_Image.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市灸促,隨后出現(xiàn)的幾起案子诫欠,更是在濱河造成了極大的恐慌,老刑警劉巖浴栽,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件荒叼,死亡現(xiàn)場離奇詭異,居然都是意外死亡典鸡,警方通過查閱死者的電腦和手機(jī)被廓,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來萝玷,“玉大人嫁乘,你說我怎么就攤上這事∏虻铮” “怎么了蜓斧?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長睁冬。 經(jīng)常有香客問我挎春,道長,這世上最難降的妖魔是什么痴突? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任搂蜓,我火速辦了婚禮,結(jié)果婚禮上辽装,老公的妹妹穿的比我還像新娘帮碰。我一直安慰自己,他們只是感情好拾积,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布殉挽。 她就那樣靜靜地躺著丰涉,像睡著了一般。 火紅的嫁衣襯著肌膚如雪斯碌。 梳的紋絲不亂的頭發(fā)上一死,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天,我揣著相機(jī)與錄音傻唾,去河邊找鬼投慈。 笑死,一個(gè)胖子當(dāng)著我的面吹牛冠骄,可吹牛的內(nèi)容都是我干的伪煤。 我是一名探鬼主播,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼凛辣,長吁一口氣:“原來是場噩夢啊……” “哼抱既!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起扁誓,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤防泵,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后蝗敢,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體捷泞,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年寿谴,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了肚邢。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,059評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡拭卿,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出贱纠,到底是詐尸還是另有隱情峻厚,我是刑警寧澤,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布谆焊,位于F島的核電站惠桃,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏辖试。R本人自食惡果不足惜辜王,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望罐孝。 院中可真熱鬧呐馆,春花似錦、人聲如沸莲兢。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至收班,卻和暖如春坟岔,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背摔桦。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工社付, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人邻耕。 一個(gè)月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓鸥咖,卻偏偏與公主長得像,于是被迫代替她去往敵國和親赊豌。 傳聞我的和親對象是個(gè)殘疾皇子扛或,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 1. 簡介 1.1 什么是 MyBatis ? MyBatis 是支持定制化 SQL碘饼、存儲過程以及高級映射的優(yōu)秀的...
    笨鳥慢飛閱讀 5,426評論 0 4
  • 1熙兔、#{}和${}的區(qū)別是什么?注:這道題是面試官面試我同事的艾恼。 答:${}是Properties文件中的變量占位...
    小沙鷹168閱讀 2,226評論 2 65
  • 記錄是一種精神住涉,是加深理解最好的方式之一。 最近看了下Mybatis的源碼钠绍,分析了Mybatis插件的實(shí)現(xiàn)方式舆声,在...
    曹金桂閱讀 17,836評論 15 52
  • 無聊的日子,本應(yīng)奮斗的青春確荒廢在了大學(xué)的殿堂
    我只想靜靜的一個(gè)人閱讀 196評論 0 1