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

mybatis plus數(shù)據(jù)權(quán)限插件在項(xiàng)目中的使用方式

 更新時(shí)間:2026年01月08日 10:27:06   作者:jpq+  
本文介紹了如何在MyBatis中實(shí)現(xiàn)數(shù)據(jù)權(quán)限攔截器,通過(guò)自定義注解和攔截器,動(dòng)態(tài)地在SQL中添加數(shù)據(jù)權(quán)限條件

前言

平時(shí)開(kāi)發(fā)中遇到根據(jù)當(dāng)前用戶的角色,只能查看數(shù)據(jù)權(quán)限范圍的數(shù)據(jù)需求。實(shí)現(xiàn)方案有兩種,一是在開(kāi)發(fā)初期就做好判斷,但如果這個(gè)需求是中途加的,或不希望每個(gè)接口都加一遍,就可以方案二加攔截器的方式。在mybatis執(zhí)行sql前修改語(yǔ)句,限定where范圍。

當(dāng)然攔截器生效后是全局性的,如何保證只對(duì)需要的接口進(jìn)行攔截和轉(zhuǎn)化,就可以應(yīng)用注解進(jìn)行識(shí)別

因此具體需要哪些步驟就明確了:

  1. 創(chuàng)建注解類
  2. 創(chuàng)建處理類,獲取數(shù)據(jù)權(quán)限 SQL 片段,設(shè)置條件
  3. 將攔截器加到MyBatis-Plus插件中

數(shù)據(jù)權(quán)限插件

DataPermissionInterceptor

插件原理和租戶插件類似動(dòng)態(tài)攔截執(zhí)行 SQl 然后拼接權(quán)限部分 SQL片段 , 該插件一直是免費(fèi)開(kāi)源的,企業(yè)高級(jí)特性-數(shù)據(jù)范圍功能也是基于該原理實(shí)現(xiàn),只不過(guò)添加了注解支持。

使用DataPermissionHandler

/**
 * 數(shù)據(jù)權(quán)限處理器
 *
 * @author hubin
 * @since 3.4.1 +
 */
public interface DataPermissionHandler {

    /**
     * 獲取數(shù)據(jù)權(quán)限 SQL 片段
     *
     * @param where             待執(zhí)行 SQL Where 條件表達(dá)式
     * @param mappedStatementId Mybatis MappedStatement Id 根據(jù)該參數(shù)可以判斷具體執(zhí)行方法
     * @return JSqlParser 條件表達(dá)式
     */
    Expression getSqlSegment(Expression where, String mappedStatementId);
}

先定義一個(gè)注解:

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface DataScope {
    /**
     * 表前綴
     */
    String tableAlis() default "";
    /**
     * 機(jī)構(gòu)前綴
     */
    String orgAlis() default "org_id";

    /**
     * 是否生效
     */
    boolean enabled() default true;
}

