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

MybatisPlus?自定義插件實現(xiàn)攔截SQL修改功能(實例詳解)

 更新時間:2023年11月15日 09:52:01   作者:愛碼猿  
這篇文章主要介紹了MybatisPlus?自定義插件實現(xiàn)攔截SQL修改功能,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧

最近項目內(nèi)使用MybatisPlus整合Phoenix實現(xiàn)對HBase進(jìn)行操作,但是Phoenix的sql語法和MySQL不太一樣,導(dǎo)致得在列上加@TableField申明列簇名稱和列名稱,不太友好,所以自己寫了個插件攔截sql并進(jìn)行修改

package org.gjw.config;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
import com.baomidou.mybatisplus.extension.parser.JsqlParserSupport;
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import net.sf.jsqlparser.expression.Alias;
import net.sf.jsqlparser.expression.BinaryExpression;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.Function;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.statement.delete.Delete;
import net.sf.jsqlparser.statement.insert.Insert;
import net.sf.jsqlparser.statement.select.*;
import net.sf.jsqlparser.statement.update.Update;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import java.util.stream.Collectors;
/**
 * @author guojunwang
 * @date 2021-11-29 17:06
 */
public class PhoenixMPPlugin extends JsqlParserSupport implements InnerInterceptor {
    /**
     * 查詢時處理邏輯
     */
    @Override
    public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
        PluginUtils.MPBoundSql mpBs = PluginUtils.mpBoundSql(boundSql);
        //通過 JSqlParser工具修改查詢sql后執(zhí)行
        mpBs.sql(parserSingle(mpBs.sql(), null));
    }
    /**
     * 增刪改時 處理邏輯
     */
    @Override
    public void beforePrepare(StatementHandler sh, Connection connection, Integer transactionTimeout) {
        PluginUtils.MPStatementHandler mpSh = PluginUtils.mpStatementHandler(sh);
        MappedStatement ms = mpSh.mappedStatement();
        SqlCommandType sct = ms.getSqlCommandType();
        //增刪改調(diào)用 JSqlParser工具修改sql后執(zhí)行
        if (sct == SqlCommandType.INSERT || sct == SqlCommandType.UPDATE || sct == SqlCommandType.DELETE) {
            PluginUtils.MPBoundSql mpBs = mpSh.mPBoundSql();
            mpBs.sql(parserMulti(mpBs.sql(), null));
        }
    }
    /**
     * 以處理查詢sql為例,增刪改的實現(xiàn)可根據(jù)自己的業(yè)務(wù)實現(xiàn)
     */
    @Override
    protected void processSelect(Select select, int index, String sql, Object obj) {
        //此處處理select邏輯 將字符串拼接上 雙引號
        SelectBody selectBody = select.getSelectBody();
        if(selectBody instanceof PlainSelect) reformatPlainSelect((PlainSelect) selectBody);
    }
    @Override
    protected void processInsert(Insert insert, int index, String sql, Object obj) {
        System.out.println( "新增前調(diào)用,可修改sql" );
    }
    @Override
    protected void processDelete(Delete delete, int index, String sql, Object obj) {
        System.out.println( "刪除前調(diào)用,可修改sql" );
    }
    @Override
    protected void processUpdate(Update update, int index, String sql, Object obj) {
        System.out.println("修改調(diào)用,可修改sql");
    }
