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

Mybatis攔截器如何實(shí)現(xiàn)數(shù)據(jù)權(quán)限過(guò)濾

 更新時(shí)間:2024年12月31日 14:14:29   作者:CodeLemon·  
本文介紹了MyBatis攔截器的使用,通過(guò)實(shí)現(xiàn)Interceptor接口對(duì)SQL進(jìn)行處理,實(shí)現(xiàn)數(shù)據(jù)權(quán)限過(guò)濾功能,通過(guò)在本地線程變量中存儲(chǔ)數(shù)據(jù)權(quán)限相關(guān)信息,并在攔截器的intercept方法中進(jìn)行SQL增強(qiáng)處理

背景

現(xiàn)在的項(xiàng)目負(fù)責(zé)人去年年底離職,導(dǎo)致前期規(guī)劃的數(shù)據(jù)過(guò)濾功能一直沒(méi)有去實(shí)現(xiàn)。

現(xiàn)在項(xiàng)目馬上進(jìn)入試運(yùn)行時(shí)期了,需要根據(jù)用戶數(shù)據(jù)權(quán)限的配置對(duì)數(shù)據(jù)進(jìn)行過(guò)濾處理。

如果一個(gè)個(gè)手動(dòng)去Mapper.xml文件中修改SQL工作量太大了,后面我考慮通過(guò)Mybatis對(duì)查詢的SQL進(jìn)行處理。

基礎(chǔ)知識(shí)

Mybatis 攔截器介紹

Interceptor接口源碼解析

package org.apache.ibatis.plugin;  
  
import java.util.Properties;  
  
public interface Interceptor {  
	
    Object intercept(Invocation invocation) throws Throwable;  

    default Object plugin(Object target) {  
        return Plugin.wrap(target, this);  
    }  
    
    default void setProperties(Properties properties) {  
    }  
}
  • intercept 方法
    這個(gè)方法是核心,當(dāng)攔截到調(diào)用時(shí)會(huì)執(zhí)行。Invocation 對(duì)象包含了被攔截方法的所有信息,包括方法本身、參數(shù)、目標(biāo)對(duì)象等。在這個(gè)方法中,你可以做任何預(yù)處理或后處理邏輯,然后通過(guò)調(diào)用 invocation.proceed() 來(lái)繼續(xù)執(zhí)行原方法,或者直接返回自定義的結(jié)果。
  • plugin方法
    這個(gè)方法用于決定是否對(duì)某個(gè)對(duì)象應(yīng)用攔截器。如果返回 target,則表示不進(jìn)行攔截;如果返回一個(gè)新的對(duì)象,則表示將使用這個(gè)新對(duì)象替代原有的對(duì)象,通常是在這里返回一個(gè)代理對(duì)象。
  • setProperties 方法
    用于設(shè)置攔截器的屬性,這些屬性可以在 MyBatis 的配置文件中定義。

Signature 注解源碼解析

@Documented  
@Retention(RetentionPolicy.RUNTIME)  
@Target({})  
public @interface Signature {  
	Class<?> type();

	String method();

	Class<?>[] args();
}
  • type:表示目標(biāo)對(duì)象的類型,
  • method:表示要攔截的目標(biāo)方法的名字。
  • args:表示目標(biāo)方法的參數(shù)類型列表。不同的 @Signature 注解可能有不同的參數(shù)類型列表,這取決于具體的方法簽名。

代碼實(shí)戰(zhàn)

實(shí)現(xiàn)一個(gè)類似與PageHelper的一個(gè)工具類,在本地線程變量中存儲(chǔ)數(shù)據(jù)權(quán)限相關(guān)信息

public class DataAccessMethod {  
    private static final ThreadLocal<DataAccessType[]> ACCESS_LOCAL = new ThreadLocal<>();  
  
  
    public DataAccessMethod() {  
  
    }  
    public static void setLocalAccess(DataAccessType... accessType) {  
        ACCESS_LOCAL.set(accessType);  
    }  
  
