亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

怎么用Springboot+mybatis-plus+注解實現數據權限隔離

發布時間:2022-04-02 16:02:38 來源:億速云 閱讀:754 作者:iii 欄目:移動開發

今天小編給大家分享一下怎么用Springboot+mybatis-plus+注解實現數據權限隔離的相關知識點,內容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。

1.創建注解

當此注解打在類上,不需要傳參,該類下所有查詢接口開啟數據隔離;打在方法上默認開啟數據隔離,傳參為false則該方法關閉驗證

/**
 * 數據權限驗證注解
 * @author xiaohua
 * @date 2021/6/23
 */
@Documented
@Target({METHOD, ANNOTATION_TYPE, TYPE})
@Retention(RUNTIME)
public @interface DataPermission {
    /**
     * 是否要進行數據權限隔離
     */
    boolean isPermi() default true;
}

2. 具體實現

@Component
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
public class DataPermissionInterceptor implements Interceptor {
    private static final Logger logger = LoggerFactory.getLogger(DataPermissionInterceptor.class);

    @Autowired
    private TokenService tokenService;

    //掃描的包路徑(根據自己的項目路徑來),這里是取的配置里的包路徑
    @Value("${permission.package-path}")
    private String packagePath;

    private final static String DEPT_ID = "dept_id";

    private final static String USER_ID = "create_user";

    private static List<String> classNames;

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        try {
            LoginInfo user = tokenService.getLoginInfo();
            if (user == null){
                return invocation.proceed();
            }

            List<Long> deptIds = (List<Long>) Convert.toList(user.getDataScope());
            if (deptIds == null){
                deptIds = new ArrayList<>();
            }
            //反射掃包會比較慢,這里做了個懶加載
            if (classNames == null) {
                synchronized (LazyInit.class){
                    if (classNames == null){
                        //掃描指定包路徑下所有包含指定注解的類
                        Set<Class<?>> classSet = ClassUtil.scanPackageByAnnotation(packagePath, DataPermission.class);
                        if (classSet == null && classSet.size() == 0){
                            classNames = new ArrayList<>();
                        } else {
                            //取得類全名
                            classNames =  classSet.stream().map(Class::getName).collect(Collectors.toList());
                        }
                    }
                }
            }

            // 拿到mybatis的一些對象
            StatementHandler statementHandler = PluginUtils.realTarget(invocation.getTarget());
            MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
            MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");

            // mappedStatement.getId()為執行的mapper方法的全路徑名,newId為執行的mapper方法的類全名
            String newId = mappedStatement.getId().substring(0, mappedStatement.getId().lastIndexOf("."));
            // 如果不是指定的方法,直接結束攔截
            if (!classNames.contains(newId)) {
                return invocation.proceed();
            }
            String newName = mappedStatement.getId().substring(mappedStatement.getId().lastIndexOf(".") + 1, mappedStatement.getId().length());
            //是否開啟數據權限
            boolean isPermi = true;
            Class<?> clazz = Class.forName(newId);
            //遍歷方法
            for (Method method : clazz.getDeclaredMethods()) {
                //方法是否含有DataPermission注解,如果含有注解則將數據結果過濾
                if (method.isAnnotationPresent(DataPermission.class) && newName.equals(method.getName())) {
                    DataPermission dataPermission =  method.getAnnotation(DataPermission.class);
                    if (dataPermission != null) {
                        //不驗證
                        if (!dataPermission.isPermi()) {
                            isPermi = false;
                        } else { //開啟驗證
                            isPermi = true;
                        }
                    }
                }
            }

            if (isPermi){
                // 獲取到原始sql語句
                String sql = statementHandler.getBoundSql().getSql();

                // 解析并返回新的SQL語句,只處理查詢sql
                if (mappedStatement.getSqlCommandType().toString().equals("SELECT")) {
    //                    String newSql = getNewSql(sql,deptIds,user.getUserId());
                    sql = getSql(sql,deptIds,user.getUserId());
                }
                // 修改sql
                metaObject.setValue("delegate.boundSql.sql", sql);
            }
            return invocation.proceed();
        } catch (Exception e){
            logger.error("數據權限隔離異常:", e);
            return invocation.proceed();
        }

    }
    
    
    /**
     * 解析SQL語句,并返回新的SQL語句
     * 注意,該方法使用了JSqlParser來操作SQL,該依賴包Mybatis-plus已經集成了。如果要單獨使用,請先自行導入依賴
     *
     * @param sql 原SQL
     * @return 新SQL
     */
    private String getSql(String sql,List<Long> deptIds,Long userId) {

        try {
            String condition = "";
            String permissionSql = "(";
            if (deptIds.size() > 0){
                for (Long deptId : deptIds) {
                    if ("(".equals(permissionSql)){
                        permissionSql = permissionSql + deptId;
                    } else {
                        permissionSql = permissionSql + "," + deptId;
                    }
                }
                permissionSql = permissionSql + ")";
                // 修改原語句
                condition = DEPT_ID +" in " + permissionSql;
            } else {
                condition = USER_ID +" = " + userId;
            }

            if (StringUtils.isBlank(condition)){
                return sql;
            }
            Select select = (Select)CCJSqlParserUtil.parse(sql);
            PlainSelect plainSelect = (PlainSelect)select.getSelectBody();
            //取得原SQL的where條件
            final Expression expression = plainSelect.getWhere();
            //增加新的where條件
            final Expression envCondition = CCJSqlParserUtil.parseCondExpression(condition);
            if (expression == null) {
                plainSelect.setWhere(envCondition);
            } else {
                AndExpression andExpression = new AndExpression(expression, envCondition);
                plainSelect.setWhere(andExpression);
            }
            return plainSelect.toString();
        } catch (JSQLParserException e) {
            logger.error("解析原SQL并構建新SQL錯誤:" + e);
            return sql;
        }
    }

以上就是“怎么用Springboot+mybatis-plus+注解實現數據權限隔離”這篇文章的所有內容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

凤阳县| 钦州市| 广安市| 中阳县| 新干县| 肃宁县| 边坝县| 青州市| 县级市| 革吉县| 徐水县| 阿尔山市| 蓬溪县| 泾源县| 广丰县| 寻乌县| 南江县| 云浮市| 安塞县| 贞丰县| 黄梅县| 宣恩县| 济阳县| 江山市| 巴彦淖尔市| 孟州市| 延寿县| 澳门| 玛多县| 贺兰县| 沙坪坝区| 商城县| 集安市| 马关县| 呼图壁县| 佛冈县| 阿图什市| 广水市| 丰原市| 乌兰浩特市| 宣汉县|