//---------------以下為處理sql操作,根據(jù)自己業(yè)務(wù)功能完善
    /**
     * 處理查詢字段
     */
    private List<SelectItem> disposeSelectColumn(List<SelectItem> selectItems){
        return selectItems.stream().map( this::resetSelectItem ).collect(Collectors.toList());
    }
    private SelectItem resetSelectItem( SelectItem selectItem ){
        //如果不符合直接返回
        if( !(selectItem instanceof SelectExpressionItem) ) return selectItem;
        SelectExpressionItem item = (SelectExpressionItem)selectItem;
        //如果是列
        if( item.getExpression() instanceof Column ){
            Column columnExp = (Column)item.getExpression();
            return new SelectExpressionItem( reFormatSelectColumn( columnExp,item.getAlias() ) );
        }
        //如果是函數(shù)
        if( item.getExpression() instanceof Function){
            Function function = (Function) item.getExpression();
            return new SelectExpressionItem( reFormatFunction( function ) );
        }
         return item;
    }
    /**
     * 重新格式化 查詢語句
     * @param plainSelect 查詢語句
     * @return 格式化的查詢語句
     */
    public void reformatPlainSelect(PlainSelect plainSelect){
        //處理要查詢的字段
        List<SelectItem> selectItems = plainSelect.getSelectItems();
        //處理查詢條件
        plainSelect.setSelectItems( disposeSelectColumn( selectItems ) );
        //處理 where 條件
        plainSelect.setWhere( disposeSelectWhere( plainSelect.getWhere() )  );
    }
    /**
     * 重新格式化列
     * @param columnExp 列
     * @param alias 列別名
     * @return 格式化的列
     */
    private Column reFormatSelectColumn( Column columnExp,Alias alias ){
        if( columnExp == null ) return columnExp;
        //表名和列簇名會在一起
        String tableAndCFName= columnExp.getTable() == null ? "" : columnExp.getTable().toString();
        //字段名
        String columnName= columnExp.getColumnName();
        //根據(jù) `.` 分隔方便處理表名和列簇名
        String[] tableAndCFInfo = tableAndCFName.split("\\.");
        // 可能會出現(xiàn)很多情況 列名  列簇.列名  表名.列簇.列名 表名.列名
        String tableName = tableAndCFInfo[0];
        String cf        = tableAndCFInfo[tableAndCFInfo.length - 1];
        //如果表名和字段名相等,只有3種情況: 列名  表名.列名  列簇.列名
        if( StrUtil.equals(tableName,cf)  && StrUtil.isNotBlank(tableName) ){
            //判斷前綴是表名還是列名  要求列簇必須全大寫 表名不能全大寫
            //如果全大寫這是列簇名
            if( StrUtil.equals(cf.toUpperCase(),cf) ) {
                tableName = "";
            }else cf = ""; //否則是表名
        }
        StringBuilder finalName = new StringBuilder();
        //如果表名不為空 拼接表名
        if( StrUtil.isNotBlank( tableName ) )   finalName.append( tableName ).append( "." );
        //如果列簇名不為空 拼接列簇名
        if( StrUtil.isNotBlank( cf ) ) finalName.append( appendPrefixAndSuffix(cf) ).append(".");
        //拼接字段名
        finalName.append( appendPrefixAndSuffix(columnName) );
        //拼接別名: as xxx
        if( alias !=null ) finalName.append(" ").append( alias.getName() );
        //重新格式化列名 封裝返回
        return new Column( finalName.toString() );
    }
    /**
     * 重新格式化查詢函數(shù)
     * @param function 函數(shù)
     * @return 格式化的函數(shù)
     */
    private Function reFormatFunction( Function function ){
        List<Expression> expressions = function.getParameters().getExpressions();
        //對于是列的參數(shù)進(jìn)行格式化
        expressions = expressions.stream().map(exp -> {
            if (exp instanceof Column) return reFormatSelectColumn((Column) exp, null);
            return exp;
        }).collect(Collectors.toList());
        //重新設(shè)置回去
        function.getParameters().setExpressions(expressions);
        return function;
    }
    /**
     * 重新格式化子查詢
     * @param subSelect 子查詢
     * @return 格式化的函數(shù)
     */
    private SubSelect reFormatSubSelect( SubSelect subSelect ){
        if( subSelect.getSelectBody() instanceof PlainSelect ){
            reformatPlainSelect( (PlainSelect)subSelect.getSelectBody() );
        }
        return subSelect;
    }
    public Expression disposeSelectWhere(Expression expression){
        if( !(expression instanceof BinaryExpression) ) return expression;
        BinaryExpression binaryExpression =(BinaryExpression)expression;
        //如果左邊還是多條件的
        if( binaryExpression.getLeftExpression() instanceof BinaryExpression){
            disposeSelectWhere( binaryExpression.getLeftExpression() );
        }
        //如果右邊還是多條件的
        if( binaryExpression.getRightExpression() instanceof BinaryExpression){
            disposeSelectWhere( binaryExpression.getRightExpression() );
        }
        //如果左邊表達(dá)式是列信息 格式化
        if(  binaryExpression.getLeftExpression() instanceof Column ){
            Column newColumn = reFormatSelectColumn((Column) binaryExpression.getLeftExpression(), null);
            binaryExpression.setLeftExpression( newColumn );
        }
        //如果左邊表達(dá)式是 子查詢 processPlainSelect
        if(binaryExpression.getLeftExpression() instanceof SubSelect){
            SubSelect subSelect = (SubSelect)binaryExpression.getLeftExpression();
            if( subSelect.getSelectBody() instanceof PlainSelect ){
                reformatPlainSelect( (PlainSelect)subSelect.getSelectBody() );
            }
        }
        //如果右邊是列信息 格式化
        if(  binaryExpression.getRightExpression() instanceof Column ){
            Column newColumn = reFormatSelectColumn((Column) binaryExpression.getLeftExpression(), null);
            binaryExpression.setRightExpression( newColumn );
        }
        //如果右邊表達(dá)式是 子查詢 processPlainSelect
        if( binaryExpression.getRightExpression() instanceof SubSelect){
            SubSelect subSelect = (SubSelect)binaryExpression.getRightExpression();
            reFormatSubSelect( subSelect );
        }
        return binaryExpression;
    }
    private String appendPrefixAndSuffix(String str){
        final String PREFIX = "\"";
        final String SUFFIX = "\"";
        //如果已經(jīng)有前綴了直接返回
        if( str.contains(PREFIX) ) return str;
        //拼接前綴和后綴
        return new StringBuilder().append(PREFIX).append(str).append(SUFFIX).toString();
    }
}