    public static DataAccessType[] getLocalAccess() {  
        return ACCESS_LOCAL.get();  
    }  
  
    public static void clearLocalAccess() {  
        ACCESS_LOCAL.remove();  
    }  
  
    public static void accessData(DataAccessType... accessType) {  
        setLocalAccess(accessType);  
    }  
}

實(shí)現(xiàn) Interceptor接口對(duì)SQL進(jìn)行增強(qiáng)處理

@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}  
)})  
@Slf4j  
@Component  
public class DataAccessFilterInterceptor implements Interceptor {  
  
  
    @Override  
    public Object intercept(Invocation invocation) throws Throwable {  
        if (skip()) {  
            return invocation.proceed();  
        }  
        MappedStatement statement = (MappedStatement) invocation.getArgs()[0];  
        Object parameter = invocation.getArgs()[1];  
        BoundSql boundSql = statement.getBoundSql(parameter);  
        String originalSql = boundSql.getSql();  
        Object parameterObject = boundSql.getParameterObject();  
        String sql = addTenantCondition(originalSql, "1", "222");  
        log.info("原SQL:{}, 數(shù)據(jù)權(quán)限替換后的SQL:{}", originalSql, sql);  
  
        BoundSql newBoundSql = new BoundSql(statement.getConfiguration(), sql, boundSql.getParameterMappings(), parameterObject);  
        MappedStatement newStatement = copyFromMappedStatement(statement, new BoundSqlSqlSource(newBoundSql));  
        invocation.getArgs()[0] = newStatement;  
        return invocation.proceed();  
    }  
  
    /**  
     * 判斷是否跳過(guò)  
     *  
     * @return 是否跳過(guò)  
     */  
    private boolean skip() {  
        DataAccessType[] localAccess = DataAccessMethod.getLocalAccess();  
        return localAccess == null;  
    }  
  
    private String addTenantCondition(String originalSql, String depId, String alias) {  
        String field = "id";  
        if (StringUtils.hasText(alias)) {  
            field = alias + "." + field;  
        }  
  
        StringBuilder sb = new StringBuilder(originalSql.toLowerCase());  
        int index = sb.indexOf("where");  
        sb = new StringBuilder(originalSql);  
        if (index < 0) {  
            sb.append(" where ").append(field).append(" = ").append(depId);  
        } else {  
            sb.insert(index + 5, " " + field + " = " + depId + " and ");  
        }  
        return sb.toString();  
    }  
  
    private MappedStatement copyFromMappedStatement(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());  
        builder.timeout(ms.getTimeout());  
        builder.parameterMap(ms.getParameterMap());  
        builder.resultMaps(ms.getResultMaps());  
        builder.cache(ms.getCache());  
        builder.useCache(ms.isUseCache());  
        return builder.build();  
    }  
  
    public static class BoundSqlSqlSource implements SqlSource {  
        private final BoundSql boundSql;  
  
        public BoundSqlSqlSource(BoundSql boundSql) {  
            this.boundSql = boundSql;  
        }  
  
        @Override  
        public BoundSql getBoundSql(Object parameterObject) {  
            return boundSql;  
        }  
    }  
  
  
}

總結(jié)

以上代碼只是示例,在實(shí)際生產(chǎn)中還需要考慮多表查詢、SQL注入等相關(guān)問(wèn)題。

