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

Mybatis自定義攔截器實現(xiàn)權(quán)限功能

 更新時間:2024年12月12日 10:20:33   作者:喔喔咿哈哈  
本文主要介紹了Mybatis自定義攔截器實現(xiàn)權(quán)限功能,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

1、Mybatis 攔截器介紹

1.1 Mybatis 執(zhí)行流程

  • 首先讀取配置文件,然后加載映射文件,由SqlSessionFactory工廠對象去創(chuàng)建核心對象SqlSession,SqlSession對象會通過Executor執(zhí)行器對象執(zhí)行sql。然后Executor執(zhí)行器對象會調(diào)用StatementHandler對象去真正的訪問數(shù)據(jù)庫執(zhí)行sql語句。
  • 在執(zhí)行sql語句前MapperStatement會先對映射信息進(jìn)行封裝,然后StatementHandler調(diào)用ParameterHandler去設(shè)置編譯參數(shù)【#{},${}】,編譯在StatementHandler中進(jìn)行。然后StatementHandler調(diào)用JBDC原生API進(jìn)行處理,獲取執(zhí)行結(jié)果,這個執(zhí)行結(jié)果交給ResultSetHandler 來進(jìn)行結(jié)果集封裝,然后將結(jié)果返回給StatementHandler。
  • 注意: 這里MapperStatement是對映射信息的封裝,用于存儲要映射的SQL語句的id、參數(shù)等信息。TypeHandler進(jìn)行數(shù)據(jù)庫類型和JavaBean類型映射處理。

1.2 Mybatis中可以被攔截的類型

  • Executor:攔截執(zhí)行器的方法。
  • ParameterHandler:攔截參數(shù)的處理。
  • ResultHandler:攔截結(jié)果集的處理。
  • StatementHandler:攔截Sql語法構(gòu)建的處理。

1.3 使用規(guī)則

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Intercepts {
    /**
     * 定義攔截點
     * 只有符合攔截點的條件才會進(jìn)入到攔截器
     */
    Signature[] value();
}

Signature來指定咱們需要攔截那個類對象的哪個方法

- type:上述四種類型中的一種;
- method:對應(yīng)接口中的哪類方法(因為可能存在重載方法);
- args:對應(yīng)哪一個方法的入?yún)ⅲ?/p>

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({})
public @interface Signature {
  /**
   * 定義攔截的類 Executor、ParameterHandler、StatementHandler、ResultSetHandler當(dāng)中的一個
   */
  Class<?> type();

  /**
   * 在定義攔截類的基礎(chǔ)之上,在定義攔截的方法
   */
  String method();

  /**
   * 在定義攔截方法的基礎(chǔ)之上在定義攔截的方法對應(yīng)的參數(shù),
   * JAVA里面方法可能重載,故注意參數(shù)的類型和順序
   */
  Class<?>[] args();
}

1.4 攔截器重寫的方法

public interface Interceptor {
    //起攔截作用,在此定義一些功能
    Object intercept(Invocation var1) throws Throwable;

    //這個方法的作用是就是讓mybatis判斷,是否要進(jìn)行攔截,然后做出決定是否生成一個代理
    Object plugin(Object var1);

    //攔截器需要一些變量對象,而且這個對象是支持可配置的。
    void setProperties(Properties var1);
}

2、實戰(zhàn)部分:攔截實現(xiàn)

自定義注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DepartAuth {
    /**
     * 添加查詢條件的字段名
     * @return
     */
    String field();

    EnumDepartAuthType authType() default EnumDepartAuthType.DEPART_ID;
    
}

在所在接口上添加注解

@DepartAuth(field = "xxx", authType = )

切面(AuthAspect)

@Slf4j
@Aspect
@Component
public class DepartAuthAspect {

    @Autowired
    private DepartAuthHandler departAuthHandler;

    @Pointcut("@annotation(org.jeecg.common.auth.depart.annotation.DepartAuth)")
    public void departAuthPoint() {

    }

    @Before("departAuthPoint()")
    public void before(JoinPoint joinPoint) {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();

        Annotation[] annotations = methodSignature.getMethod().getAnnotations();

        for (Annotation annotation : annotations) {
            if (annotation instanceof DepartAuth) {
                String field = ((DepartAuth) annotation).field();
                departAuthHandler.beforeHandler((DepartAuth) annotation);
            }
        }

    }

    @After("departAuthPoint()")
    public void after(JoinPoint pjp) {
        departAuthHandler.afterHandler();
    }
}

DepartAuthHandler

將信息存儲到 TreadLocalhost 中,方便后續(xù)修改sql的時候可以讀取到需要修改的字段

@Slf4j
@Component
public class DepartAuthHandler {