使用: 編寫配置類配置MybatisPlus并設(shè)置插件

@MapperScan(value = "org.gjw.mapper.phoenix",sqlSessionTemplateRef = "phoenixSqlSessionTemplate",sqlSessionFactoryRef = "phoenixSqlSessionFactory")
@Configuration
public class PhoenixConfig {
    @Bean
    @ConfigurationProperties("spring.datasource.phoenix")
    public DataSource phoenixDataSource(){
        return new HikariDataSource();
    }
    @Bean
    public SqlSessionFactory phoenixSqlSessionFactory( @Qualifier("phoenixDataSource") @Autowired DataSource phoenixDataSource) throws Exception {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource( phoenixDataSource() );
        sqlSessionFactoryBean.setMapperLocations( new PathMatchingResourcePatternResolver().getResources("classpath*:/phoenixMapper/**/*.xml"));
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor( new PhoenixMPPlugin() );
        sqlSessionFactoryBean.setPlugins( interceptor );
        MybatisConfiguration mybatisConfiguration = new MybatisConfiguration();
        mybatisConfiguration.setMapUnderscoreToCamelCase(true);
        mybatisConfiguration.setLogImpl(StdOutImpl.class);
        sqlSessionFactoryBean.setConfiguration(mybatisConfiguration);
        return sqlSessionFactoryBean.getObject();
    }
    @Bean
    public SqlSessionTemplate phoenixSqlSessionTemplate( @Qualifier("phoenixSqlSessionFactory") @Autowired SqlSessionFactory phoenixSqlSessionFactory){
        return new SqlSessionTemplate( phoenixSqlSessionFactory );
    }
    @Bean
    public DataSourceTransactionManager phoenixDataSourceTransactionManager(@Qualifier("phoenixDataSource") @Autowired DataSource phoenixDataSource){
        return new DataSourceTransactionManager(phoenixDataSource);
    }
}