這些僅為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • JDK1.7中HashMap的死循環(huán)問(wèn)題及解決方案

    JDK1.7中HashMap的死循環(huán)問(wèn)題及解決方案

    這篇文章主要為大家介紹了JDK1.7中HashMap的死循環(huán)問(wèn)題及解決方案,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-10-10
  • 通過(guò)實(shí)例解析傳統(tǒng)jar包引用方式

    通過(guò)實(shí)例解析傳統(tǒng)jar包引用方式

    這篇文章主要介紹了通過(guò)實(shí)例解析傳統(tǒng)jar包引用方式,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-07-07
  • Java使用建造者模式實(shí)現(xiàn)辦理手機(jī)套餐功能詳解

    Java使用建造者模式實(shí)現(xiàn)辦理手機(jī)套餐功能詳解

    這篇文章主要介紹了Java使用建造者模式實(shí)現(xiàn)辦理手機(jī)套餐功能,較為詳細(xì)的描述了建造者模式的概念、原理并結(jié)合實(shí)例形式分析了Java使用建造者模式實(shí)現(xiàn)的辦理手機(jī)套餐功能具體步驟與相關(guān)操作注意事項(xiàng),需要的朋友可以參考下
    2018-05-05
  • SpringMVC體系分層模式原理圖解

    SpringMVC體系分層模式原理圖解

    這篇文章主要介紹了SpringMVC體系分層模式原理圖解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-06-06
  • 集成Spring Redis緩存的實(shí)現(xiàn)

    集成Spring Redis緩存的實(shí)現(xiàn)

    今天小編就為大家分享一篇關(guān)于集成Spring Redis緩存的實(shí)現(xiàn),小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2018-12-12
  • SpringBoot整合FTP實(shí)現(xiàn)文件傳輸?shù)牟襟E

    SpringBoot整合FTP實(shí)現(xiàn)文件傳輸?shù)牟襟E

    這篇文章主要給大家介紹了SpringBoot整合FTP實(shí)現(xiàn)文件傳輸?shù)牟襟E,文中的流程步驟和代碼示例介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下
    2023-11-11
  • SpringCloud全局過(guò)慮器GlobalFilter的用法小結(jié)

    SpringCloud全局過(guò)慮器GlobalFilter的用法小結(jié)

    這篇文章主要介紹了SpringCloud全局過(guò)慮器GlobalFilter的使用,全局過(guò)慮器使用非常廣泛,比如驗(yàn)證是否登錄,全局性的處理,黑名單或白名單的校驗(yàn)等,本文結(jié)合示例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2023-07-07
  • Java VisualVM監(jiān)控遠(yuǎn)程JVM(詳解)

    Java VisualVM監(jiān)控遠(yuǎn)程JVM(詳解)

    下面小編就為大家?guī)?lái)一篇Java VisualVM監(jiān)控遠(yuǎn)程JVM(詳解)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-10-10
  • Java中的WeakHashMap源碼分析

    Java中的WeakHashMap源碼分析

    這篇文章主要介紹了Java中的WeakHashMap源碼分析,WeakHashMap可能平時(shí)使用的頻率并不高,但是你可能聽(tīng)過(guò)WeakHashMap會(huì)進(jìn)行自動(dòng)回收吧,下面就對(duì)其原理進(jìn)行分析,需要的朋友可以參考下
    2023-09-09
  • Java使用代碼模擬高并發(fā)操作的示例

    Java使用代碼模擬高并發(fā)操作的示例

    本篇文章主要介紹了Java使用代碼模擬高并發(fā)操作的示例,Java通過(guò)代碼模擬高并發(fā)可以以最快的方式發(fā)現(xiàn)我們系統(tǒng)中潛在的線程安全性問(wèn)題,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-05-05

最新評(píng)論

绵阳市| 禄劝| 西贡区| 上高县| 宁南县| 墨竹工卡县| 赤壁市| 塘沽区| 来安县| 甘肃省| 明星| 石家庄市| 休宁县| 当涂县| 日照市| 平舆县| 鄂尔多斯市| 凤城市| 大同市| 涞水县| 洪泽县| 和林格尔县| 庆阳市| 千阳县| 田东县| 青岛市| 正宁县| 洪泽县| 十堰市| 南汇区| 金塔县| 襄汾县| 思茅市| 马边| 彭山县| 河津市| 武定县| 临邑县| 河西区| 盐亭县| 安多县|