From 69b95b3e7a3a1438abb03c1c5981f6cc19c22663 Mon Sep 17 00:00:00 2001
From: 疯狂的狮子Li <15040126243@163.com>
Date: 星期四, 16 一月 2025 17:56:29 +0800
Subject: [PATCH] update 优化 默认注释掉slave数据源
---
ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/PlusDataPermissionHandler.java | 208 +++++++++++++++++++++++++++++++++++++++++++++-------
1 files changed, 180 insertions(+), 28 deletions(-)
diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/PlusDataPermissionHandler.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/PlusDataPermissionHandler.java
index 236538a..a354707 100644
--- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/PlusDataPermissionHandler.java
+++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/PlusDataPermissionHandler.java
@@ -1,13 +1,16 @@
package org.dromara.common.mybatis.handler;
+import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
+import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.expression.operators.relational.ParenthesedExpressionList;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
+import org.apache.ibatis.io.Resources;
import org.dromara.common.core.domain.dto.RoleDTO;
import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.core.exception.ServiceException;
@@ -19,17 +22,21 @@
import org.dromara.common.mybatis.enums.DataScopeType;
import org.dromara.common.mybatis.helper.DataPermissionHelper;
import org.dromara.common.satoken.utils.LoginHelper;
+import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.expression.BeanFactoryResolver;
-import org.springframework.expression.BeanResolver;
-import org.springframework.expression.ExpressionParser;
-import org.springframework.expression.ParserContext;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
+import org.springframework.core.io.support.ResourcePatternResolver;
+import org.springframework.core.type.ClassMetadata;
+import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
+import org.springframework.expression.*;
import org.springframework.expression.common.TemplateParserContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
+import org.springframework.util.ClassUtils;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Set;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
/**
@@ -42,6 +49,11 @@
public class PlusDataPermissionHandler {
/**
+ * 绫诲悕绉颁笌娉ㄨВ鐨勬槧灏勫叧绯荤紦瀛�(鐢变簬aop鏃犳硶鎷︽埅mybatis鎺ュ彛绫讳笂鐨勬敞瑙� 鍙兘閫氳繃鍚姩棰勬壂鎻忕殑鏂瑰紡杩涜)
+ */
+ private final Map<String, DataPermission> dataPermissionCacheMap = new ConcurrentHashMap<>();
+
+ /**
* spel 瑙f瀽鍣�
*/
private final ExpressionParser parser = new SpelExpressionParser();
@@ -50,6 +62,15 @@
* bean瑙f瀽鍣� 鐢ㄤ簬澶勭悊 spel 琛ㄨ揪寮忎腑瀵� bean 鐨勮皟鐢�
*/
private final BeanResolver beanResolver = new BeanFactoryResolver(SpringUtils.getBeanFactory());
+
+ /**
+ * 鏋勯�犳柟娉曪紝鎵弿鎸囧畾鍖呬笅鐨� Mapper 绫诲苟鍒濆鍖栫紦瀛�
+ *
+ * @param mapperPackage Mapper 绫绘墍鍦ㄧ殑鍖呰矾寰�
+ */
+ public PlusDataPermissionHandler(String mapperPackage) {
+ scanMapperClasses(mapperPackage);
+ }
/**
* 鑾峰彇鏁版嵁杩囨护鏉′欢鐨� SQL 鐗囨
@@ -62,7 +83,7 @@
public Expression getSqlSegment(Expression where, String mappedStatementId, boolean isSelect) {
try {
// 鑾峰彇鏁版嵁鏉冮檺閰嶇疆
- DataPermission dataPermission = DataPermissionHelper.getPermission();
+ DataPermission dataPermission = getDataPermission(mappedStatementId);
// 鑾峰彇褰撳墠鐧诲綍鐢ㄦ埛淇℃伅
LoginUser currentUser = DataPermissionHelper.getVariable("user");
if (ObjectUtil.isNull(currentUser)) {
@@ -108,10 +129,33 @@
joinStr = " " + dataPermission.joinStr() + " ";
}
LoginUser user = DataPermissionHelper.getVariable("user");
- StandardEvaluationContext context = new StandardEvaluationContext();
+ Object defaultValue = "-1";
+ NullSafeStandardEvaluationContext context = new NullSafeStandardEvaluationContext(defaultValue);
+ context.addPropertyAccessor(new NullSafePropertyAccessor(context.getPropertyAccessors().get(0), defaultValue));
context.setBeanResolver(beanResolver);
DataPermissionHelper.getContext().forEach(context::setVariable);
Set<String> conditions = new HashSet<>();
+ // 浼樺厛璁剧疆鍙橀噺
+ List<String> keys = new ArrayList<>();
+ Map<DataColumn, Boolean> ignoreMap = new HashMap<>();
+ for (DataColumn dataColumn : dataPermission.value()) {
+ if (dataColumn.key().length != dataColumn.value().length) {
+ throw new ServiceException("瑙掕壊鏁版嵁鑼冨洿寮傚父 => key涓巚alue闀垮害涓嶅尮閰�");
+ }
+ // 鍖呭惈鏉冮檺鏍囪瘑绗� 杩欑洿鎺ヨ烦杩�
+ if (StringUtils.isNotBlank(dataColumn.permission()) &&
+ CollUtil.contains(user.getMenuPermission(), dataColumn.permission())
+ ) {
+ ignoreMap.put(dataColumn, Boolean.TRUE);
+ continue;
+ }
+ // 璁剧疆娉ㄨВ鍙橀噺 key 涓鸿〃杈惧紡鍙橀噺 value 涓哄彉閲忓��
+ for (int i = 0; i < dataColumn.key().length; i++) {
+ context.setVariable(dataColumn.key()[i], dataColumn.value()[i]);
+ }
+ keys.addAll(Arrays.stream(dataColumn.key()).map(key -> "#" + key).toList());
+ }
+
for (RoleDTO role : user.getRoles()) {
user.setRoleId(role.getRoleId());
// 鑾峰彇瑙掕壊鏉冮檺娉涘瀷
@@ -121,33 +165,25 @@
}
// 鍏ㄩ儴鏁版嵁鏉冮檺鐩存帴杩斿洖
if (type == DataScopeType.ALL) {
- return "";
+ return StringUtils.EMPTY;
}
boolean isSuccess = false;
for (DataColumn dataColumn : dataPermission.value()) {
- if (dataColumn.key().length != dataColumn.value().length) {
- throw new ServiceException("瑙掕壊鏁版嵁鑼冨洿寮傚父 => key涓巚alue闀垮害涓嶅尮閰�");
- }
- // 涓嶅寘鍚� key 鍙橀噺 鍒欎笉澶勭悊
- if (!StringUtils.containsAny(type.getSqlTemplate(),
- Arrays.stream(dataColumn.key()).map(key -> "#" + key).toArray(String[]::new)
- )) {
- continue;
- }
// 鍖呭惈鏉冮檺鏍囪瘑绗� 杩欑洿鎺ヨ烦杩�
- if (StringUtils.isNotBlank(dataColumn.permission()) &&
- CollUtil.contains(user.getMenuPermission(), dataColumn.permission())
- ) {
+ if (ignoreMap.containsKey(dataColumn)) {
// 淇澶氳鑹蹭笌鏉冮檺鏍囪瘑绗﹀叡鐢ㄩ棶棰� https://gitee.com/dromara/RuoYi-Vue-Plus/issues/IB4CS4
conditions.add(joinStr + " 1 = 1 ");
isSuccess = true;
continue;
}
- // 璁剧疆娉ㄨВ鍙橀噺 key 涓鸿〃杈惧紡鍙橀噺 value 涓哄彉閲忓��
- for (int i = 0; i < dataColumn.key().length; i++) {
- context.setVariable(dataColumn.key()[i], dataColumn.value()[i]);
+ // 涓嶅寘鍚� key 鍙橀噺 鍒欎笉澶勭悊
+ if (!StringUtils.containsAny(type.getSqlTemplate(), keys.toArray(String[]::new))) {
+ continue;
}
-
+ // 褰撳墠娉ㄨВ涓嶆弧瓒虫ā鏉� 涓嶅鐞�
+ if (!StringUtils.containsAny(type.getSqlTemplate(), dataColumn.key())) {
+ continue;
+ }
// 蹇界暐鏁版嵁鏉冮檺 闃叉spel琛ㄨ揪寮忓唴鏈夊叾浠杝ql鏌ヨ瀵艰嚧姝诲惊鐜皟鐢�
String sql = DataPermissionHelper.ignore(() ->
parser.parseExpression(type.getSqlTemplate(), parserContext).getValue(context, String.class)
@@ -166,15 +202,131 @@
String sql = StreamUtils.join(conditions, Function.identity(), "");
return sql.substring(joinStr.length());
}
- return "";
+ return StringUtils.EMPTY;
+ }
+
+ /**
+ * 鎵弿鎸囧畾鍖呬笅鐨� Mapper 绫伙紝骞舵煡鎵惧叾涓甫鏈夌壒瀹氭敞瑙g殑鏂规硶鎴栫被
+ *
+ * @param mapperPackage Mapper 绫绘墍鍦ㄧ殑鍖呰矾寰�
+ */
+ private void scanMapperClasses(String mapperPackage) {
+ // 鍒涘缓璧勬簮瑙f瀽鍣ㄥ拰鍏冩暟鎹鍙栧伐鍘�
+ PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
+ CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
+ // 灏� Mapper 鍖呰矾寰勬寜鍒嗛殧绗︽媶鍒嗕负鏁扮粍
+ String[] packagePatternArray = StringUtils.splitPreserveAllTokens(mapperPackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
+ String classpath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX;
+ try {
+ for (String packagePattern : packagePatternArray) {
+ // 灏嗗寘璺緞杞崲涓鸿祫婧愯矾寰�
+ String path = ClassUtils.convertClassNameToResourcePath(packagePattern);
+ // 鑾峰彇鎸囧畾璺緞涓嬬殑鎵�鏈� .class 鏂囦欢璧勬簮
+ Resource[] resources = resolver.getResources(classpath + path + "/*.class");
+ for (Resource resource : resources) {
+ // 鑾峰彇璧勬簮鐨勭被鍏冩暟鎹�
+ ClassMetadata classMetadata = factory.getMetadataReader(resource).getClassMetadata();
+ // 鑾峰彇璧勬簮瀵瑰簲鐨勭被瀵硅薄
+ Class<?> clazz = Resources.classForName(classMetadata.getClassName());
+ // 鏌ユ壘绫讳腑鐨勭壒瀹氭敞瑙�
+ if (AnnotationUtil.hasAnnotation(clazz, DataPermission.class)) {
+ DataPermission dataPermission = AnnotationUtil.getAnnotation(clazz, DataPermission.class);
+ dataPermissionCacheMap.put(clazz.getName(), dataPermission);
+ }
+ }
+ }
+ } catch (Exception e) {
+ log.error("鍒濆鍖栨暟鎹畨鍏ㄧ紦瀛樻椂鍑洪敊:{}", e.getMessage());
+ }
+ }
+
+ /**
+ * 鏍规嵁鏄犲皠璇彞 ID 鎴栫被鍚嶈幏鍙栧搴旂殑 DataPermission 娉ㄨВ瀵硅薄
+ *
+ * @param mapperId 鏄犲皠璇彞 ID
+ * @return DataPermission 娉ㄨВ瀵硅薄锛屽鏋滀笉瀛樺湪鍒欒繑鍥� null
+ */
+ public DataPermission getDataPermission(String mapperId) {
+ // 妫�鏌ヤ笂涓嬫枃涓槸鍚﹀寘鍚槧灏勮鍙� ID 瀵瑰簲鐨� DataPermission 娉ㄨВ瀵硅薄
+ if (DataPermissionHelper.getPermission() != null) {
+ return DataPermissionHelper.getPermission();
+ }
+ // 濡傛灉缂撳瓨涓笉鍖呭惈鏄犲皠璇彞 ID 瀵瑰簲鐨� DataPermission 娉ㄨВ瀵硅薄锛屽垯灏濊瘯浣跨敤绫诲悕浣滀负閿煡鎵�
+ String clazzName = mapperId.substring(0, mapperId.lastIndexOf("."));
+ if (dataPermissionCacheMap.containsKey(clazzName)) {
+ return dataPermissionCacheMap.get(clazzName);
+ }
+ return null;
}
/**
* 妫�鏌ョ粰瀹氱殑鏄犲皠璇彞 ID 鏄惁鏈夋晥锛屽嵆鏄惁鑳藉鎵惧埌瀵瑰簲鐨� DataPermission 娉ㄨВ瀵硅薄
*
+ * @param mapperId 鏄犲皠璇彞 ID
* @return 濡傛灉鎵惧埌瀵瑰簲鐨� DataPermission 娉ㄨВ瀵硅薄锛屽垯杩斿洖 false锛涘惁鍒欒繑鍥� true
*/
- public boolean invalid() {
- return DataPermissionHelper.getPermission() == null;
+ public boolean invalid(String mapperId) {
+ return getDataPermission(mapperId) == null;
}
+
+ /**
+ * 瀵规墍鏈塶ull鍙橀噺鎵句笉鍒扮殑鍙橀噺杩斿洖榛樿鍊�
+ */
+ @AllArgsConstructor
+ private static class NullSafeStandardEvaluationContext extends StandardEvaluationContext {
+
+ private final Object defaultValue;
+
+ @Override
+ public Object lookupVariable(String name) {
+ Object obj = super.lookupVariable(name);
+ // 濡傛灉璇诲彇鍒扮殑鍊兼槸 null锛屽垯杩斿洖榛樿鍊�
+ if (obj == null) {
+ return defaultValue;
+ }
+ return obj;
+ }
+
+ }
+
+ /**
+ * 瀵规墍鏈塶ull鍙橀噺鎵句笉鍒扮殑鍙橀噺杩斿洖榛樿鍊� 濮旀墭妯″紡 灏嗕笉闇�瑕佸鐞嗙殑鏂规硶濮旀墭缁欏師澶勭悊鍣�
+ */
+ @AllArgsConstructor
+ private static class NullSafePropertyAccessor implements PropertyAccessor {
+
+ private final PropertyAccessor delegate;
+ private final Object defaultValue;
+
+ @Override
+ public Class<?>[] getSpecificTargetClasses() {
+ return delegate.getSpecificTargetClasses();
+ }
+
+ @Override
+ public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException {
+ return delegate.canRead(context, target, name);
+ }
+
+ @Override
+ public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException {
+ TypedValue value = delegate.read(context, target, name);
+ // 濡傛灉璇诲彇鍒扮殑鍊兼槸 null锛屽垯杩斿洖榛樿鍊�
+ if (value.getValue() == null) {
+ return new TypedValue(defaultValue);
+ }
+ return value;
+ }
+
+ @Override
+ public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException {
+ return delegate.canWrite(context, target, name);
+ }
+
+ @Override
+ public void write(EvaluationContext context, Object target, String name, Object newValue) throws AccessException {
+ delegate.write(context, target, name, newValue);
+ }
+ }
+
}
--
Gitblit v1.9.3