新建一個(gè)OrgScopeHandler,通過(guò)實(shí)現(xiàn)以上接口:

 @Override
    public Expression getSqlSegment(Expression where, String mappedStatementId) {

        try {
            Class<?> clazz = Class.forName(mappedStatementId.substring(0, mappedStatementId.lastIndexOf(".")));
            String methodName = mappedStatementId.substring(mappedStatementId.lastIndexOf(".") + 1);
            Method[] methods = clazz.getDeclaredMethods();
            for (Method method : methods) {
                DataScope annotation = method.getAnnotation(DataScope.class);
                if (ObjectUtils.isNotEmpty(annotation)
                        && (method.getName().equals(methodName) || (method.getName() + "_COUNT").equals(methodName))) {
                    if (annotation.enabled()) {

                        return dataScopeFilter(annotation, where);
                    }

                }
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return where;
    }

在項(xiàng)目中的MybatisPlusConfig中加上自定義的OrgScopeHandler:

 MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
 // 數(shù)據(jù)權(quán)限
        interceptor.addInnerInterceptor(new DataPermissionInterceptor(new OrgScopeHandler()));

getSqlSegment中的實(shí)現(xiàn)是遍歷Mybatis MappedStatement類的所有方法,對(duì)每一個(gè)方法執(zhí)行以下操作:

獲取該方法上的 DataScope 注解。

檢查注解是否存在且不為空(ObjectUtils.isNotEmpty(annotation))。

檢查方法名是否與之前獲取的 methodName 相同,或者是方法名后加上 _COUNT 后綴的情況。

如果以上條件都滿足,再檢查 DataScope 注解的 enabled() 屬性是否為 true。

如果找到了匹配的方法并且注解啟用,那么調(diào)用 dataScopeFilter 方法,傳入該方法上的 DataScope 注解和 where 參數(shù),進(jìn)行數(shù)據(jù)范圍過(guò)濾。

自定義的dataScopeFilter方法

    /**
     * 根據(jù)注解中的內(nèi)容構(gòu)造 拼接sql,用于數(shù)據(jù)權(quán)限過(guò)濾
     *
     * @param dataPermission 數(shù)據(jù)權(quán)限注解,用于指定表和組織別名等信息
     * @param where 原始sql的where條件表達(dá)式
     * @return 返回拼接后的sql表達(dá)式,添加了數(shù)據(jù)權(quán)限的過(guò)濾條件
     */
    private Expression dataScopeFilter(DataScope dataPermission, Expression where) {
        // 獲取當(dāng)前登錄的用戶
        NutUser user = SecurityUtil.getNutUser();

        String tableAlias = dataPermission.tableAlis(); // 表別名
        String orgAlias = dataPermission.orgAlis(); // 組織別名
        // 構(gòu)造數(shù)據(jù)過(guò)濾的in表達(dá)式
        InExpression inExpression = new InExpression();
        // 設(shè)置左邊的字段表達(dá)式,根據(jù)表和組織別名構(gòu)建
        inExpression.setLeftExpression(buildColumn(tableAlias, orgAlias));
        
        // 使用JSQLParser解析組織ID的查詢語(yǔ)句
        CCJSqlParserManager parserManager = new CCJSqlParserManager();
        Statement statement;
        try {
            // 構(gòu)造查詢當(dāng)前用戶所屬組織及其子組織ID的sql語(yǔ)句
            StringReader statementReader = new StringReader(
                    "select id from sys_org where path like '%" + user.getOrgId() + "%'");
            statement = parserManager.parse(statementReader);
        } catch (JSQLParserException e) {
            // 處理解析異常
            throw new RuntimeException(e);
        }
        Select selectStatement = (Select) statement;
        SubSelect subSelect = new SubSelect();
        subSelect.setSelectBody(selectStatement.getSelectBody()); // 設(shè)置子查詢的查詢體
        inExpression.setRightExpression(subSelect); // 設(shè)置右邊的子查詢表達(dá)式

        // 如果原有where條件不為空,則將數(shù)據(jù)權(quán)限過(guò)濾條件和原有條件用and連接
        return ObjectUtils.isNotEmpty(where) ? new AndExpression(where, new Parenthesis(inExpression)) : inExpression;
    }

buildColumn方法:

 /**
     * 構(gòu)建Column
     *
     * @param tableAlias 表別名
     * @param columnName 字段名稱
     * @return 帶表別名字段
     */
    public static Column buildColumn(String tableAlias, String columnName) {
        if (StringUtils.isNotEmpty(tableAlias)) {
            columnName = tableAlias + "." + columnName;
        }
        return new Column(columnName);
    }

使用:

  /**
     * 分頁(yè)查詢
     *
     * @param page  page
     * @param query query
     */
    @DataScope(tableAlis = "item")
    Page<InfoBO> selectPageQuery(Page page, @Param("query") HandleQuery query);

結(jié)果是實(shí)際的sql上將拼接上:

and (org_id IN (SELECT id FROM sys_org WHERE path LIKE concat('%', 1, '%')))

CCJSqlParserManager類解析

CCJSqlParserManager 類是 JSqlParser 庫(kù)中的一個(gè)關(guān)鍵類,它主要用于管理和執(zhí)行 SQL 語(yǔ)句的解析操作。

JSqlParser 是一個(gè) Java 庫(kù),用于解析 SQL 語(yǔ)言,并將其轉(zhuǎn)化為可遍歷、操作和修改的 Java 對(duì)象模型。

CCJSqlParserManager 主要功能如下:

  1. 初始化解析器資源:該類負(fù)責(zé)初始化和管理 JSqlParser 解析器所需的資源。
  2. 解析 SQL 語(yǔ)句:它可以接受字符串形式的 SQL 查詢,并通過(guò) parse() 方法將其轉(zhuǎn)換成 Statement 對(duì)象,這是一個(gè)抽象類,代表了 SQL 語(yǔ)句的不同類型(如 Select, Update, Delete, Insert 等)。
  3. 處理并發(fā)請(qǐng)求:CCJSqlParserManager 可能會(huì)實(shí)現(xiàn)資源池或其他機(jī)制來(lái)更有效地處理多個(gè)并發(fā)的 SQL 解析請(qǐng)求。
    例如,在上述代碼片段中:
CCJSqlParserManager parserManager = new CCJSqlParserManager();
Statement statement;
try {
    StringReader statementReader = new StringReader("select id from sys_org where path like '%" + user.getOrgId() + "%'");
    statement = parserManager.parse(statementReader);
} catch (JSQLParserException e) {
    throw new RuntimeException(e);
}

這段代碼就是創(chuàng)建了一個(gè) CCJSqlParserManager 實(shí)例,然后使用它來(lái)解析一個(gè) SQL 語(yǔ)句,這個(gè) SQL 語(yǔ)句是為了查詢當(dāng)前用戶及其子組織的 ID。

通過(guò)解析得到的 statement 對(duì)象可以進(jìn)一步被分析或修改,以便進(jìn)行動(dòng)態(tài) SQL 生成、權(quán)限檢查、SQL 優(yōu)化等各種操作。

總結(jié)

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

相關(guān)文章

  • IDEA2020.2.3中創(chuàng)建JavaWeb工程的完整步驟記錄

    IDEA2020.2.3中創(chuàng)建JavaWeb工程的完整步驟記錄

    這篇文章主要給大家介紹了關(guān)于IDEA2020.2.3中創(chuàng)建JavaWeb工程的完整步驟,文中通過(guò)圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • java創(chuàng)建jar包并被項(xiàng)目引用步驟詳解

    java創(chuàng)建jar包并被項(xiàng)目引用步驟詳解

    這篇文章主要介紹了java創(chuàng)建jar包并被項(xiàng)目引用步驟詳解,jar包實(shí)現(xiàn)了特定功能的,java字節(jié)碼文件的壓縮包,更多相關(guān)內(nèi)容需要的朋友可以參考一下
    2022-07-07
  • java的多線程用法編程總結(jié)

    java的多線程用法編程總結(jié)

    本文主要講了java中多線程的使用方法、線程同步、線程數(shù)據(jù)傳遞、線程狀態(tài)及相應(yīng)的一些線程函數(shù)用法、概述等。
    2016-10-10
  • 使用JMF實(shí)現(xiàn)java視頻播放器

    使用JMF實(shí)現(xiàn)java視頻播放器

    這篇文章主要為大家詳細(xì)介紹了使用JMF實(shí)現(xiàn)java視頻播放器的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • mybatis中的test語(yǔ)句失效處理方式

    mybatis中的test語(yǔ)句失效處理方式

    這篇文章主要介紹了mybatis中的test語(yǔ)句失效處理方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • SpringCloud Gateway使用redis實(shí)現(xiàn)動(dòng)態(tài)路由的方法

    SpringCloud Gateway使用redis實(shí)現(xiàn)動(dòng)態(tài)路由的方法

    這篇文章主要介紹了SpringCloud Gateway使用redis實(shí)現(xiàn)動(dòng)態(tài)路由的方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-01-01
  • Spring IoC容器常見(jiàn)獲取Bean的方式匯總示例解析

    Spring IoC容器常見(jiàn)獲取Bean的方式匯總示例解析

    這篇文章主要為大家介紹了Spring IoC容器常見(jiàn)獲取Bean的方式匯總示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-09-09
  • Java設(shè)計(jì)模式之模版方法模式簡(jiǎn)介

    Java設(shè)計(jì)模式之模版方法模式簡(jiǎn)介

    這篇文章主要介紹了Java設(shè)計(jì)模式之模版方法模式,需要的朋友可以參考下
    2014-07-07
  • 養(yǎng)成良好java代碼編碼規(guī)范

    養(yǎng)成良好java代碼編碼規(guī)范

    這篇文章主要介紹了如何養(yǎng)成良好java代碼編碼規(guī)范,規(guī)范需要平時(shí)編碼過(guò)程中注意,是一個(gè)慢慢養(yǎng)成的好習(xí)慣,下面小編就帶大家來(lái)一起詳細(xì)了解一下吧
    2019-06-06
  • Java輕松實(shí)現(xiàn)在Word中插入頁(yè)眉頁(yè)腳的實(shí)用指南

    Java輕松實(shí)現(xiàn)在Word中插入頁(yè)眉頁(yè)腳的實(shí)用指南

    在現(xiàn)代企業(yè)應(yīng)用中,Java 開(kāi)發(fā)者經(jīng)常需要處理各種文檔操作,本文將深入探討如何利用功能強(qiáng)大的 Spire.Doc for Java 庫(kù)輕松實(shí)現(xiàn)各種頁(yè)眉頁(yè)腳的插入需求,需要的小伙伴可以了解下
    2025-09-09

最新評(píng)論

邻水| 大城县| 南木林县| 龙州县| 沙坪坝区| 溆浦县| 南川市| 尉氏县| 韩城市| 山东省| 龙游县| 固始县| 巴楚县| 壶关县| 名山县| 马龙县| 武隆县| 桂阳县| 兴仁县| 平远县| 嘉定区| 鄂温| 固原市| 玛沁县| 漳州市| 临汾市| 翁源县| 治多县| 叙永县| 涞源县| 双城市| 叶城县| 泰宁县| 孝昌县| 安顺市| 灵宝市| 遂宁市| 桑日县| 南昌县| 政和县| 永年县|