    public static ThreadLocal<DepartAuth> DEPART_AUTH_CACHE = new ThreadLocal<>();
    public static ThreadLocal<Integer> DEPART_AUTH_COUNT = new ThreadLocal<>();

    public void beforeHandler(DepartAuth departAuth) {
        String field = departAuth.field();
        if(StringUtils.isNotBlank(field)) {
            DEPART_AUTH_CACHE.set(departAuth);
            DEPART_AUTH_COUNT.remove();
        }
        PriorityQueue queue = new PriorityQueue<>();
        queue.peek();
    }

    public void afterHandler() {
        DEPART_AUTH_CACHE.remove();
        DEPART_AUTH_COUNT.remove();
    }
}

攔截器部分

  • 獲取StatementHandler:通過 invocation.getTarget() 獲取當(dāng)前被攔截的 StatementHandler 對象。由于 MyBatis 使用了代理模式,因此這里得到的是一個代理對象。接著,通過反射獲取其實際的代理對象 ,即最終執(zhí)行SQL的 StatementHandler 實例。
  • 獲取MappedStatement:通過反射從 StatementHandler 中獲取 mappedStatement 對象。這個對象包含了關(guān)于即將執(zhí)行的SQL語句的所有信息,包括SQL類型、參數(shù)類型等。
  • 判斷SQL類型:通過mappedStatement.getSqlCommandType()獲取SQL命令類型。如果類型是SELECT,說明當(dāng)前是一個查詢操作,需要進(jìn)行權(quán)限檢查和處理。
  • 獲取并解析原始SQL:通過delegate.getBoundSql()獲取BoundSql對象,它包含了實際執(zhí)行的SQL語句和相關(guān)的參數(shù)信息。然后使用CCJSqlParserUtil.parse()解析這個SQL語句,得到一個抽象語法樹(AST)。
  • 修改SQL:從AST中提取出PlainSelect對象(即SELECT語句的主體)。然后調(diào)用自定義的buildWhereClause方法,根據(jù)departAuth中的權(quán)限信息構(gòu)建一個權(quán)限檢查條件,并將其注入到原始的SELECT語句中。這通常是通過在WHERE子句后追加額外的條件來實現(xiàn)的。
  • 更新BoundSql對象:將修改后的SQL語句重新設(shè)置回BoundSql對象中,以便MyBatis在執(zhí)行時能夠使用修改后的SQL。
  • 繼續(xù)執(zhí)行后續(xù)流程:在完成SQL修改后,調(diào)用invocation.proceed()繼續(xù)執(zhí)行MyBatis的后續(xù)處理流程,包括實際的SQL執(zhí)行、結(jié)果集處理等。
@Data
@Slf4j
@Component
@Intercepts({
        @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})
})
public class DepartAuthMapperInterceptor implements Interceptor {

    private Properties properties;




    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        DepartAuth departAuth = DepartAuthHandler.DEPART_AUTH_CACHE.get();
        Integer count = DepartAuthHandler.DEPART_AUTH_COUNT.get();
        if(departAuth != null && count == null) {
            // 說明當(dāng)前線程已經(jīng)執(zhí)行了過濾條件,避免遞歸調(diào)用
            DepartAuthHandler.DEPART_AUTH_COUNT.set(1);
            RoutingStatementHandler handler = (RoutingStatementHandler) invocation.getTarget();
            //獲取StatementHandler構(gòu)造器
            StatementHandler delegate = (StatementHandler) ReflectUtil.getFieldValue(handler, "delegate");
            // 通過反射獲取delegate父類BaseStatementHandler的mappedStatement屬性
            MappedStatement mappedStatement = (MappedStatement) ReflectUtil.getFieldValue(delegate, "mappedStatement");
            SqlCommandType commandType = mappedStatement.getSqlCommandType();
            // 處理select對象
            if (SqlCommandType.SELECT.equals(commandType)) {
                // 獲取原始sql
                BoundSql boundSql = delegate.getBoundSql();
                Statement statement = CCJSqlParserUtil.parse(boundSql.getSql());
                PlainSelect selectBody = (PlainSelect) ((Select) statement).getSelectBody();
                log.info("原始 sql:{}", boundSql.getSql());
                // 拼接新條件
                buildWhereClause(selectBody, getSql(departAuth));
                ReflectUtil.setFieldValue(boundSql, "sql", statement.toString());
            }
            return invocation.proceed();

        }
        return invocation.proceed();
    }

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

    @Override
    public void setProperties(Properties properties) {
        this.properties = properties;
    }

    /**
     * 添加查詢條件
     * @param select
     * @param dataFilter
     * @throws JSQLParserException
     */
    private void buildWhereClause(PlainSelect select, String dataFilter) throws JSQLParserException {
        if(StringUtils.isBlank(dataFilter)) {
            return;
        }
        if (select.getWhere() == null) {
            select.setWhere(CCJSqlParserUtil.parseCondExpression(dataFilter));
        } else {
            AndExpression and = new AndExpression(
                    CCJSqlParserUtil.parseCondExpression(dataFilter), select.getWhere());
            select.setWhere(and);
        }
    }

    private String getSql(DepartAuth departAuth) {
        //結(jié)合自己的業(yè)務(wù),拼接相對應(yīng)的sql語句
    }
}

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

