diff --git a/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/annotation/DataPermission.java b/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/annotation/DataPermission.java index 75b322e..5704da2 100644 --- a/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/annotation/DataPermission.java +++ b/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/annotation/DataPermission.java @@ -1,5 +1,6 @@ package cn.axzo.framework.datapermission.annotation; +import cn.axzo.framework.datapermission.rule.OrgDefaultRule; import cn.axzo.framework.datapermission.rule.DataPermissionRule; /** @@ -8,9 +9,9 @@ import cn.axzo.framework.datapermission.rule.DataPermissionRule; * @date 2024/5/30 17:57 */ public @interface DataPermission { - boolean enable() default false; + boolean enable() default true; - Class[] includeRule() default {}; + Class includeRule() default OrgDefaultRule.class; String bizCode() default ""; diff --git a/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/aop/DataPermissionFilter.java b/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/aop/DataPermissionFilter.java index ee41cad..56a2001 100644 --- a/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/aop/DataPermissionFilter.java +++ b/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/aop/DataPermissionFilter.java @@ -1,16 +1,61 @@ package cn.axzo.framework.datapermission.aop; +import cn.axzo.framework.auth.domain.ContextInfo; +import cn.axzo.framework.auth.domain.ContextInfoHolder; import cn.axzo.framework.datapermission.annotation.DataPermission; -import cn.axzo.framework.datapermission.config.DataPermissionConfig; +import cn.axzo.framework.datapermission.context.DataPermissionContextHolder; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.BooleanUtils; +import org.springframework.core.annotation.Order; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.HandlerInterceptor; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; /** * * @author tanjie@axzo.cn * @date 2024/5/31 16:37 */ -public class DataPermissionFilter { +@Order(2) +@Slf4j +public class DataPermissionFilter implements HandlerInterceptor { - // 拦截@DataPermission - // 设置DataPermissionContext + /** + * 拦截@DataPermission + * 设置DataPermissionContext + * @param request + * @param response + * @param handler + * @return + * @throws Exception + */ + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) + throws Exception { + if (handler instanceof HandlerMethod) { + HandlerMethod handlerMethod = (HandlerMethod) handler; + DataPermission dataPermission = handlerMethod.getMethodAnnotation(DataPermission.class); + if (dataPermission == null || BooleanUtils.isNotTrue(dataPermission.enable())) { + return true; + } + + DataPermissionContextHolder.DataPermissionContext dataPermissionContext = DataPermissionContextHolder.DataPermissionContext.builder() + .dataPermission(dataPermission) + .build(); + + // 有数据权限注解,但没用户信息,让后面拦截器做处理更合理(可以返回空数据或者不阻塞业务正常查询数据) + ContextInfo contextInfo = ContextInfoHolder.get(); + if (contextInfo != null) { + dataPermissionContext.setWorkspaceId(contextInfo.getWorkspaceId()); + dataPermissionContext.setOuId(contextInfo.getOuId()); + dataPermissionContext.setPersonId(contextInfo.getUserInfo().getPersonId()); + } + + DataPermissionContextHolder.setContext(dataPermissionContext); + } + return true; + } } diff --git a/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/aop/DataPermissionMybatisInterceptor.java b/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/aop/DataPermissionMybatisInterceptor.java index f579435..cb03997 100644 --- a/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/aop/DataPermissionMybatisInterceptor.java +++ b/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/aop/DataPermissionMybatisInterceptor.java @@ -4,6 +4,8 @@ import cn.axzo.framework.datapermission.annotation.DataPermission; import cn.axzo.framework.datapermission.context.DataPermissionContextFactory; import cn.axzo.framework.datapermission.context.DataPermissionContextHolder; import cn.axzo.framework.datapermission.rule.DataPermissionRule; +import cn.axzo.karma.client.feign.tyr.response.MatchDataObjectResp; +import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.parser.SqlParserHelper; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import com.baomidou.mybatisplus.core.toolkit.PluginUtils; @@ -52,9 +54,10 @@ import java.util.Optional; * @date 2024/5/31 11:41 */ @RequiredArgsConstructor -public class DataPermissionMybatisInterceptor extends JsqlParserSupport implements InnerInterceptor { +public class DataPermissionMybatisInterceptor extends JsqlParserSupport implements InnerInterceptor { private final DataPermissionContextFactory dataPermissionContextFactory; + @Override public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException { if (!filter()) { @@ -315,7 +318,9 @@ public class DataPermissionMybatisInterceptor extends JsqlParserSupport implem private boolean filter() { DataPermissionContextHolder.DataPermissionContext dataPermissionContext = DataPermissionContextHolder.get(); - if (null == dataPermissionContext|| !dataPermissionContext.getDataPermission().enable()) { + if (null == dataPermissionContext + || dataPermissionContext.getDataPermission() == null + || !dataPermissionContext.getDataPermission().enable()) { return false; } diff --git a/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/config/DataPermissionConfig.java b/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/config/DataPermissionConfig.java index 78c911f..ceea116 100644 --- a/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/config/DataPermissionConfig.java +++ b/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/config/DataPermissionConfig.java @@ -2,15 +2,11 @@ package cn.axzo.framework.datapermission.config; import cn.axzo.framework.datapermission.aop.DataPermissionMybatisInterceptor; import cn.axzo.framework.datapermission.context.DataPermissionContextFactory; -import cn.axzo.framework.datapermission.rule.DataPermissionDefaultRule; import cn.axzo.framework.datapermission.rule.DataPermissionRule; -import cn.axzo.karma.client.feign.FlowSupportApi; -import cn.hutool.extra.spring.SpringUtil; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.context.annotation.Bean; -import java.net.DatagramSocketImplFactory; import java.util.List; /** @@ -20,12 +16,6 @@ import java.util.List; @ConditionalOnBean(MybatisPlusInterceptor.class) public class DataPermissionConfig { - @Bean - public DataPermissionDefaultRule deptDataPermissionRule(FlowSupportApi permissionApi) { - // 创建 DeptDataPermissionRule 对象 - return new DataPermissionDefaultRule(permissionApi); - } - @Bean @ConditionalOnBean(MybatisPlusInterceptor.class) public DataPermissionMybatisInterceptor mybatisDataPermissionInterceptor(MybatisPlusInterceptor mybatisPlusInterceptor, DataPermissionContextFactory dataPermissionContextFactory) { diff --git a/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/context/DataPermissionContextFactory.java b/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/context/DataPermissionContextFactory.java index 6c1c7c2..5cc2dab 100644 --- a/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/context/DataPermissionContextFactory.java +++ b/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/context/DataPermissionContextFactory.java @@ -4,8 +4,8 @@ import cn.axzo.framework.datapermission.annotation.DataPermission; import cn.axzo.framework.datapermission.rule.DataPermissionRule; import lombok.AllArgsConstructor; -import java.util.Arrays; import java.util.List; +import java.util.Objects; import java.util.stream.Collectors; /** @@ -23,8 +23,8 @@ public class DataPermissionContextFactory { } public List getRuleByDataPermission(DataPermission dataPermission) { - Class[] classes = dataPermission.includeRule(); - return rules.stream().filter(rule -> Arrays.stream(classes).anyMatch(e -> e.equals(rule.getClass()))).collect(Collectors.toList()); + Class classes = dataPermission.includeRule(); + return rules.stream().filter(rule -> Objects.equals(classes, rule.getClass())).collect(Collectors.toList()); } } diff --git a/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/context/DataPermissionContextHolder.java b/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/context/DataPermissionContextHolder.java index 6dcabcf..99abfce 100644 --- a/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/context/DataPermissionContextHolder.java +++ b/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/context/DataPermissionContextHolder.java @@ -2,7 +2,10 @@ package cn.axzo.framework.datapermission.context; import cn.axzo.framework.datapermission.annotation.DataPermission; import com.google.common.collect.Maps; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; +import lombok.NoArgsConstructor; import java.util.Map; @@ -16,6 +19,15 @@ public class DataPermissionContextHolder { private final static ThreadLocal DATA_PERMISSION_CONTEXT = new ThreadLocal<>(); + public static final String SELF_SUBORDINATE = "SELF_SUBORDINATE"; + public static final String DEPARTMENT_ONLY = "DEPARTMENT_ONLY"; + public static final String DEPARTMENT_SUBORDINATE = "DEPARTMENT_SUBORDINATE"; + public static final String UNIT_ONLY = "UNIT_ONLY"; + public static final String UNIT_ONLY_EXCLUDE_TEAM = "UNIT_ONLY_EXCLUDE_TEAM"; + public static final String UNIT_DIRECT_SUBORDINATE = "UNIT_DIRECT_SUBORDINATE"; + public static final String UNIT_COOPERATE_SUBORDINATE = "UNIT_COOPERATE_SUBORDINATE"; + public static final String UNIT_ALL_SUBORDINATE = "UNIT_ALL_SUBORDINATE"; + public static final String WORKSPACE = "WORKSPACE"; public static void setContext(DataPermissionContext dataPermission) { DATA_PERMISSION_CONTEXT.set(dataPermission); @@ -23,6 +35,9 @@ public class DataPermissionContextHolder { @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor public static class DataPermissionContext { private DataPermission dataPermission; private Long ouId; @@ -48,6 +63,10 @@ public class DataPermissionContextHolder { * */ private Map permissionDataCache = Maps.newConcurrentMap(); + + public void putPermissionData(String key, Object value) { + permissionDataCache.put(key, value); + } } public static void remove() { diff --git a/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/dataObject/DataObjectRule.java b/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/dataObject/DataObjectRule.java new file mode 100644 index 0000000..87f74d1 --- /dev/null +++ b/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/dataObject/DataObjectRule.java @@ -0,0 +1,65 @@ +package cn.axzo.framework.datapermission.dataObject; + +import cn.axzo.karma.client.feign.tyr.response.MatchDataObjectResp; +import com.google.common.collect.Sets; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.util.CollectionUtils; + +import java.util.List; +import java.util.Objects; +import java.util.Set; + +public interface DataObjectRule { + + /** + * 解析规则,返回解析后的数据 + * @param context + * @return + */ + void resolve(DataObjectRuleContext context); + + /** + * 查询规则的id + * @return + */ + Integer getRulePermissionId(); + + @Data + @Builder + @AllArgsConstructor + @NoArgsConstructor + class DataObjectRuleContext { + + /** + * 解析后的人员id + */ + @Builder.Default + private Set personIds = Sets.newHashSet(); + + /** + * 解析后的部门id + */ + @Builder.Default + private Set nodeIds = Sets.newHashSet(); + + public void addPersonIds(Set personIds) { + this.getPersonIds().addAll(personIds); + } + + public void addNodeIds(Set nodeIds) { + this.getNodeIds().addAll(nodeIds); + } + } + + default boolean match(List rules) { + if (CollectionUtils.isEmpty(rules)) { + return false; + } + + return rules.stream() + .anyMatch(e -> Objects.equals(e.getRowPermission(), getRulePermissionId())); + } +} diff --git a/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/dataObject/DepartmentAndSubordinateRule.java b/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/dataObject/DepartmentAndSubordinateRule.java new file mode 100644 index 0000000..f4f767b --- /dev/null +++ b/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/dataObject/DepartmentAndSubordinateRule.java @@ -0,0 +1,79 @@ +package cn.axzo.framework.datapermission.dataObject; + +import cn.axzo.framework.datapermission.context.DataPermissionContextHolder; +import cn.axzo.karma.client.feign.organization.OrganizationalNodeApi; +import cn.axzo.karma.client.feign.organization.request.PageOrganizationNodeReq; +import cn.axzo.karma.client.feign.organization.response.OrganizationalNodeResp; +import lombok.RequiredArgsConstructor; +import org.springframework.util.CollectionUtils; + +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +import static cn.axzo.framework.datapermission.context.DataPermissionContextHolder.DEPARTMENT_SUBORDINATE; + +@RequiredArgsConstructor +public class DepartmentAndSubordinateRule implements DataObjectRule { + + private final OrganizationalNodeApi organizationalNodeApi; + + /** + * 本部门及以下数据规则id + */ + private static final Integer RULE_PERMISSION_ID = 4; + + @Override + public Integer getRulePermissionId() { + return RULE_PERMISSION_ID; + } + + @Override + public void resolve(DataObjectRuleContext context) { + DataPermissionContextHolder.DataPermissionContext dataPermissionContext = DataPermissionContextHolder.get(); + + List nodes = organizationalNodeApi.page(PageOrganizationNodeReq.builder() + .personId(dataPermissionContext.getPersonId()) + .ouId(dataPermissionContext.getOuId()) + .needSubordinate(true) + .build()) + .getData() + .getData(); + + if (CollectionUtils.isEmpty(nodes)) { + return; + } + + Set nodeIds = nodes.stream() + .map(OrganizationalNodeResp::getId) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + + resolveNodes(nodeIds, nodes); + + dataPermissionContext.putPermissionData(DEPARTMENT_SUBORDINATE, nodeIds); + context.addNodeIds(nodeIds); + } + + private void resolveNodes(Set nodeIds, List nodes) { + if (CollectionUtils.isEmpty(nodes)) { + return; + } + + Set subordinateIds = nodes.stream() + .map(OrganizationalNodeResp::getSubordinateOuNodes) + .filter(Objects::nonNull) + .flatMap(Collection::stream) + .map(OrganizationalNodeResp::getId) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + if (CollectionUtils.isEmpty(subordinateIds)) { + return; + } + nodeIds.addAll(subordinateIds); + + nodes.forEach(e -> resolveNodes(nodeIds, e.getSubordinateOuNodes())); + } +} diff --git a/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/dataObject/DepartmentOnlyRule.java b/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/dataObject/DepartmentOnlyRule.java new file mode 100644 index 0000000..7dd12db --- /dev/null +++ b/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/dataObject/DepartmentOnlyRule.java @@ -0,0 +1,58 @@ +package cn.axzo.framework.datapermission.dataObject; + +import cn.axzo.framework.datapermission.context.DataPermissionContextHolder; +import cn.axzo.karma.client.feign.organization.OrganizationalNodeApi; +import cn.axzo.karma.client.feign.organization.request.PageOrganizationNodeReq; +import cn.axzo.karma.client.feign.organization.response.OrganizationalNodeResp; +import lombok.RequiredArgsConstructor; +import org.springframework.util.CollectionUtils; + +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +import static cn.axzo.framework.datapermission.context.DataPermissionContextHolder.DEPARTMENT_ONLY; + +/** + * 本部门数据规则 + */ +@RequiredArgsConstructor +public class DepartmentOnlyRule implements DataObjectRule { + + private final OrganizationalNodeApi organizationalNodeApi; + + /** + * 本部门数据规则id + */ + private static final Integer RULE_PERMISSION_ID = 3; + + @Override + public Integer getRulePermissionId() { + return RULE_PERMISSION_ID; + } + + @Override + public void resolve(DataObjectRuleContext context) { + DataPermissionContextHolder.DataPermissionContext dataPermissionContext = DataPermissionContextHolder.get(); + + List nodes = organizationalNodeApi.page(PageOrganizationNodeReq.builder() + .personId(dataPermissionContext.getPersonId()) + .ouId(dataPermissionContext.getOuId()) + .build()) + .getData() + .getData(); + + if (CollectionUtils.isEmpty(nodes)) { + return; + } + + Set nodeIds = nodes.stream() + .map(OrganizationalNodeResp::getId) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + + context.addNodeIds(nodeIds); + dataPermissionContext.putPermissionData(DEPARTMENT_ONLY, nodeIds); + } +} diff --git a/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/dataObject/MatchRuleFactory.java b/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/dataObject/MatchRuleFactory.java new file mode 100644 index 0000000..f795c3f --- /dev/null +++ b/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/dataObject/MatchRuleFactory.java @@ -0,0 +1,38 @@ +package cn.axzo.framework.datapermission.dataObject; + +import cn.axzo.karma.client.feign.tyr.response.MatchDataObjectResp; +import lombok.AllArgsConstructor; +import org.springframework.util.CollectionUtils; + +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; + +@AllArgsConstructor +public class MatchRuleFactory { + + private final List dataObjectRules; + + public Optional matchAndResolve(MatchDataObjectResp matchDataObjectResp) { + + if (Objects.isNull(matchDataObjectResp) || CollectionUtils.isEmpty(matchDataObjectResp.getRules())) { + return Optional.empty(); + } + + List matchedRules = dataObjectRules.stream() + .filter(e -> e.match(matchDataObjectResp.getRules())) + .collect(Collectors.toList()); + + if (CollectionUtils.isEmpty(matchedRules)) { + return Optional.empty(); + } + + DataObjectRule.DataObjectRuleContext dataObjectRuleContext = DataObjectRule.DataObjectRuleContext.builder().build(); + for (DataObjectRule matchedRule : matchedRules) { + matchedRule.resolve(dataObjectRuleContext); + } + + return Optional.ofNullable(dataObjectRuleContext); + } +} diff --git a/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/dataObject/SelfAndSubordinateRule.java b/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/dataObject/SelfAndSubordinateRule.java new file mode 100644 index 0000000..f788bd5 --- /dev/null +++ b/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/dataObject/SelfAndSubordinateRule.java @@ -0,0 +1,82 @@ +package cn.axzo.framework.datapermission.dataObject; + +import cn.axzo.framework.datapermission.context.DataPermissionContextHolder; +import cn.axzo.karma.client.feign.organization.OrganizationalNodeUserApi; +import cn.axzo.karma.client.feign.organization.request.PageOrganizationNodeUserReq; +import cn.axzo.karma.client.feign.organization.response.OrganizationalNodeUserResp; +import lombok.RequiredArgsConstructor; +import org.springframework.util.CollectionUtils; + +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +import static cn.axzo.framework.datapermission.context.DataPermissionContextHolder.SELF_SUBORDINATE; + +/** + * 本人及下属数据规则 + */ +@RequiredArgsConstructor +public class SelfAndSubordinateRule implements DataObjectRule { + + private final OrganizationalNodeUserApi organizationalNodeUserApi; + + /** + * 本人及下属数据规则id + */ + private static final Integer RULE_PERMISSION_ID = 2; + + @Override + public Integer getRulePermissionId() { + return RULE_PERMISSION_ID; + } + + @Override + public void resolve(DataObjectRuleContext context) { + DataPermissionContextHolder.DataPermissionContext dataPermissionContext = DataPermissionContextHolder.get(); + + List nodeUsers = organizationalNodeUserApi.page(PageOrganizationNodeUserReq.builder() + .personId(dataPermissionContext.getPersonId()) + .ouId(dataPermissionContext.getOuId()) + .needSubordinate(true) + .build()) + .getData() + .getData(); + + if (CollectionUtils.isEmpty(nodeUsers)) { + return; + } + + Set personIds = nodeUsers.stream() + .map(OrganizationalNodeUserResp::getPersonId) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + + resolveNodeUsers(personIds, nodeUsers); + + dataPermissionContext.putPermissionData(SELF_SUBORDINATE, personIds); + context.addPersonIds(personIds); + } + + private void resolveNodeUsers(Set personIds, List nodeUsers) { + if (CollectionUtils.isEmpty(nodeUsers)) { + return; + } + + Set subordinatePersonIds = nodeUsers.stream() + .map(OrganizationalNodeUserResp::getSubordinateOuNodeUsers) + .filter(Objects::nonNull) + .flatMap(Collection::stream) + .map(OrganizationalNodeUserResp::getPersonId) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + if (CollectionUtils.isEmpty(subordinatePersonIds)) { + return; + } + personIds.addAll(subordinatePersonIds); + + nodeUsers.forEach(e -> resolveNodeUsers(personIds, e.getSubordinateOuNodeUsers())); + } +} diff --git a/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/dataObject/SelfOnlyRule.java b/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/dataObject/SelfOnlyRule.java new file mode 100644 index 0000000..c42d917 --- /dev/null +++ b/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/dataObject/SelfOnlyRule.java @@ -0,0 +1,28 @@ +package cn.axzo.framework.datapermission.dataObject; + +import cn.axzo.framework.datapermission.context.DataPermissionContextHolder; +import com.google.common.collect.Sets; +import lombok.RequiredArgsConstructor; + +/** + * 仅本人数据规则 + */ +@RequiredArgsConstructor +public class SelfOnlyRule implements DataObjectRule { + + /** + * 仅本人数据的规则id + */ + private static final Integer RULE_PERMISSION_ID = 1; + + @Override + public Integer getRulePermissionId() { + return RULE_PERMISSION_ID; + } + + @Override + public void resolve(DataObjectRuleContext context) { + DataPermissionContextHolder.DataPermissionContext dataPermissionContext = DataPermissionContextHolder.get(); + context.addPersonIds(Sets.newHashSet(dataPermissionContext.getPersonId())); + } +} diff --git a/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/dataObject/UnitAllSubordinateRule.java b/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/dataObject/UnitAllSubordinateRule.java new file mode 100644 index 0000000..6011abf --- /dev/null +++ b/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/dataObject/UnitAllSubordinateRule.java @@ -0,0 +1,58 @@ +package cn.axzo.framework.datapermission.dataObject; + +import cn.axzo.framework.datapermission.context.DataPermissionContextHolder; +import cn.axzo.karma.client.feign.organization.OrganizationalNodeApi; +import cn.axzo.karma.client.feign.organization.request.QueryOuMultiConditionalReq; +import cn.axzo.karma.client.feign.organization.response.QueryOuMultiConditionalResp; +import lombok.RequiredArgsConstructor; +import org.springframework.util.CollectionUtils; + +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +import static cn.axzo.framework.datapermission.context.DataPermissionContextHolder.UNIT_ALL_SUBORDINATE; + +/** + * 本单位及以下协同(直属+合作)单位数据 + */ +@RequiredArgsConstructor +public class UnitAllSubordinateRule implements DataObjectRule { + + + private final OrganizationalNodeApi organizationalNodeApi; + + /** + * 本单位及以下协同(直属+合作)单位数据的规则id + */ + private static final Integer RULE_PERMISSION_ID = 8; + + @Override + public Integer getRulePermissionId() { + return RULE_PERMISSION_ID; + } + + @Override + public void resolve(DataObjectRuleContext context) { + DataPermissionContextHolder.DataPermissionContext dataPermissionContext = DataPermissionContextHolder.get(); + + QueryOuMultiConditionalResp node = organizationalNodeApi.queryOuMultiConditional(QueryOuMultiConditionalReq.builder() + .workspaceId(dataPermissionContext.getWorkspaceId()) + .ouId(dataPermissionContext.getOuId()) + .needDirectlyAndCooperateWithDescendant(true) + .build()) + .getData(); + + if (Objects.isNull(node) || CollectionUtils.isEmpty(node.getBasicNodeUsers())) { + return; + } + + Set nodeIds = node.getBasicNodeUsers().stream() + .map(QueryOuMultiConditionalResp.BasicNodeUser::getNodeId) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + + context.addNodeIds(nodeIds); + dataPermissionContext.putPermissionData(UNIT_ALL_SUBORDINATE, nodeIds); + } +} diff --git a/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/dataObject/UnitCooperateSubordinateRule.java b/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/dataObject/UnitCooperateSubordinateRule.java new file mode 100644 index 0000000..e5ce279 --- /dev/null +++ b/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/dataObject/UnitCooperateSubordinateRule.java @@ -0,0 +1,58 @@ +package cn.axzo.framework.datapermission.dataObject; + +import cn.axzo.framework.datapermission.context.DataPermissionContextHolder; +import cn.axzo.karma.client.feign.organization.OrganizationalNodeApi; +import cn.axzo.karma.client.feign.organization.request.QueryOuMultiConditionalReq; +import cn.axzo.karma.client.feign.organization.response.QueryOuMultiConditionalResp; +import lombok.RequiredArgsConstructor; +import org.springframework.util.CollectionUtils; + +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +import static cn.axzo.framework.datapermission.context.DataPermissionContextHolder.UNIT_COOPERATE_SUBORDINATE; + +/** + * 本单位及下级协同(直属+合作)单位数据 + */ +@RequiredArgsConstructor +public class UnitCooperateSubordinateRule implements DataObjectRule { + + + private final OrganizationalNodeApi organizationalNodeApi; + + /** + * 本单位及下级协同(直属+合作)单位数据的规则id + */ + private static final Integer RULE_PERMISSION_ID = 7; + + @Override + public Integer getRulePermissionId() { + return RULE_PERMISSION_ID; + } + + @Override + public void resolve(DataObjectRuleContext context) { + DataPermissionContextHolder.DataPermissionContext dataPermissionContext = DataPermissionContextHolder.get(); + + QueryOuMultiConditionalResp node = organizationalNodeApi.queryOuMultiConditional(QueryOuMultiConditionalReq.builder() + .workspaceId(dataPermissionContext.getWorkspaceId()) + .ouId(dataPermissionContext.getOuId()) + .needDirectlyAndCooperate(true) + .build()) + .getData(); + + if (Objects.isNull(node) || CollectionUtils.isEmpty(node.getBasicNodeUsers())) { + return; + } + + Set nodeIds = node.getBasicNodeUsers().stream() + .map(QueryOuMultiConditionalResp.BasicNodeUser::getNodeId) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + + context.addNodeIds(nodeIds); + dataPermissionContext.putPermissionData(UNIT_COOPERATE_SUBORDINATE, nodeIds); + } +} diff --git a/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/dataObject/UnitDirectSubordinateRule.java b/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/dataObject/UnitDirectSubordinateRule.java new file mode 100644 index 0000000..d56f822 --- /dev/null +++ b/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/dataObject/UnitDirectSubordinateRule.java @@ -0,0 +1,58 @@ +package cn.axzo.framework.datapermission.dataObject; + +import cn.axzo.framework.datapermission.context.DataPermissionContextHolder; +import cn.axzo.karma.client.feign.organization.OrganizationalNodeApi; +import cn.axzo.karma.client.feign.organization.request.QueryOuMultiConditionalReq; +import cn.axzo.karma.client.feign.organization.response.QueryOuMultiConditionalResp; +import lombok.RequiredArgsConstructor; +import org.springframework.util.CollectionUtils; + +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +import static cn.axzo.framework.datapermission.context.DataPermissionContextHolder.UNIT_DIRECT_SUBORDINATE; + +/** + * 本单位及下级直属单位数据 + */ +@RequiredArgsConstructor +public class UnitDirectSubordinateRule implements DataObjectRule { + + + private final OrganizationalNodeApi organizationalNodeApi; + + /** + * 本单位及下级直属单位数据的规则id + */ + private static final Integer RULE_PERMISSION_ID = 6; + + @Override + public Integer getRulePermissionId() { + return RULE_PERMISSION_ID; + } + + @Override + public void resolve(DataObjectRuleContext context) { + DataPermissionContextHolder.DataPermissionContext dataPermissionContext = DataPermissionContextHolder.get(); + + QueryOuMultiConditionalResp node = organizationalNodeApi.queryOuMultiConditional(QueryOuMultiConditionalReq.builder() + .workspaceId(dataPermissionContext.getWorkspaceId()) + .ouId(dataPermissionContext.getOuId()) + .needDirectlyUnder(true) + .build()) + .getData(); + + if (Objects.isNull(node) || CollectionUtils.isEmpty(node.getBasicNodeUsers())) { + return; + } + + Set nodeIds = node.getBasicNodeUsers().stream() + .map(QueryOuMultiConditionalResp.BasicNodeUser::getNodeId) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + + context.addNodeIds(nodeIds); + dataPermissionContext.putPermissionData(UNIT_DIRECT_SUBORDINATE, nodeIds); + } +} diff --git a/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/dataObject/UnitOnlyExcludeTeamRule.java b/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/dataObject/UnitOnlyExcludeTeamRule.java new file mode 100644 index 0000000..149bb9e --- /dev/null +++ b/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/dataObject/UnitOnlyExcludeTeamRule.java @@ -0,0 +1,57 @@ +package cn.axzo.framework.datapermission.dataObject; + +import cn.axzo.framework.datapermission.context.DataPermissionContextHolder; +import cn.axzo.karma.client.feign.organization.OrganizationalNodeApi; +import cn.axzo.karma.client.feign.organization.request.QueryOuMultiConditionalReq; +import cn.axzo.karma.client.feign.organization.response.QueryOuMultiConditionalResp; +import lombok.RequiredArgsConstructor; +import org.springframework.util.CollectionUtils; + +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +import static cn.axzo.framework.datapermission.context.DataPermissionContextHolder.UNIT_ONLY_EXCLUDE_TEAM; + +/** + * 仅本单位数据(不包含班组) + */ +@RequiredArgsConstructor +public class UnitOnlyExcludeTeamRule implements DataObjectRule { + + + private final OrganizationalNodeApi organizationalNodeApi; + + /** + * 仅本单位数据(不包含班组)的规则id + */ + private static final Integer RULE_PERMISSION_ID = 10; + + @Override + public Integer getRulePermissionId() { + return RULE_PERMISSION_ID; + } + + @Override + public void resolve(DataObjectRuleContext context) { + DataPermissionContextHolder.DataPermissionContext dataPermissionContext = DataPermissionContextHolder.get(); + + QueryOuMultiConditionalResp node = organizationalNodeApi.queryOuMultiConditional(QueryOuMultiConditionalReq.builder() + .workspaceId(dataPermissionContext.getWorkspaceId()) + .ouId(dataPermissionContext.getOuId()) + .build()) + .getData(); + + if (Objects.isNull(node) || CollectionUtils.isEmpty(node.getBasicNodeUsers())) { + return; + } + + Set nodeIds = node.getBasicNodeUsers().stream() + .map(QueryOuMultiConditionalResp.BasicNodeUser::getNodeId) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + + context.addNodeIds(nodeIds); + dataPermissionContext.putPermissionData(UNIT_ONLY_EXCLUDE_TEAM, nodeIds); + } +} diff --git a/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/dataObject/UnitOnlyRule.java b/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/dataObject/UnitOnlyRule.java new file mode 100644 index 0000000..8b827ff --- /dev/null +++ b/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/dataObject/UnitOnlyRule.java @@ -0,0 +1,58 @@ +package cn.axzo.framework.datapermission.dataObject; + +import cn.axzo.framework.datapermission.context.DataPermissionContextHolder; +import cn.axzo.karma.client.feign.organization.OrganizationalNodeApi; +import cn.axzo.karma.client.feign.organization.request.QueryOuMultiConditionalReq; +import cn.axzo.karma.client.feign.organization.response.QueryOuMultiConditionalResp; +import lombok.RequiredArgsConstructor; +import org.springframework.util.CollectionUtils; + +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +import static cn.axzo.framework.datapermission.context.DataPermissionContextHolder.UNIT_ONLY; + +/** + * 仅本单位数据(包含班组) + */ +@RequiredArgsConstructor +public class UnitOnlyRule implements DataObjectRule { + + + private final OrganizationalNodeApi organizationalNodeApi; + + /** + * 仅本单位数据(包含班组)的规则id + */ + private static final Integer RULE_PERMISSION_ID = 5; + + @Override + public Integer getRulePermissionId() { + return RULE_PERMISSION_ID; + } + + @Override + public void resolve(DataObjectRuleContext context) { + DataPermissionContextHolder.DataPermissionContext dataPermissionContext = DataPermissionContextHolder.get(); + + QueryOuMultiConditionalResp node = organizationalNodeApi.queryOuMultiConditional(QueryOuMultiConditionalReq.builder() + .workspaceId(dataPermissionContext.getWorkspaceId()) + .ouId(dataPermissionContext.getOuId()) + .needTeam(true) + .build()) + .getData(); + + if (Objects.isNull(node) || CollectionUtils.isEmpty(node.getBasicNodeUsers())) { + return; + } + + Set nodeIds = node.getBasicNodeUsers().stream() + .map(QueryOuMultiConditionalResp.BasicNodeUser::getNodeId) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + + context.addNodeIds(nodeIds); + dataPermissionContext.putPermissionData(UNIT_ONLY, nodeIds); + } +} diff --git a/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/dataObject/WorkspaceRule.java b/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/dataObject/WorkspaceRule.java new file mode 100644 index 0000000..3c418b0 --- /dev/null +++ b/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/dataObject/WorkspaceRule.java @@ -0,0 +1,58 @@ +package cn.axzo.framework.datapermission.dataObject; + +import cn.axzo.framework.datapermission.context.DataPermissionContextHolder; +import cn.axzo.karma.client.feign.organization.OrganizationalNodeApi; +import cn.axzo.karma.client.feign.organization.request.PageOrganizationNodeReq; +import cn.axzo.karma.client.feign.organization.response.OrganizationalNodeResp; +import lombok.RequiredArgsConstructor; +import org.springframework.util.CollectionUtils; + +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +import static cn.axzo.framework.datapermission.context.DataPermissionContextHolder.WORKSPACE; + +/** + * 本项目部数据 + */ +@RequiredArgsConstructor +public class WorkspaceRule implements DataObjectRule { + + + private final OrganizationalNodeApi organizationalNodeApi; + + /** + * 本项目部数据的规则id + */ + private static final Integer RULE_PERMISSION_ID = 9; + + @Override + public Integer getRulePermissionId() { + return RULE_PERMISSION_ID; + } + + @Override + public void resolve(DataObjectRuleContext context) { + DataPermissionContextHolder.DataPermissionContext dataPermissionContext = DataPermissionContextHolder.get(); + + List nodes = organizationalNodeApi.page(PageOrganizationNodeReq.builder() + .workspaceId(dataPermissionContext.getWorkspaceId()) + .build()) + .getData() + .getData(); + + if (CollectionUtils.isEmpty(nodes)) { + return; + } + + Set nodeIds = nodes.stream() + .map(OrganizationalNodeResp::getId) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + + context.addNodeIds(nodeIds); + dataPermissionContext.putPermissionData(WORKSPACE, nodeIds); + } +} diff --git a/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/rule/DataPermissionRule.java b/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/rule/DataPermissionRule.java index 7a9ae2e..0a1d36a 100644 --- a/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/rule/DataPermissionRule.java +++ b/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/rule/DataPermissionRule.java @@ -1,10 +1,8 @@ package cn.axzo.framework.datapermission.rule; -import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor; import net.sf.jsqlparser.expression.Alias; import net.sf.jsqlparser.expression.Expression; -import java.util.List; import java.util.Set; /** @@ -16,5 +14,4 @@ public interface DataPermissionRule { Set getTableName(); Expression getExpression(String tableName, Alias tableAlias); - } diff --git a/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/rule/DataPermissionDefaultRule.java b/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/rule/OrgDefaultRule.java similarity index 59% rename from axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/rule/DataPermissionDefaultRule.java rename to axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/rule/OrgDefaultRule.java index 089988a..7783a1b 100644 --- a/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/rule/DataPermissionDefaultRule.java +++ b/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/rule/OrgDefaultRule.java @@ -1,13 +1,19 @@ package cn.axzo.framework.datapermission.rule; -import cn.axzo.karma.client.feign.FlowSupportApi; -import cn.hutool.core.collection.ListUtil; +import cn.axzo.framework.datapermission.context.DataPermissionContextHolder; +import cn.axzo.framework.datapermission.dataObject.DataObjectRule; +import cn.axzo.framework.datapermission.dataObject.MatchRuleFactory; +import cn.axzo.karma.client.feign.tyr.DataObjectApi; +import cn.axzo.karma.client.feign.tyr.request.MatchDataObjectReq; +import cn.axzo.karma.client.feign.tyr.response.MatchDataObjectResp; +import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.metadata.TableInfo; import com.baomidou.mybatisplus.core.metadata.TableInfoHelper; import com.baomidou.mybatisplus.core.toolkit.StringPool; import com.baomidou.mybatisplus.extension.activerecord.Model; -import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import net.sf.jsqlparser.expression.Alias; import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.LongValue; @@ -17,25 +23,25 @@ import net.sf.jsqlparser.expression.operators.conditional.OrExpression; import net.sf.jsqlparser.expression.operators.relational.ExpressionList; import net.sf.jsqlparser.expression.operators.relational.InExpression; import net.sf.jsqlparser.schema.Column; -import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; -import java.util.ArrayList; -import java.util.HashMap; import java.util.HashSet; -import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; /** + * 基于personId、租户、单位、部门的数据权限 * @author tanjie@axzo.cn * @date 2024/5/30 18:35 */ +@Builder @RequiredArgsConstructor -public class DataPermissionDefaultRule implements DataPermissionRule { +@Slf4j +public class OrgDefaultRule implements DataPermissionRule { static final Expression EXPRESSION_NULL = new NullValue(); private static final String DEFAULT_PERSON = "person_id"; @@ -54,9 +60,9 @@ public class DataPermissionDefaultRule implements DataPermissionRule { protected final Set tableName =new HashSet<>(); + private final DataObjectApi dataObjectApi; - //// TODO: 2024/6/3 查询数据权限的api - private final FlowSupportApi permissionApi; + private final MatchRuleFactory matchRuleFactory; @Override public Set getTableName() { @@ -66,22 +72,41 @@ public class DataPermissionDefaultRule implements DataPermissionRule { @Override public Expression getExpression(String tableName, Alias tableAlias) { - // TODO: 2024/5/31 可访问的数据 @李龙 - List nodeIds = ListUtil.of(1L, 2L, 3L); - List personIds = ListUtil.of(110L, 223L); + Optional matchDataObjectOptional = this.matchRule(); + if (!matchDataObjectOptional.isPresent() || CollectionUtils.isEmpty(matchDataObjectOptional.get().getRules())) { + log.warn("no match data rule, dataPermissionContext:{}", JSONObject.toJSONString(DataPermissionContextHolder.get())); + return EXPRESSION_NULL; + } + + MatchDataObjectResp matchDataObject = matchDataObjectOptional.get(); + + Optional dataObjectRuleContextOpt = matchRuleFactory.matchAndResolve(matchDataObject); + + if (!dataObjectRuleContextOpt.isPresent()) { + return EXPRESSION_NULL; + } + + DataObjectRule.DataObjectRuleContext dataObjectRuleContext = dataObjectRuleContextOpt.get(); + + Set nodeIds = dataObjectRuleContext.getNodeIds(); + Set personIds = dataObjectRuleContext.getPersonIds(); Expression deptExpression = buildExpression(tableName, tableAlias, nodeIds); Expression userExpression = buildExpression(tableName, tableAlias, personIds); + if (deptExpression == null && userExpression == null) { // 未获取到数据权限 返回NULL 不查询数据 return EXPRESSION_NULL; } + if (deptExpression == null) { return userExpression; } + if (userExpression == null) { return deptExpression; } + // 如果两个都有,用or WHERE (organizational_Node_id IN ? OR person_id in ?) return new Parenthesis(new OrExpression(deptExpression, userExpression)); @@ -96,7 +121,7 @@ public class DataPermissionDefaultRule implements DataPermissionRule { * @param ids 可能是nodeids 也可以是personIds * @return */ - private Expression buildExpression(String tableName, Alias tableAlias, List ids) { + private Expression buildExpression(String tableName, Alias tableAlias, Set ids) { // 如果不存在配置,则无需作为条件 String columnName = nodeTable.get(tableName); if (!StringUtils.hasText(columnName)) { @@ -133,15 +158,6 @@ public class DataPermissionDefaultRule implements DataPermissionRule { tableName.add(tableInfo.getTableName()); } - /** - * 添加组织节点所对应的字段 字段默认使用organizational_node_id - * - * @param entityClass 表所对应的entity - */ - public void addNodeColumn(Class> entityClass) { - addNodeColumn(entityClass, DEFAULT_NODE); - } - /** * 添加personId所对应的字段 * @@ -157,12 +173,34 @@ public class DataPermissionDefaultRule implements DataPermissionRule { tableName.add(tableInfo.getTableName()); } - /** - * 字段默认使用person_id - * - * @param entityClass 表所对应的entity - */ - public void addPersonColumn(Class> entityClass) { - addPersonColumn(entityClass, DEFAULT_PERSON); + private Optional matchRule() { + + if (invalidContext()) { + return Optional.empty(); + } + + DataPermissionContextHolder.DataPermissionContext dataPermissionContext = DataPermissionContextHolder.get(); + + MatchDataObjectReq matchDataObjectReq = MatchDataObjectReq.builder() + .dataObjectCode(dataPermissionContext.getDataPermission().bizCode()) + .ouId(dataPermissionContext.getOuId()) + .workspaceId(dataPermissionContext.getWorkspaceId()) + .personId(dataPermissionContext.getPersonId()) + .build(); + + return Optional.ofNullable(dataObjectApi.match(matchDataObjectReq).getData()); + } + + private boolean invalidContext() { + + DataPermissionContextHolder.DataPermissionContext dataPermissionContext = DataPermissionContextHolder.get(); + + return dataPermissionContext == null + || dataPermissionContext.getDataPermission() == null + || StringsUtil.isBlank(dataPermissionContext.getDataPermission().bizCode()) + || !dataPermissionContext.getDataPermission().enable() + || dataPermissionContext.getOuId() == null + || dataPermissionContext.getWorkspaceId() == null + || dataPermissionContext.getPersonId() == null; } } diff --git a/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/rule/StringsUtil.java b/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/rule/StringsUtil.java new file mode 100644 index 0000000..87d1a20 --- /dev/null +++ b/axzo-common-data-permission/src/main/java/cn/axzo/framework/datapermission/rule/StringsUtil.java @@ -0,0 +1,27 @@ +package cn.axzo.framework.datapermission.rule; + +public class StringsUtil { + + public static boolean isNotBlank(CharSequence cs) { + return !isBlank(cs); + } + + public static boolean isBlank(CharSequence cs) { + int strLen = length(cs); + if (strLen == 0) { + return true; + } else { + for(int i = 0; i < strLen; ++i) { + if (!Character.isWhitespace(cs.charAt(i))) { + return false; + } + } + + return true; + } + } + + public static int length(CharSequence cs) { + return cs == null ? 0 : cs.length(); + } +}