MyBatis Interceptor修改SQL

背景:需要分表的情況下 不借助中間件 如何實(shí)現(xiàn)管理后臺(tái)頁(yè)面的多表聚合查詢爵憎?

想法是通過mybatis 提供的攔截器 重寫sql


package com.jdh.general.config;

import com.baomidou.mybatisplus.extension.handlers.AbstractSqlParserHandler;
import com.jdh.general.common.annotation.CallWhen;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.logging.Log;
import org.apache.ibatis.logging.LogFactory;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

/**
 * 單庫(kù)分表 做聚合查詢 攔截器
 *
 * @author hubin
 * @since 2016-08-16
 */
@EqualsAndHashCode(callSuper = true)
@Data
@Accessors(chain = true)
@Intercepts({@Signature(type = Executor.class, method = "query",
        args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})})
public class SimpleUnionQuery extends AbstractSqlParserHandler implements Interceptor {


    @SuppressWarnings("unused")
    private static final Log logger = LogFactory.getLog(SimpleUnionQuery .class);

    private Properties properties;


    final static String _FROM = " FROM ";
    final static String _WHERE = " WHERE ";
    final static String _LIMIT = " LIMIT ";

    /**
     * intercept 方法用來對(duì)攔截的sql進(jìn)行具體的操作
     *
     * @param invocation
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Invocation invocation) throws Throwable {

        Method method = invocation.getMethod();
        //由自定義注解配置
        CallWhen annotation = method.getAnnotation(CallWhen.class);
        ArrayList<String> tableNums = new ArrayList<>();
        tableNums.add("_1");
        tableNums.add("_2");


        Object[] args = invocation.getArgs();
        MappedStatement ms = (MappedStatement) args[0];
        Object parameterObject = args[1];
        BoundSql boundSql = ms.getBoundSql(parameterObject);
        String origSql = boundSql.getSql();

        //多少個(gè)union all 表構(gòu)建多少次參數(shù)
        List<ParameterMapping> tempParam = boundSql.getParameterMappings();
        tableNums.forEach(tableNum->{
            boundSql.getParameterMappings().addAll(tempParam);
        });

        // 組裝新的 sql
        String newSql = sqlUpdate(origSql,tableNums);

        // 重新new一個(gè)查詢語(yǔ)句對(duì)象
        BoundSql newBoundSql = new BoundSql(ms.getConfiguration(), newSql,
                boundSql.getParameterMappings(), boundSql.getParameterObject());

     // 把新的查詢放到statement里
        MappedStatement newMs = newMappedStatement(ms, new BoundSqlSqlSource(newBoundSql));
        for (ParameterMapping mapping : boundSql.getParameterMappings()) {
            String prop = mapping.getProperty();
            if (boundSql.hasAdditionalParameter(prop)) {
                newBoundSql.setAdditionalParameter(prop, boundSql.getAdditionalParameter(prop));
            }
        }

        Object[] queryArgs = invocation.getArgs();
        queryArgs[0] = newMs;


        return invocation.proceed();
    }

    /**
     *
     * @param sql 源sql
     * @param tableNums 需要構(gòu)建表名個(gè)數(shù)
     * @return
     */
    public String sqlUpdate(String sql, ArrayList<String> tableNums) {

        String[] froms = sql.split(_FROM);
        String column = froms[0];
        String fromAfter = froms[1];

        String[] wheres = fromAfter.split(_WHERE);

        String table = wheres[0];
        String whereAfter = wheres[1];

        String[] limits = whereAfter.split(_LIMIT);

        String condition = limits[0];
        String limit = limits[1];

        StringBuilder sqlContent = new StringBuilder();
        for (int i = 0; i < tableNums.size(); i++) {
            sqlContent.append(column)
                    .append(_FROM)
                    .append(table.trim() + tableNums.get(i))
                    .append(_WHERE)
                    .append(condition);
            if ((i + 1) < tableNums.size()) sqlContent.append(" UNION All \n");
        }
        sqlContent.append(_LIMIT).append(limit);

        return sqlContent.toString();
    }