相關(guān)文章

  • Spring-Bean創(chuàng)建對象的步驟方式詳解

    Spring-Bean創(chuàng)建對象的步驟方式詳解

    在本篇文章里小編給大家分享的是關(guān)于Spring-Bean創(chuàng)建對象的步驟方式詳解內(nèi)容,有興趣的朋友們跟著學(xué)習(xí)下。
    2020-02-02
  • Java實現(xiàn)汽車租賃系統(tǒng)

    Java實現(xiàn)汽車租賃系統(tǒng)

    這篇文章介紹了Java實現(xiàn)汽車租賃系統(tǒng)的方法,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-03-03
  • Java后端實現(xiàn)生成驗證碼圖片的示例代碼

    Java后端實現(xiàn)生成驗證碼圖片的示例代碼

    驗證碼是一種用于驗證用戶身份或確保用戶操作安全的技術(shù)手段,通常以圖形、聲音或文字的形式出現(xiàn),本文主要介紹了如何通過java實現(xiàn)生成驗證碼圖片,需要的可以參考下
    2023-12-12
  • servlet 解決亂碼問題

    servlet 解決亂碼問題

    這篇文章主要介紹了servlet 解決亂碼問題 ,需要的朋友可以參考下
    2015-04-04
  • Java實現(xiàn)企業(yè)微信消息推送功能的詳細(xì)步驟

    Java實現(xiàn)企業(yè)微信消息推送功能的詳細(xì)步驟

    這篇文章主要介紹了Java實現(xiàn)企業(yè)微信消息推送功能,本文圖文實例代碼相結(jié)合給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2022-04-04
  • java高并發(fā)寫入用戶信息到數(shù)據(jù)庫的幾種方法

    java高并發(fā)寫入用戶信息到數(shù)據(jù)庫的幾種方法

    本文主要介紹了java高并發(fā)寫入用戶信息到數(shù)據(jù)庫的幾種方法,具有很好的參考價值。下面跟著小編一起來看下吧
    2017-03-03
  • java批量下載將多個文件(minio中存儲)壓縮成一個zip包代碼示例

    java批量下載將多個文件(minio中存儲)壓縮成一個zip包代碼示例

    在Java應(yīng)用程序中有時我們需要從多個URL地址下載文件,并將這些文件打包成一個Zip文件進(jìn)行批量處理或傳輸,這篇文章主要給大家介紹了關(guān)于java批量下載將多個文件(minio中存儲)壓縮成一個zip包的相關(guān)資料,需要的朋友可以參考下
    2023-11-11
  • 詳解Java內(nèi)存管理中的JVM垃圾回收

    詳解Java內(nèi)存管理中的JVM垃圾回收

    這篇文章給大家分享了關(guān)于Java內(nèi)存管理中的JVM垃圾回收的相關(guān)知識點內(nèi)容,有興趣的朋友們可以學(xué)習(xí)參考下。
    2018-08-08
  • SpringBoot Jackson日期格式化統(tǒng)一配置的實現(xiàn)

    SpringBoot Jackson日期格式化統(tǒng)一配置的實現(xiàn)

    Spring項目中經(jīng)常需要配置日期時間格式格式,本文主要介紹了SpringBoot Jackson日期格式化統(tǒng)一配置的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-08-08
  • springboot掃描自定義的servlet和filter代碼詳解

    springboot掃描自定義的servlet和filter代碼詳解

    本文是一篇根據(jù)作者工作經(jīng)歷總結(jié)出來的關(guān)于springboot掃描自定義的servlet和filter代碼詳解的文章,小編覺得非常不錯,這里給大家分享下,和朋友們一起學(xué)習(xí),進(jìn)步。
    2017-10-10

最新評論

溧水县| 宁强县| 漳州市| 敦煌市| 繁昌县| 临桂县| 肥乡县| 崇礼县| 图们市| 普安县| 加查县| 拜城县| 稻城县| 石渠县| 宜都市| 射阳县| 黄陵县| 贡觉县| 沙坪坝区| 蒙山县| 兰溪市| 乌审旗| 边坝县| 永定县| 和顺县| 景泰县| 佛山市| 清苑县| 马尔康县| 大石桥市| 南涧| 海口市| 兴隆县| 大田县| 高平市| 璧山县| 汽车| 巢湖市| 新津县| 临泽县| 论坛|