diff --git a/ruoyi-admin/src/test/java/org/dromara/test/mapper/CustomSqlTest.java b/ruoyi-admin/src/test/java/org/dromara/test/mapper/CustomSqlTest.java new file mode 100644 index 000000000..5c6a0a3a8 --- /dev/null +++ b/ruoyi-admin/src/test/java/org/dromara/test/mapper/CustomSqlTest.java @@ -0,0 +1,41 @@ +package org.dromara.test.mapper; + +public class CustomSqlTest { + /** + * mapper 接口 + * @Mapper + * public interface ILoanMapper extends BaseMapper { + * @DataPermission({ + * @DataColumn(key = DataColumn.CUSTOM_SQL, value = "(#{#trackerId} = #{#user.userId} or #{#salespersonId} = #{#user.userId})"), + * @DataColumn(key = {"trackerId", "salespersonId"}, value = {"l.tracker_id", "l.salesperson_id"}), + * }) + * Page selectPageLoanList(@Param("page") Page page, @Param(Constants.WRAPPER) Wrapper queryWrapper); + * } + * + * mapper 文件 + * + * + * 实体 + * public class Loan extends TenantEntity { + * private Long id; + * //业务员 + * private Long salespersonId; + * //跟单员 + * private Long trackerId; + * ..... + * } + * + * //结果: 业务员 与 跟单员都只能看自己的数据,但每条数据 既有跟单员也有业务员 + * select * from zr_loan where (l.tracker_id = 1 or l.salesperson_id = 1) + */ +} diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/annotation/DataColumn.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/annotation/DataColumn.java index 2879b9d1c..29b5d5cd6 100644 --- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/annotation/DataColumn.java +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/annotation/DataColumn.java @@ -15,6 +15,7 @@ import java.lang.annotation.*; @Retention(RetentionPolicy.RUNTIME) @Documented public @interface DataColumn { + String CUSTOM_SQL = "CustomSql"; /** * 数据权限模板的占位符关键字,默认为 "deptName" diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataScopeType.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataScopeType.java index 455cecb2e..d50ad352f 100644 --- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataScopeType.java +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataScopeType.java @@ -4,6 +4,7 @@ import lombok.AllArgsConstructor; import lombok.Getter; import org.dromara.common.core.domain.model.LoginUser; import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.annotation.DataColumn; import org.dromara.common.mybatis.helper.DataPermissionHelper; /** @@ -56,7 +57,12 @@ public enum DataScopeType { * 使用 SpEL 表达式:`#{#userName} = #{#user.userId}` * 如果不满足条件,则使用默认 SQL 表达式:`1 = 0` */ - SELF("5", " #{#userName} = #{#user.userId} ", " 1 = 0 "); + SELF("5", " #{#userName} = #{#user.userId} ", " 1 = 0 "), + + /** + * 弹性数据权限(通过自定义SQL实现) + */ + CUSTOM_SQL("6", " {" + DataColumn.CUSTOM_SQL + "} ", " 1 = 0 "); private final String code; 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 61c86ff36..6f6435acd 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 @@ -3,6 +3,7 @@ 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 cn.hutool.core.util.StrUtil; import lombok.extern.slf4j.Slf4j; import net.sf.jsqlparser.JSQLParserException; import net.sf.jsqlparser.expression.Expression; @@ -37,10 +38,7 @@ import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.util.ClassUtils; import java.lang.reflect.Method; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; @@ -147,13 +145,23 @@ public class PlusDataPermissionHandler { if (type == DataScopeType.ALL) { return ""; } + + String sqlTemplate = type.getSqlTemplate(); + if (type == DataScopeType.CUSTOM_SQL) { + //自定义SQL逻辑 + DataColumn customColum = Arrays.stream(dataColumns).filter(c -> Arrays.asList(c.key()).contains(DataColumn.CUSTOM_SQL)).findFirst().orElseThrow(() -> new ServiceException("角色数据范围异常key配置异常 => " + role.getDataScope())); + Map map = new HashMap<>(); + map.put(DataColumn.CUSTOM_SQL, customColum.value()[0]); + sqlTemplate = StrUtil.format(sqlTemplate, map); + } + boolean isSuccess = false; for (DataColumn dataColumn : dataPermission.value()) { if (dataColumn.key().length != dataColumn.value().length) { throw new ServiceException("角色数据范围异常 => key与value长度不匹配"); } // 不包含 key 变量 则不处理 - if (!StringUtils.containsAny(type.getSqlTemplate(), + if (!StringUtils.containsAny(sqlTemplate, Arrays.stream(dataColumn.key()).map(key -> "#" + key).toArray(String[]::new) )) { continue; @@ -170,7 +178,7 @@ public class PlusDataPermissionHandler { } // 解析sql模板并填充 - String sql = parser.parseExpression(type.getSqlTemplate(), parserContext).getValue(context, String.class); + String sql = parser.parseExpression(sqlTemplate, parserContext).getValue(context, String.class); conditions.add(joinStr + sql); isSuccess = true; }