到此這篇關(guān)于MybatisPlus 自定義插件實現(xiàn)攔截SQL修改功能的文章就介紹到這了,更多相關(guān)MybatisPlus 攔截SQL內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Spring?Boot?DevTools?全局配置學(xué)習(xí)指南

    Spring?Boot?DevTools?全局配置學(xué)習(xí)指南

    這篇文章主要介紹了Spring?Boot?DevTools?全局配置,注意包括直接重啟項目與devtools重啟的區(qū)別,DevTools配置,DevTools全局配置及trigger-file控制重啟行為的相關(guān)知識,需要的朋友可以參考下
    2022-03-03
  • Java中Integer和int的使用及注意點(diǎn)

    Java中Integer和int的使用及注意點(diǎn)

    文章主要介紹了Java中Integer和Long類的緩存機(jī)制以及它們的比較方式,Integer和Long類在-128到127之間的值會被緩存,因此在這個范圍內(nèi)的值比較時可以使用==運(yùn)算符,而超出這個范圍的值則需要使用equals()方法進(jìn)行比較
    2025-01-01
  • SpringBean實例化的基本流程源碼剖析

    SpringBean實例化的基本流程源碼剖析

    Spring容器通過BeanDefinition對象和singletonObjects Map集合管理Bean實例化過程,實現(xiàn)依賴注入和控制反轉(zhuǎn),本文給大家介紹SpringBean實例化的基本流程源碼剖析,感興趣的朋友跟隨小編一起看看吧
    2026-01-01
  • 淺析SpringBoot3.x 如何避免內(nèi)部服務(wù)調(diào)用被重復(fù)攔截

    淺析SpringBoot3.x 如何避免內(nèi)部服務(wù)調(diào)用被重復(fù)攔截

    這篇文章主要為大家詳細(xì)介紹了SpringBoot3.x 避免內(nèi)部服務(wù)調(diào)用被重復(fù)攔截的相關(guān)方法,文中的示例代碼講解詳細(xì),有需要的小伙伴可以了解下
    2025-09-09
  • spring boot 命令行啟動的方式

    spring boot 命令行啟動的方式

    這篇文章主要介紹了spring boot 命令行啟動的方式,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • Java中的動態(tài)代理實現(xiàn)代碼實例

    Java中的動態(tài)代理實現(xiàn)代碼實例

    這篇文章主要介紹了Java中的動態(tài)代理實現(xiàn)代碼實例,jdk動態(tài)代理本質(zhì)上是使用被代理對象的類加載器,通過被代理類實現(xiàn)的接口在運(yùn)行時動態(tài)構(gòu)造出代理類來增強(qiáng)原始類的功能的方法,需要的朋友可以參考下
    2023-12-12
  • 解決Feign異步調(diào)用丟失上下文問題

    解決Feign異步調(diào)用丟失上下文問題

    在微服務(wù)中使用Feign調(diào)用時,若需要攜帶登錄狀態(tài)的Cookie信息,通常會使用攔截器,但在異步調(diào)用(如order服務(wù)異步調(diào)用會員服務(wù)和購物車服務(wù))時,攔截器可能無法獲取上下文信息,導(dǎo)致異常,解決方法是將RequestContextHolder的數(shù)據(jù)同步到新開啟的線程中
    2024-11-11
  • SpringBoot自定義對象參數(shù)實現(xiàn)自動類型轉(zhuǎn)換與格式化

    SpringBoot自定義對象參數(shù)實現(xiàn)自動類型轉(zhuǎn)換與格式化

    SpringBoot 通過自定義對象參數(shù),可以實現(xiàn)自動類型轉(zhuǎn)換與格式化,并可以級聯(lián)封裝,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧
    2022-09-09
  • Tomcat調(diào)優(yōu)詳解

    Tomcat調(diào)優(yōu)詳解

    這篇文章主要介紹了Tomcat調(diào)優(yōu)方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-04-04
  • Java唯一訂單編號生成代碼例子

    Java唯一訂單編號生成代碼例子

    在項目中,我們經(jīng)常遇到需要生成訂單編號、字典編號等唯一值場景,下面這篇文章主要給大家介紹了關(guān)于Java唯一訂單編號生成的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-07-07

最新評論

昌图县| 阿鲁科尔沁旗| 两当县| 普安县| 湘西| 衡阳县| 囊谦县| 梨树县| 托克托县| 稻城县| 金寨县| 沂南县| 扎赉特旗| 本溪| 万山特区| 湘西| 余江县| 衡南县| 博野县| 天气| 重庆市| 泸溪县| 偏关县| 平武县| 宁城县| 武隆县| 中宁县| 庄河市| 姜堰市| 苍梧县| 望谟县| 盈江县| 隆林| 维西| 开远市| 巴塘县| 安康市| 永吉县| 清河县| 福泉市| 南召县|