Commit b0855cc626d2b9eb4495ea9e2d996df11d8dd090
1 parent
f9b15fe7
实现 DataPermissionRuleFactoryImpl,并增加相关单测
Showing
6 changed files
with
284 additions
and
15 deletions
yudao-framework/yudao-spring-boot-starter-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/aop/DataPermissionAnnotationInterceptor.java
| ... | ... | @@ -34,7 +34,7 @@ public class DataPermissionAnnotationInterceptor implements MethodInterceptor { |
| 34 | 34 | // 入栈 |
| 35 | 35 | DataPermission dataPermission = this.findAnnotation(methodInvocation); |
| 36 | 36 | if (dataPermission != null) { |
| 37 | - DataPermissionContextHolder.push(dataPermission); | |
| 37 | + DataPermissionContextHolder.add(dataPermission); | |
| 38 | 38 | } |
| 39 | 39 | try { |
| 40 | 40 | // 执行逻辑 |
| ... | ... | @@ -42,7 +42,7 @@ public class DataPermissionAnnotationInterceptor implements MethodInterceptor { |
| 42 | 42 | } finally { |
| 43 | 43 | // 出栈 |
| 44 | 44 | if (dataPermission != null) { |
| 45 | - DataPermissionContextHolder.poll(); | |
| 45 | + DataPermissionContextHolder.remove(); | |
| 46 | 46 | } |
| 47 | 47 | } |
| 48 | 48 | } | ... | ... |
yudao-framework/yudao-spring-boot-starter-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/aop/DataPermissionContextHolder.java
| ... | ... | @@ -3,8 +3,8 @@ package cn.iocoder.yudao.framework.datapermission.core.aop; |
| 3 | 3 | import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; |
| 4 | 4 | import com.alibaba.ttl.TransmittableThreadLocal; |
| 5 | 5 | |
| 6 | -import java.util.ArrayDeque; | |
| 7 | -import java.util.Deque; | |
| 6 | +import java.util.LinkedList; | |
| 7 | +import java.util.List; | |
| 8 | 8 | |
| 9 | 9 | /** |
| 10 | 10 | * {@link DataPermission} 注解的 Context 上下文 |
| ... | ... | @@ -13,16 +13,19 @@ import java.util.Deque; |
| 13 | 13 | */ |
| 14 | 14 | public class DataPermissionContextHolder { |
| 15 | 15 | |
| 16 | - private static final ThreadLocal<Deque<DataPermission>> DATA_PERMISSIONS = | |
| 17 | - TransmittableThreadLocal.withInitial(ArrayDeque::new); | |
| 16 | + /** | |
| 17 | + * 使用 List 的原因,可能存在方法的嵌套调用 | |
| 18 | + */ | |
| 19 | + private static final ThreadLocal<LinkedList<DataPermission>> DATA_PERMISSIONS = | |
| 20 | + TransmittableThreadLocal.withInitial(LinkedList::new); | |
| 18 | 21 | |
| 19 | 22 | /** |
| 20 | 23 | * 获得当前的 DataPermission 注解 |
| 21 | 24 | * |
| 22 | 25 | * @return DataPermission 注解 |
| 23 | 26 | */ |
| 24 | - public static DataPermission peek() { | |
| 25 | - return DATA_PERMISSIONS.get().remove(); | |
| 27 | + public static DataPermission get() { | |
| 28 | + return DATA_PERMISSIONS.get().peekLast(); | |
| 26 | 29 | } |
| 27 | 30 | |
| 28 | 31 | /** |
| ... | ... | @@ -30,8 +33,8 @@ public class DataPermissionContextHolder { |
| 30 | 33 | * |
| 31 | 34 | * @param dataPermission DataPermission 注解 |
| 32 | 35 | */ |
| 33 | - public static void push(DataPermission dataPermission) { | |
| 34 | - DATA_PERMISSIONS.get().push(dataPermission); | |
| 36 | + public static void add(DataPermission dataPermission) { | |
| 37 | + DATA_PERMISSIONS.get().addLast(dataPermission); | |
| 35 | 38 | } |
| 36 | 39 | |
| 37 | 40 | /** |
| ... | ... | @@ -39,13 +42,31 @@ public class DataPermissionContextHolder { |
| 39 | 42 | * |
| 40 | 43 | * @return DataPermission 注解 |
| 41 | 44 | */ |
| 42 | - public static DataPermission poll() { | |
| 43 | - DataPermission dataPermission = DATA_PERMISSIONS.get().poll(); | |
| 45 | + public static DataPermission remove() { | |
| 46 | + DataPermission dataPermission = DATA_PERMISSIONS.get().removeLast(); | |
| 44 | 47 | // 无元素时,清空 ThreadLocal |
| 45 | - if (dataPermission == null) { | |
| 48 | + if (DATA_PERMISSIONS.get().isEmpty()) { | |
| 46 | 49 | DATA_PERMISSIONS.remove(); |
| 47 | 50 | } |
| 48 | 51 | return dataPermission; |
| 49 | 52 | } |
| 50 | 53 | |
| 54 | + /** | |
| 55 | + * 获得所有 DataPermission | |
| 56 | + * | |
| 57 | + * @return DataPermission 队列 | |
| 58 | + */ | |
| 59 | + public static List<DataPermission> getAll() { | |
| 60 | + return DATA_PERMISSIONS.get(); | |
| 61 | + } | |
| 62 | + | |
| 63 | + /** | |
| 64 | + * 清空上下文 | |
| 65 | + * | |
| 66 | + * 目前仅仅用于单测 | |
| 67 | + */ | |
| 68 | + public static void clear() { | |
| 69 | + DATA_PERMISSIONS.remove(); | |
| 70 | + } | |
| 71 | + | |
| 51 | 72 | } | ... | ... |
yudao-framework/yudao-spring-boot-starter-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/rule/DataPermissionRuleFactoryImpl.java
| 1 | 1 | package cn.iocoder.yudao.framework.datapermission.core.rule; |
| 2 | 2 | |
| 3 | +import cn.hutool.core.collection.CollUtil; | |
| 4 | +import cn.hutool.core.util.ArrayUtil; | |
| 5 | +import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; | |
| 6 | +import cn.iocoder.yudao.framework.datapermission.core.aop.DataPermissionContextHolder; | |
| 3 | 7 | import lombok.RequiredArgsConstructor; |
| 4 | 8 | |
| 9 | +import java.util.Collections; | |
| 5 | 10 | import java.util.List; |
| 11 | +import java.util.stream.Collectors; | |
| 6 | 12 | |
| 13 | +/** | |
| 14 | + * 默认的 DataPermissionRuleFactoryImpl 实现类 | |
| 15 | + * 支持通过 {@link DataPermissionContextHolder} 过滤数据权限 | |
| 16 | + * | |
| 17 | + * @author 芋道源码 | |
| 18 | + */ | |
| 7 | 19 | @RequiredArgsConstructor |
| 8 | 20 | public class DataPermissionRuleFactoryImpl implements DataPermissionRuleFactory { |
| 9 | 21 | |
| ... | ... | @@ -17,9 +29,34 @@ public class DataPermissionRuleFactoryImpl implements DataPermissionRuleFactory |
| 17 | 29 | return rules; |
| 18 | 30 | } |
| 19 | 31 | |
| 20 | - @Override | |
| 32 | + @Override // mappedStatementId 参数,暂时没有用。以后,可以基于 mappedStatementId + DataPermission 进行缓存 | |
| 21 | 33 | public List<DataPermissionRule> getDataPermissionRule(String mappedStatementId) { |
| 22 | - return null; | |
| 34 | + // 1. 无数据权限 | |
| 35 | + if (CollUtil.isEmpty(rules)) { | |
| 36 | + return Collections.emptyList(); | |
| 37 | + } | |
| 38 | + // 2. 未配置,则默认开启 | |
| 39 | + DataPermission dataPermission = DataPermissionContextHolder.get(); | |
| 40 | + if (dataPermission == null) { | |
| 41 | + return rules; | |
| 42 | + } | |
| 43 | + // 3. 已配置,但禁用 | |
| 44 | + if (!dataPermission.enable()) { | |
| 45 | + return Collections.emptyList(); | |
| 46 | + } | |
| 47 | + | |
| 48 | + // 4. 已配置,只选择部分规则 | |
| 49 | + if (ArrayUtil.isNotEmpty(dataPermission.includeRules())) { | |
| 50 | + return rules.stream().filter(rule -> ArrayUtil.contains(dataPermission.includeRules(), rule.getClass())) | |
| 51 | + .collect(Collectors.toList()); // 一般规则不会太多,所以不采用 HashSet 查询 | |
| 52 | + } | |
| 53 | + // 5. 已配置,只排除部分规则 | |
| 54 | + if (ArrayUtil.isNotEmpty(dataPermission.excludeRules())) { | |
| 55 | + return rules.stream().filter(rule -> !ArrayUtil.contains(dataPermission.excludeRules(), rule.getClass())) | |
| 56 | + .collect(Collectors.toList()); // 一般规则不会太多,所以不采用 HashSet 查询 | |
| 57 | + } | |
| 58 | + // 6. 已配置,全部规则 | |
| 59 | + return rules; | |
| 23 | 60 | } |
| 24 | 61 | |
| 25 | 62 | } | ... | ... |
yudao-framework/yudao-spring-boot-starter-data-permission/src/test/resources/META-INF/spring.factories renamed to yudao-framework/yudao-spring-boot-starter-data-permission/src/main/resources/META-INF/spring.factories
yudao-framework/yudao-spring-boot-starter-data-permission/src/test/java/cn/iocoder/yudao/framework/datapermission/core/aop/DataPermissionContextHolderTest.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.datapermission.core.aop; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; | |
| 4 | +import org.junit.jupiter.api.BeforeEach; | |
| 5 | +import org.junit.jupiter.api.Test; | |
| 6 | + | |
| 7 | +import static org.junit.jupiter.api.Assertions.assertEquals; | |
| 8 | +import static org.junit.jupiter.api.Assertions.assertSame; | |
| 9 | +import static org.mockito.Mockito.mock; | |
| 10 | + | |
| 11 | +/** | |
| 12 | + * {@link DataPermissionContextHolder} 的单元测试 | |
| 13 | + * | |
| 14 | + * @author 芋道源码 | |
| 15 | + */ | |
| 16 | +class DataPermissionContextHolderTest { | |
| 17 | + | |
| 18 | + @BeforeEach | |
| 19 | + public void setUp() { | |
| 20 | + DataPermissionContextHolder.clear(); | |
| 21 | + } | |
| 22 | + | |
| 23 | + @Test | |
| 24 | + public void testGet() { | |
| 25 | + // mock 方法 | |
| 26 | + DataPermission dataPermission01 = mock(DataPermission.class); | |
| 27 | + DataPermissionContextHolder.add(dataPermission01); | |
| 28 | + DataPermission dataPermission02 = mock(DataPermission.class); | |
| 29 | + DataPermissionContextHolder.add(dataPermission02); | |
| 30 | + | |
| 31 | + // 调用 | |
| 32 | + DataPermission result = DataPermissionContextHolder.get(); | |
| 33 | + // 断言 | |
| 34 | + assertSame(result, dataPermission02); | |
| 35 | + } | |
| 36 | + | |
| 37 | + @Test | |
| 38 | + public void testPush() { | |
| 39 | + // 调用 | |
| 40 | + DataPermission dataPermission01 = mock(DataPermission.class); | |
| 41 | + DataPermissionContextHolder.add(dataPermission01); | |
| 42 | + DataPermission dataPermission02 = mock(DataPermission.class); | |
| 43 | + DataPermissionContextHolder.add(dataPermission02); | |
| 44 | + // 断言 | |
| 45 | + DataPermission first = DataPermissionContextHolder.getAll().get(0); | |
| 46 | + DataPermission second = DataPermissionContextHolder.getAll().get(1); | |
| 47 | + assertSame(dataPermission01, first); | |
| 48 | + assertSame(dataPermission02, second); | |
| 49 | + } | |
| 50 | + | |
| 51 | + @Test | |
| 52 | + public void testRemove() { | |
| 53 | + // mock 方法 | |
| 54 | + DataPermission dataPermission01 = mock(DataPermission.class); | |
| 55 | + DataPermissionContextHolder.add(dataPermission01); | |
| 56 | + DataPermission dataPermission02 = mock(DataPermission.class); | |
| 57 | + DataPermissionContextHolder.add(dataPermission02); | |
| 58 | + | |
| 59 | + // 调用 | |
| 60 | + DataPermission result = DataPermissionContextHolder.remove(); | |
| 61 | + // 断言 | |
| 62 | + assertSame(result, dataPermission02); | |
| 63 | + assertEquals(1, DataPermissionContextHolder.getAll().size()); | |
| 64 | + } | |
| 65 | + | |
| 66 | +} | ... | ... |
yudao-framework/yudao-spring-boot-starter-data-permission/src/test/java/cn/iocoder/yudao/framework/datapermission/core/rule/DataPermissionRuleFactoryImplTest.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.datapermission.core.rule; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; | |
| 4 | +import cn.iocoder.yudao.framework.datapermission.core.aop.DataPermissionContextHolder; | |
| 5 | +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; | |
| 6 | +import net.sf.jsqlparser.expression.Alias; | |
| 7 | +import net.sf.jsqlparser.expression.Expression; | |
| 8 | +import org.junit.jupiter.api.BeforeEach; | |
| 9 | +import org.junit.jupiter.api.Test; | |
| 10 | +import org.mockito.InjectMocks; | |
| 11 | +import org.mockito.Spy; | |
| 12 | +import org.springframework.core.annotation.AnnotationUtils; | |
| 13 | + | |
| 14 | +import java.util.Arrays; | |
| 15 | +import java.util.List; | |
| 16 | +import java.util.Set; | |
| 17 | + | |
| 18 | +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString; | |
| 19 | +import static org.junit.jupiter.api.Assertions.*; | |
| 20 | + | |
| 21 | +/** | |
| 22 | + * {@link DataPermissionRuleFactoryImpl} 单元测试 | |
| 23 | + * | |
| 24 | + * @author 芋道源码 | |
| 25 | + */ | |
| 26 | +class DataPermissionRuleFactoryImplTest extends BaseMockitoUnitTest { | |
| 27 | + | |
| 28 | + @InjectMocks | |
| 29 | + private DataPermissionRuleFactoryImpl dataPermissionRuleFactory; | |
| 30 | + | |
| 31 | + @Spy | |
| 32 | + private List<DataPermissionRule> rules = Arrays.asList(new DataPermissionRule01(), | |
| 33 | + new DataPermissionRule02()); | |
| 34 | + | |
| 35 | + @BeforeEach | |
| 36 | + public void setUp() { | |
| 37 | + DataPermissionContextHolder.clear(); | |
| 38 | + } | |
| 39 | + | |
| 40 | + @Test | |
| 41 | + public void testGetDataPermissionRule_02() { | |
| 42 | + // 准备参数 | |
| 43 | + String mappedStatementId = randomString(); | |
| 44 | + | |
| 45 | + // 调用 | |
| 46 | + List<DataPermissionRule> result = dataPermissionRuleFactory.getDataPermissionRule(mappedStatementId); | |
| 47 | + // 断言 | |
| 48 | + assertSame(rules, result); | |
| 49 | + } | |
| 50 | + | |
| 51 | + @Test | |
| 52 | + public void testGetDataPermissionRule_03() { | |
| 53 | + // 准备参数 | |
| 54 | + String mappedStatementId = randomString(); | |
| 55 | + // mock 方法 | |
| 56 | + DataPermissionContextHolder.add(AnnotationUtils.findAnnotation(TestClass03.class, DataPermission.class)); | |
| 57 | + | |
| 58 | + // 调用 | |
| 59 | + List<DataPermissionRule> result = dataPermissionRuleFactory.getDataPermissionRule(mappedStatementId); | |
| 60 | + // 断言 | |
| 61 | + assertTrue(result.isEmpty()); | |
| 62 | + } | |
| 63 | + | |
| 64 | + @Test | |
| 65 | + public void testGetDataPermissionRule_04() { | |
| 66 | + // 准备参数 | |
| 67 | + String mappedStatementId = randomString(); | |
| 68 | + // mock 方法 | |
| 69 | + DataPermissionContextHolder.add(AnnotationUtils.findAnnotation(TestClass04.class, DataPermission.class)); | |
| 70 | + | |
| 71 | + // 调用 | |
| 72 | + List<DataPermissionRule> result = dataPermissionRuleFactory.getDataPermissionRule(mappedStatementId); | |
| 73 | + // 断言 | |
| 74 | + assertEquals(1, result.size()); | |
| 75 | + assertEquals(DataPermissionRule01.class, result.get(0).getClass()); | |
| 76 | + } | |
| 77 | + | |
| 78 | + @Test | |
| 79 | + public void testGetDataPermissionRule_05() { | |
| 80 | + // 准备参数 | |
| 81 | + String mappedStatementId = randomString(); | |
| 82 | + // mock 方法 | |
| 83 | + DataPermissionContextHolder.add(AnnotationUtils.findAnnotation(TestClass05.class, DataPermission.class)); | |
| 84 | + | |
| 85 | + // 调用 | |
| 86 | + List<DataPermissionRule> result = dataPermissionRuleFactory.getDataPermissionRule(mappedStatementId); | |
| 87 | + // 断言 | |
| 88 | + assertEquals(1, result.size()); | |
| 89 | + assertEquals(DataPermissionRule02.class, result.get(0).getClass()); | |
| 90 | + } | |
| 91 | + | |
| 92 | + @Test | |
| 93 | + public void testGetDataPermissionRule_06() { | |
| 94 | + // 准备参数 | |
| 95 | + String mappedStatementId = randomString(); | |
| 96 | + // mock 方法 | |
| 97 | + DataPermissionContextHolder.add(AnnotationUtils.findAnnotation(TestClass06.class, DataPermission.class)); | |
| 98 | + | |
| 99 | + // 调用 | |
| 100 | + List<DataPermissionRule> result = dataPermissionRuleFactory.getDataPermissionRule(mappedStatementId); | |
| 101 | + // 断言 | |
| 102 | + assertSame(rules, result); | |
| 103 | + } | |
| 104 | + | |
| 105 | + @DataPermission(enable = false) | |
| 106 | + static class TestClass03 {} | |
| 107 | + | |
| 108 | + @DataPermission(includeRules = DataPermissionRule01.class) | |
| 109 | + static class TestClass04 {} | |
| 110 | + | |
| 111 | + @DataPermission(excludeRules = DataPermissionRule01.class) | |
| 112 | + static class TestClass05 {} | |
| 113 | + | |
| 114 | + @DataPermission | |
| 115 | + static class TestClass06 {} | |
| 116 | + | |
| 117 | + static class DataPermissionRule01 implements DataPermissionRule { | |
| 118 | + | |
| 119 | + @Override | |
| 120 | + public Set<String> getTableNames() { | |
| 121 | + return null; | |
| 122 | + } | |
| 123 | + | |
| 124 | + @Override | |
| 125 | + public Expression getExpression(String tableName, Alias tableAlias) { | |
| 126 | + return null; | |
| 127 | + } | |
| 128 | + | |
| 129 | + } | |
| 130 | + | |
| 131 | + static class DataPermissionRule02 implements DataPermissionRule { | |
| 132 | + | |
| 133 | + @Override | |
| 134 | + public Set<String> getTableNames() { | |
| 135 | + return null; | |
| 136 | + } | |
| 137 | + | |
| 138 | + @Override | |
| 139 | + public Expression getExpression(String tableName, Alias tableAlias) { | |
| 140 | + return null; | |
| 141 | + } | |
| 142 | + | |
| 143 | + } | |
| 144 | + | |
| 145 | +} | ... | ... |