    /**
     * 定義一個(gè)內(nèi)部輔助類,作用是包裝 SQL
     */
    class BoundSqlSqlSource implements SqlSource {
        private BoundSql boundSql;

        public BoundSqlSqlSource(BoundSql boundSql) {
            this.boundSql = boundSql;
        }

        public BoundSql getBoundSql(Object parameterObject) {
            return boundSql;
        }

    }

    private MappedStatement newMappedStatement(MappedStatement ms, SqlSource newSqlSource) {
        MappedStatement.Builder builder = new
                MappedStatement.Builder(ms.getConfiguration(), ms.getId(), newSqlSource, ms.getSqlCommandType());
        builder.resource(ms.getResource());
        builder.fetchSize(ms.getFetchSize());
        builder.statementType(ms.getStatementType());
        builder.keyGenerator(ms.getKeyGenerator());
        if (ms.getKeyProperties() != null && ms.getKeyProperties().length > 0) {
            builder.keyProperty(ms.getKeyProperties()[0]);
        }
        builder.timeout(ms.getTimeout());
        builder.parameterMap(ms.getParameterMap());
        builder.resultMaps(ms.getResultMaps());
        builder.resultSetType(ms.getResultSetType());
        builder.cache(ms.getCache());
        builder.flushCacheRequired(ms.isFlushCacheRequired());
        builder.useCache(ms.isUseCache());
        return builder.build();
    }


  @Override
    public Object plugin(Object target) {
        if (target instanceof Executor) {
            return Plugin.wrap(target, this);
        }
        return target;
    }

    @Override
    public void setProperties(Properties prop) {
        this.properties = prop;
    }
    
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子陶耍,更是在濱河造成了極大的恐慌仲智,老刑警劉巖沉帮,帶你破解...
    沈念sama閱讀 221,695評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異珍剑,居然都是意外死亡掸宛,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門招拙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來唧瘾,“玉大人,你說我怎么就攤上這事别凤∈涡颍” “怎么了?”我有些...
    開封第一講書人閱讀 168,130評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵规哪,是天一觀的道長(zhǎng)求豫。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么蝠嘉? 我笑而不...
    開封第一講書人閱讀 59,648評(píng)論 1 297
  • 正文 為了忘掉前任最疆,我火速辦了婚禮,結(jié)果婚禮上蚤告,老公的妹妹穿的比我還像新娘努酸。我一直安慰自己,他們只是感情好罩缴,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,655評(píng)論 6 397
  • 文/花漫 我一把揭開白布蚊逢。 她就那樣靜靜地躺著,像睡著了一般箫章。 火紅的嫁衣襯著肌膚如雪烙荷。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,268評(píng)論 1 309
  • 那天檬寂,我揣著相機(jī)與錄音终抽,去河邊找鬼。 笑死桶至,一個(gè)胖子當(dāng)著我的面吹牛昼伴,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播镣屹,決...
    沈念sama閱讀 40,835評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼圃郊,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了女蜈?” 一聲冷哼從身側(cè)響起持舆,我...
    開封第一講書人閱讀 39,740評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎伪窖,沒想到半個(gè)月后逸寓,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,286評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡覆山,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,375評(píng)論 3 340
  • 正文 我和宋清朗相戀三年竹伸,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片簇宽。...
    茶點(diǎn)故事閱讀 40,505評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡勋篓,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出魏割,到底是詐尸還是另有隱情生巡,我是刑警寧澤,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布见妒,位于F島的核電站孤荣,受9級(jí)特大地震影響甸陌,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜盐股,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,873評(píng)論 3 333
  • 文/蒙蒙 一钱豁、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧疯汁,春花似錦牲尺、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至溢豆,卻和暖如春蜒简,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背漩仙。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工搓茬, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人队他。 一個(gè)月前我還...
    沈念sama閱讀 48,921評(píng)論 3 376
  • 正文 我出身青樓卷仑,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親麸折。 傳聞我的和親對(duì)象是個(gè)殘疾皇子锡凝,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,515評(píng)論 2 359

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