From 61ec20b260ff0847fb55910594948f1bac0f1b91 Mon Sep 17 00:00:00 2001 From: Carina Date: Fri, 15 Oct 2021 17:36:49 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BC=98=E5=8C=96=E7=BB=84=E7=BB=87?= =?UTF-8?q?=E6=9C=BA=E6=9E=84=E3=80=81=E6=96=B0=E5=A2=9E=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E6=9D=83=E9=99=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 优化组织机构 2. 新增数据权限 --- README.md | 4 +- .../opsli/api/web/system/user/UserApi.java | 33 +- .../api/web/system/user/UserOrgRefApi.java | 18 + .../api/web/system/user/UserRoleRefApi.java | 44 +++ .../api/wrapper/system/role/RoleModel.java | 11 +- .../wrapper/system/user/UserRoleRefModel.java | 7 + .../common/constants/MyBatisConstants.java | 2 +- .../org/opsli/common/utils/CheckStrength.java | 2 +- .../org/opsli/common/utils/FieldUtil.java | 56 ++- .../base/service/impl/CrudServiceImpl.java | 6 +- .../cache/pushsub/handler/OrgHandler.java | 3 +- .../MybatisAutoFillInterceptor.java | 16 + .../java/org/opsli/core/msg/TokenMsg.java | 2 +- .../querybuilder/chain/QueryBuilderChain.java | 12 + .../chain/QueryDataPermsHandler.java | 232 +++++++++++ .../querybuilder/chain/QueryOrgHandler.java | 71 ---- .../chain/QueryTenantHandler.java | 28 ++ .../querybuilder/conf/WebQueryConf.java | 29 +- .../java/org/opsli/core/utils/OrgUtil.java | 154 +------- .../org/opsli/core/utils/UserTokenUtil.java | 5 +- .../java/org/opsli/core/utils/UserUtil.java | 372 +++++++++++++++++- .../system/login/web/LoginRestController.java | 7 + .../menu/service/impl/MenuServiceImpl.java | 14 +- .../system/menu/web/MenuRestController.java | 5 +- .../system/org/web/SysOrgRestController.java | 2 +- .../modulars/system/role/entity/SysRole.java | 5 +- .../service/impl/RoleMenuRefServiceImpl.java | 14 +- .../role/service/impl/RoleServiceImpl.java | 55 ++- .../role/web/RoleMenuRefRestController.java | 6 +- .../system/role/web/RoleRestController.java | 12 +- .../system/user/entity/SysUserRoleRef.java | 2 + .../system/user/mapper/UserMapper.java | 35 -- .../system/user/mapper/UserRoleRefMapper.java | 36 ++ .../system/user/mapper/xml/UserMapper.xml | 93 ----- .../user/mapper/xml/UserRoleRefMapper.xml | 93 +++++ .../user/service/IUserOrgRefService.java | 14 + .../user/service/IUserRoleRefService.java | 59 ++- .../system/user/service/IUserService.java | 40 +- .../service/impl/UserOrgRefServiceImpl.java | 35 +- .../service/impl/UserRoleRefServiceImpl.java | 183 ++++++++- .../user/service/impl/UserServiceImpl.java | 124 +----- .../user/web/UserOrgRefRestController.java | 95 +++++ .../system/user/web/UserRestController.java | 114 +----- .../user/web/UserRoleRefRestController.java | 85 +++- .../gentest/carinfo/entity/TestCar.java | 4 +- 45 files changed, 1525 insertions(+), 714 deletions(-) create mode 100644 opsli-base-support/opsli-core/src/main/java/org/opsli/core/persistence/querybuilder/chain/QueryDataPermsHandler.java delete mode 100644 opsli-base-support/opsli-core/src/main/java/org/opsli/core/persistence/querybuilder/chain/QueryOrgHandler.java diff --git a/README.md b/README.md index cab207b..6ec5b2a 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@

-[![AUR](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg)](https://github.com/hiparker/opsli-boot/blob/master/LICENSE) [![spring-boot](https://img.shields.io/badge/spring--boot-2.3.3.RELEASE-green.svg)](http://spring.io/projects/spring-boot) [![mybatis-plus](https://img.shields.io/badge/mybatis--plus-3.4.0-blue.svg)](http://mp.baomidou.com) [![hutool](https://img.shields.io/badge/hutool-5.6.3-blue.svg)](https://www.hutool.cn) [![Stars](https://img.shields.io/github/stars/hiparker/opsli-boot?style=flat-square&label=Stars&logo=github)](https://github.com/hiparker/opsli-boot) [![Forks](https://img.shields.io/github/forks/hiparker/opsli-boot?style=flat-square&label=Forks&logo=github)](https://github.com/hiparker/opsli-boot) +[![AUR](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg)](https://github.com/hiparker/opsli-boot/blob/master/LICENSE) [![spring-boot](https://img.shields.io/badge/spring--boot-2.3.3.RELEASE-green.svg)](http://spring.io/projects/spring-boot) [![mybatis-plus](https://img.shields.io/badge/mybatis--plus-3.4.0-blue.svg)](http://mp.baomidou.com) [![hutool](https://img.shields.io/badge/hutool-5.7.14-blue.svg)](https://www.hutool.cn) [![Stars](https://img.shields.io/github/stars/hiparker/opsli-boot?style=flat-square&label=Stars&logo=github)](https://github.com/hiparker/opsli-boot) [![Forks](https://img.shields.io/github/forks/hiparker/opsli-boot?style=flat-square&label=Forks&logo=github)](https://github.com/hiparker/opsli-boot) ## 关于 @@ -39,7 +39,7 @@ | shiro-redis版本 | ^3.3.1 | | jwt版本 | ^3.10.3 | | ehcache版本 | ^3.9.0 | | easyexcel版本 | ^2.2.6 | | kaptcha版本 | ^0.0.9 | | guava版本 | ^29.0-jre | -| enjoy版本 | ^4.9.03 | | hutool版本 | ^5.6.3 | +| enjoy版本 | ^4.9.03 | | hutool版本 | ^5.7.14 | ## 在线演示 diff --git a/opsli-api/src/main/java/org/opsli/api/web/system/user/UserApi.java b/opsli-api/src/main/java/org/opsli/api/web/system/user/UserApi.java index cca47d8..b82d079 100644 --- a/opsli-api/src/main/java/org/opsli/api/web/system/user/UserApi.java +++ b/opsli-api/src/main/java/org/opsli/api/web/system/user/UserApi.java @@ -17,6 +17,7 @@ package org.opsli.api.web.system.user; import org.opsli.api.base.result.ResultVo; import org.opsli.api.wrapper.system.menu.MenuModel; +import org.opsli.api.wrapper.system.role.RoleModel; import org.opsli.api.wrapper.system.user.UserInfo; import org.opsli.api.wrapper.system.user.UserModel; import org.opsli.api.wrapper.system.user.UserOrgRefWebModel; @@ -235,38 +236,6 @@ public interface UserApi { //@GetMapping("/getUserByUsername") ResultVo getUserByUsername(String username); - /** - * 根据 userId 获得用户角色 - * @param userId 用户Id - * @return ResultVo - */ - //@GetMapping("/getRolesByUserId") - ResultVo> getRolesByUserId(String userId); - - /** - * 根据 userId 获得用户权限 - * @param userId 用户Id - * @return ResultVo - */ - //@GetMapping("/queryAllPerms") - ResultVo> getAllPerms(String userId); - - /** - * 根据 userId 获得用户菜单 - * @param userId 用户Id - * @return ResultVo - */ - //@GetMapping("/queryAllPerms") - ResultVo> getMenuListByUserId(String userId); - - - /** - * 当前登陆用户信息 - * - * @param userId 用户ID - * @return ResultVo - */ - ResultVo getOrgInfoByUserId(String userId); } diff --git a/opsli-api/src/main/java/org/opsli/api/web/system/user/UserOrgRefApi.java b/opsli-api/src/main/java/org/opsli/api/web/system/user/UserOrgRefApi.java index 1af292a..c64a3dc 100644 --- a/opsli-api/src/main/java/org/opsli/api/web/system/user/UserOrgRefApi.java +++ b/opsli-api/src/main/java/org/opsli/api/web/system/user/UserOrgRefApi.java @@ -16,6 +16,7 @@ package org.opsli.api.web.system.user; import org.opsli.api.base.result.ResultVo; +import org.opsli.api.wrapper.system.org.SysOrgModel; import org.opsli.api.wrapper.system.user.UserOrgRefModel; import org.opsli.api.wrapper.system.user.UserOrgRefWebModel; import org.springframework.web.bind.annotation.PostMapping; @@ -58,4 +59,21 @@ public interface UserOrgRefApi { */ ResultVo> findListByUserId(String userId); + + /** + * 根据 userId 获得用户默认组织 + * @param userId 用户Id + * @return ResultVo + */ + //@GetMapping("/getRolesByUserId") + ResultVo getDefOrgByUserId(String userId); + + /** + * 当前登陆用户信息 + * + * @param userId 用户ID + * @return ResultVo + */ + ResultVo getOrgInfoByUserId(String userId); + } diff --git a/opsli-api/src/main/java/org/opsli/api/web/system/user/UserRoleRefApi.java b/opsli-api/src/main/java/org/opsli/api/web/system/user/UserRoleRefApi.java index ae3ae19..176314e 100644 --- a/opsli-api/src/main/java/org/opsli/api/web/system/user/UserRoleRefApi.java +++ b/opsli-api/src/main/java/org/opsli/api/web/system/user/UserRoleRefApi.java @@ -16,12 +16,16 @@ package org.opsli.api.web.system.user; import org.opsli.api.base.result.ResultVo; +import org.opsli.api.wrapper.system.menu.MenuModel; import org.opsli.api.wrapper.system.role.RoleMenuRefModel; +import org.opsli.api.wrapper.system.role.RoleModel; import org.opsli.api.wrapper.system.user.UserRoleRefModel; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; +import java.util.List; + /** * 用户角色 API @@ -41,6 +45,13 @@ public interface UserRoleRefApi { /** 子标题 */ String SUB_TITLE = "用户角色"; + /** + * 设置角色 + * @param userId 用户ID + * @return ResultVo + */ + @GetMapping("/getRoles") + ResultVo getRoles(String userId); /** * 设置角色 @@ -50,4 +61,37 @@ public interface UserRoleRefApi { @PostMapping("/setRoles") ResultVo setRoles(@RequestBody UserRoleRefModel model); + + /** + * 根据 userId 获得用户角色 + * @param userId 用户Id + * @return ResultVo + */ + //@GetMapping("/getRolesByUserId") + ResultVo> getRolesByUserId(String userId); + + /** + * 根据 userId 获得用户默认角色 + * @param userId 用户Id + * @return ResultVo + */ + //@GetMapping("/getRolesByUserId") + ResultVo getDefRoleByUserId(String userId); + + /** + * 根据 userId 获得用户权限 + * @param userId 用户Id + * @return ResultVo + */ + //@GetMapping("/queryAllPerms") + ResultVo> getAllPerms(String userId); + + /** + * 根据 userId 获得用户菜单 + * @param userId 用户Id + * @return ResultVo + */ + //@GetMapping("/queryAllPerms") + ResultVo> getMenuListByUserId(String userId); + } diff --git a/opsli-api/src/main/java/org/opsli/api/wrapper/system/role/RoleModel.java b/opsli-api/src/main/java/org/opsli/api/wrapper/system/role/RoleModel.java index 4b70cf9..ce5f408 100644 --- a/opsli-api/src/main/java/org/opsli/api/wrapper/system/role/RoleModel.java +++ b/opsli-api/src/main/java/org/opsli/api/wrapper/system/role/RoleModel.java @@ -60,9 +60,18 @@ public class RoleModel extends ApiWrapper { @ValidatorLenMax(1) private String izLock; + + /** 授权数据范围 */ + @ApiModelProperty(value = "授权数据范围") + @ExcelProperty(value = "授权数据范围", order = 4) + @ExcelInfo(dictType = "role_data_scope") + @Validator({ValidatorType.IS_NOT_NULL}) + @ValidatorLenMax(5) + private String dataScope; + /** 备注 */ @ApiModelProperty(value = "备注") - @ExcelProperty(value = "备注", order = 4) + @ExcelProperty(value = "备注", order = 5) @ExcelInfo @ValidatorLenMax(255) private String remark; diff --git a/opsli-api/src/main/java/org/opsli/api/wrapper/system/user/UserRoleRefModel.java b/opsli-api/src/main/java/org/opsli/api/wrapper/system/user/UserRoleRefModel.java index 12ed8d5..941bb41 100644 --- a/opsli-api/src/main/java/org/opsli/api/wrapper/system/user/UserRoleRefModel.java +++ b/opsli-api/src/main/java/org/opsli/api/wrapper/system/user/UserRoleRefModel.java @@ -17,6 +17,7 @@ package org.opsli.api.wrapper.system.user; import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; import io.swagger.annotations.ApiModelProperty; +import lombok.Builder; import lombok.Data; import lombok.EqualsAndHashCode; import org.opsli.common.annotation.validator.Validator; @@ -34,6 +35,7 @@ import java.io.Serializable; @Data @EqualsAndHashCode(callSuper = false) @ExcelIgnoreUnannotated +@Builder public class UserRoleRefModel implements Serializable { /** 用户ID */ @@ -46,4 +48,9 @@ public class UserRoleRefModel implements Serializable { @ApiModelProperty(value = "权限数组") private String[] roleIds; + /** 默认角色ID */ + @ApiModelProperty(value = "默认角色") + @Validator({ValidatorType.IS_NOT_NULL}) + private String defRoleId; + } diff --git a/opsli-base-support/opsli-common/src/main/java/org/opsli/common/constants/MyBatisConstants.java b/opsli-base-support/opsli-common/src/main/java/org/opsli/common/constants/MyBatisConstants.java index 6bf6eba..893209c 100644 --- a/opsli-base-support/opsli-common/src/main/java/org/opsli/common/constants/MyBatisConstants.java +++ b/opsli-base-support/opsli-common/src/main/java/org/opsli/common/constants/MyBatisConstants.java @@ -53,5 +53,5 @@ public interface MyBatisConstants { /** 多租户字段 */ String FIELD_TENANT = "tenantId"; /** 组织字段 */ - String FIELD_ORG_GROUP = "org_group"; + String FIELD_ORG_GROUP = "orgIds"; } diff --git a/opsli-base-support/opsli-common/src/main/java/org/opsli/common/utils/CheckStrength.java b/opsli-base-support/opsli-common/src/main/java/org/opsli/common/utils/CheckStrength.java index 1a899ae..a3f4c18 100644 --- a/opsli-base-support/opsli-common/src/main/java/org/opsli/common/utils/CheckStrength.java +++ b/opsli-base-support/opsli-common/src/main/java/org/opsli/common/utils/CheckStrength.java @@ -365,7 +365,7 @@ public class CheckStrength { */ public static boolean equalsNull(String str) { int strLen; - if (str == null || (strLen = str.length()) == 0 || str.equalsIgnoreCase("null")) { + if (str == null || (strLen = str.length()) == 0 || "null".equalsIgnoreCase(str)) { return true; } for (int i = 0; i < strLen; i++) { diff --git a/opsli-base-support/opsli-common/src/main/java/org/opsli/common/utils/FieldUtil.java b/opsli-base-support/opsli-common/src/main/java/org/opsli/common/utils/FieldUtil.java index 9dc1efe..d6ce39c 100644 --- a/opsli-base-support/opsli-common/src/main/java/org/opsli/common/utils/FieldUtil.java +++ b/opsli-base-support/opsli-common/src/main/java/org/opsli/common/utils/FieldUtil.java @@ -17,6 +17,12 @@ package org.opsli.common.utils; import org.springframework.util.StringUtils; +import java.io.Serializable; +import java.lang.invoke.SerializedLambda; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.function.Function; + /** * 字段处理工具类 * @@ -101,8 +107,56 @@ public final class FieldUtil { return str; } + + /** + * 获得字段名称 + * @param fn 方法 + * @param 泛型 + * @return String + */ + public static String getFileName(SFunction fn) { + // 从function取出序列化方法 + Method writeReplaceMethod; + try { + writeReplaceMethod = fn.getClass().getDeclaredMethod("writeReplace"); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } + + // 从序列化方法取出序列化的lambda信息 + boolean isAccessible = writeReplaceMethod.isAccessible(); + writeReplaceMethod.setAccessible(true); + SerializedLambda serializedLambda; + try { + serializedLambda = (SerializedLambda) writeReplaceMethod.invoke(fn); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException(e); + } + writeReplaceMethod.setAccessible(isAccessible); + + // 从lambda信息取出method、field、class等 + String fieldName = serializedLambda.getImplMethodName().substring("get".length()); + fieldName = fieldName.replaceFirst(fieldName.charAt(0) + "", (fieldName.charAt(0) + "").toLowerCase()); +// Field field; +// try { +// field = Class.forName(serializedLambda.getImplClass().replace("/", ".")).getDeclaredField(fieldName); +// } catch (ClassNotFoundException | NoSuchFieldException e) { +// throw new RuntimeException(e); +// } + + return fieldName; + } + + // ==================== - private FieldUtil(){} + /** + * 使Function获取序列化能力 + */ + @FunctionalInterface + public interface SFunction extends Function, Serializable { + + } + private FieldUtil(){} } diff --git a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/base/service/impl/CrudServiceImpl.java b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/base/service/impl/CrudServiceImpl.java index 3fa28ea..dc47842 100644 --- a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/base/service/impl/CrudServiceImpl.java +++ b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/base/service/impl/CrudServiceImpl.java @@ -32,7 +32,7 @@ import org.opsli.core.base.service.interfaces.CrudServiceInterface; import org.opsli.core.persistence.Page; import org.opsli.core.persistence.querybuilder.GenQueryBuilder; import org.opsli.core.persistence.querybuilder.QueryBuilder; -import org.opsli.core.persistence.querybuilder.chain.QueryOrgHandler; +import org.opsli.core.persistence.querybuilder.chain.QueryDataPermsHandler; import org.opsli.core.persistence.querybuilder.chain.QueryTenantHandler; import org.springframework.transaction.annotation.Transactional; @@ -213,7 +213,7 @@ public abstract class CrudServiceImpl, T extends BaseEnt public List findList(QueryWrapper queryWrapper) { // 数据处理责任链 queryWrapper = new QueryTenantHandler( - new QueryOrgHandler() + new QueryDataPermsHandler() ).handler(entityClazz, queryWrapper); return super.list(queryWrapper); @@ -225,7 +225,7 @@ public abstract class CrudServiceImpl, T extends BaseEnt QueryWrapper queryWrapper = queryBuilder.build(); // 数据处理责任链 queryWrapper = new QueryTenantHandler( - new QueryOrgHandler() + new QueryDataPermsHandler() ).handler(entityClazz, queryWrapper); return super.list(queryWrapper); diff --git a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/cache/pushsub/handler/OrgHandler.java b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/cache/pushsub/handler/OrgHandler.java index 7cc2529..fc98d3a 100644 --- a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/cache/pushsub/handler/OrgHandler.java +++ b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/cache/pushsub/handler/OrgHandler.java @@ -23,6 +23,7 @@ import org.opsli.core.cache.local.CacheUtil; import org.opsli.core.cache.pushsub.enums.MsgArgsType; import org.opsli.core.cache.pushsub.enums.PushSubType; import org.opsli.core.utils.OrgUtil; +import org.opsli.core.utils.UserUtil; import org.opsli.plugins.cache.EhCachePlugin; import org.springframework.beans.factory.annotation.Autowired; @@ -66,7 +67,7 @@ public class OrgHandler implements RedisPushSubHandler{ return; } - String cacheKey = CacheUtil.handleKey(OrgUtil.PREFIX_CODE + userId); + String cacheKey = CacheUtil.handleKey(UserUtil.PREFIX_ID_ORGS + userId); // 先删除 ehCachePlugin.delete(CacheConstants.EHCACHE_SPACE, cacheKey); diff --git a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/filters/interceptor/MybatisAutoFillInterceptor.java b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/filters/interceptor/MybatisAutoFillInterceptor.java index eb08e3d..fd25dff 100644 --- a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/filters/interceptor/MybatisAutoFillInterceptor.java +++ b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/filters/interceptor/MybatisAutoFillInterceptor.java @@ -28,8 +28,11 @@ import org.apache.ibatis.executor.Executor; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.mapping.SqlCommandType; import org.apache.ibatis.plugin.*; +import org.opsli.api.wrapper.system.org.SysOrgModel; +import org.opsli.api.wrapper.system.user.UserOrgRefModel; import org.opsli.common.constants.MyBatisConstants; import org.opsli.core.utils.UserTokenUtil; +import org.opsli.core.utils.UserUtil; import org.springframework.stereotype.Component; import java.lang.reflect.Field; @@ -180,6 +183,19 @@ public class MybatisAutoFillInterceptor implements Interceptor { BeanUtil.setProperty(arg, MyBatisConstants.FIELD_TENANT, UserTokenUtil.getTenantIdByToken()); } break; + // 组织机构设置 + case MyBatisConstants.FIELD_ORG_GROUP: + // 如果组织IDs 为空则进行默认赋值 + Object orgValue = ReflectUtil.getFieldValue(arg, f.getName()); + if(StringUtils.isBlank(Convert.toStr(orgValue))){ + UserOrgRefModel userOrgRefModel = + UserUtil.getUserDefOrgByUserId(UserTokenUtil.getUserIdByToken()); + if(null != userOrgRefModel){ + String orgIds = userOrgRefModel.getOrgIds(); + BeanUtil.setProperty(arg, MyBatisConstants.FIELD_ORG_GROUP, orgIds); + } + } + break; default: break; } diff --git a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/msg/TokenMsg.java b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/msg/TokenMsg.java index 853a6e3..c22fbac 100644 --- a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/msg/TokenMsg.java +++ b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/msg/TokenMsg.java @@ -50,7 +50,7 @@ public enum TokenMsg implements BaseMsg { EXCEPTION_LOGIN_DECRYPT(12107,"登录账号密码解析失败"), EXCEPTION_USER_ROLE_NOT_NULL(12108,"用户暂无角色,请设置后登录"), EXCEPTION_USER_MENU_NOT_NULL(12109,"用户暂无角色菜单,请设置后登录"), - + EXCEPTION_USER_PERMS_NOT_NULL(12110,"用户暂无权限,请设置后登录"), /** * 其他 */ diff --git a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/persistence/querybuilder/chain/QueryBuilderChain.java b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/persistence/querybuilder/chain/QueryBuilderChain.java index a990f6c..0854333 100644 --- a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/persistence/querybuilder/chain/QueryBuilderChain.java +++ b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/persistence/querybuilder/chain/QueryBuilderChain.java @@ -17,6 +17,7 @@ package org.opsli.core.persistence.querybuilder.chain; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import org.opsli.core.base.entity.BaseEntity; +import org.opsli.core.persistence.querybuilder.conf.WebQueryConf; /** * 查询构建器责任链 @@ -35,4 +36,15 @@ public interface QueryBuilderChain { */ QueryWrapper handler(Class entityClazz, QueryWrapper wrapper); + /** + * 执行 + * @param entityClazz entity class + * @param wrapper 包装类 + * @param webQueryConf 字段(如果是关联查询 出现字段冲突可指定字段) + * @param 泛型 + * @return + */ + QueryWrapper handler(Class entityClazz, WebQueryConf webQueryConf, + QueryWrapper wrapper); + } diff --git a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/persistence/querybuilder/chain/QueryDataPermsHandler.java b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/persistence/querybuilder/chain/QueryDataPermsHandler.java new file mode 100644 index 0000000..3ebe7ee --- /dev/null +++ b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/persistence/querybuilder/chain/QueryDataPermsHandler.java @@ -0,0 +1,232 @@ +/** + * Copyright 2020 OPSLI 快速开发平台 https://www.opsli.com + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package org.opsli.core.persistence.querybuilder.chain; + +import cn.hutool.core.util.ReflectUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.google.common.collect.Lists; +import org.apache.commons.lang3.StringUtils; +import org.opsli.api.wrapper.system.role.RoleModel; +import org.opsli.api.wrapper.system.user.UserModel; +import org.opsli.api.wrapper.system.user.UserOrgRefModel; +import org.opsli.common.constants.MyBatisConstants; +import org.opsli.common.utils.FieldUtil; +import org.opsli.common.utils.ListDistinctUtil; +import org.opsli.core.base.entity.BaseEntity; +import org.opsli.core.persistence.querybuilder.conf.WebQueryConf; +import org.opsli.core.utils.UserUtil; + +import java.util.List; + +/** + * 数据权限赋值处理 + * + * @author Parker + * @date 2020-09-13 19:36 + */ +public class QueryDataPermsHandler implements QueryBuilderChain{ + + /** + * 子 责任链 + */ + private QueryBuilderChain queryBuilderChain; + + + public QueryDataPermsHandler(){} + + /** + * 构造函数 + * @param queryBuilderChain 责任链 + */ + public QueryDataPermsHandler(QueryBuilderChain queryBuilderChain){ + this.queryBuilderChain = queryBuilderChain; + } + + @Override + public QueryWrapper handler(Class entityClazz, QueryWrapper wrapper) { + // 执行 子 责任链 + if(queryBuilderChain != null){ + wrapper = queryBuilderChain.handler(entityClazz, wrapper); + } + + // 自身责任 -- 判断组织 + boolean flag = ReflectUtil.hasField(entityClazz, MyBatisConstants.FIELD_ORG_GROUP); + if(flag) { + String fieldName = FieldUtil.humpToUnderline(MyBatisConstants.FIELD_ORG_GROUP); + // 处理查询条件 + handleDataPermsCondition(fieldName, wrapper); + } + + return wrapper; + } + + @Override + public QueryWrapper handler(Class entityClazz, WebQueryConf webQueryConf, QueryWrapper wrapper) { + // 执行 子 责任链 + if(queryBuilderChain != null){ + wrapper = queryBuilderChain.handler(entityClazz, webQueryConf, wrapper); + } + + // 自身责任 -- 判断组织 + boolean flag = ReflectUtil.hasField(entityClazz, MyBatisConstants.FIELD_ORG_GROUP); + if(flag) { + String fieldName = webQueryConf.get(MyBatisConstants.FIELD_ORG_GROUP); + if(StringUtils.isEmpty(fieldName)){ + fieldName = FieldUtil.humpToUnderline(MyBatisConstants.FIELD_ORG_GROUP); + } + + // 处理查询条件 + handleDataPermsCondition(fieldName, wrapper); + } + + return wrapper; + } + + + /** + * 处理 数据权限 条件 + * + * @param field 查询字段 + * @param queryWrapper 组织集合 + */ + private static QueryWrapper handleDataPermsCondition(String field, QueryWrapper queryWrapper) { + + // 1. 当前用户 + UserModel currUser = UserUtil.getUser(); + + // 2. 当前用户 组织机构集合 + List userOrgRefModelList = UserUtil.getOrgListByUserId(currUser.getId()); + List orgIdGroupList = Lists.newArrayListWithCapacity(userOrgRefModelList.size()); + for (UserOrgRefModel userOrgRefModel : userOrgRefModelList) { + orgIdGroupList.add(userOrgRefModel.getOrgIds()); + } + // 组织机构集合 去重 + orgIdGroupList = ListDistinctUtil.distinct(orgIdGroupList); + + // 3. 获得查询类型 + // 如果是超级管理员 则查询类型为全部 + ConditionType conditionType = ConditionType.SELF; + if(StringUtils.equals(UserUtil.SUPER_ADMIN, currUser.getUsername())){ + conditionType = ConditionType.ALL; + }else{ + // 如果不是超级管理员 则获得当前用户的默认角色下的 授权数据权限类型 + RoleModel defRole = UserUtil.getUserDefRoleByUserId(currUser.getId()); + if(null != defRole){ + conditionType = ConditionType.getConditionType(defRole.getDataScope()); + } + } + + // 4. 如果查询字段为空 则默认 + if(StringUtils.isBlank(field)){ + field = FieldUtil.humpToUnderline(MyBatisConstants.FIELD_ORG_GROUP); + } + + // 常量 + final ConditionType finalConditionType = conditionType; + final String finalField = field; + final List finalOrgIdGroupList = orgIdGroupList; + + // 查询 全部 + if(ConditionType.ALL.equals(finalConditionType)){ + // .. + }else { + queryWrapper.and(wra -> { + // 查询 本部门 + if(ConditionType.DEPT.equals(finalConditionType)){ + wra.in(finalField, finalOrgIdGroupList); + } + // 部门及以下 + else if(ConditionType.DEPT_AND_BELOW.equals(finalConditionType)){ + wra.and(wraConfine -> { + // 增加右模糊 查询条件 + for (int i = 0; i < finalOrgIdGroupList.size(); i++) { + // 右模糊匹配 + wraConfine.likeRight( + finalField, finalOrgIdGroupList.get(i)); + + if(i < finalOrgIdGroupList.size() - 1){ + wraConfine.or(); + } + } + }); + }else { + // 查自身 + wra.in(FieldUtil.humpToUnderline(MyBatisConstants.FIELD_CREATE_BY), currUser.getId()); + } + }); + } + + + return queryWrapper; + } + + // ================================= + + /** + * 条件类型 + */ + public enum ConditionType{ + + /** 自身 */ + SELF("0", "自身"), + + /** 部门 */ + DEPT("1", "本部门"), + + /** 部门及以下 */ + DEPT_AND_BELOW("2", "本部门及以下"), + + /** 全部 */ + ALL("3", "全部"); + + + /** 值 */ + private final String value; + + /** 描述 */ + private final String describe; + + ConditionType(String value, String describe){ + this.value = value; + this.describe = describe; + } + + public String getValue() { + return value; + } + + public String getDescribe() { + return describe; + } + + /** + * 获得 类型 + * @param value 值 + * @return AlgSource + */ + public static ConditionType getConditionType(String value) { + ConditionType[] var1 = values(); + for (ConditionType source : var1) { + if(source.value.equals(value)){ + return source; + } + } + // 如果条件类型为空 则默认 查看自身数据 + return ConditionType.SELF; + } + } + +} diff --git a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/persistence/querybuilder/chain/QueryOrgHandler.java b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/persistence/querybuilder/chain/QueryOrgHandler.java deleted file mode 100644 index e782f9f..0000000 --- a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/persistence/querybuilder/chain/QueryOrgHandler.java +++ /dev/null @@ -1,71 +0,0 @@ -/** - * Copyright 2020 OPSLI 快速开发平台 https://www.opsli.com - *

- * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package org.opsli.core.persistence.querybuilder.chain; - -import cn.hutool.core.util.ReflectUtil; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import org.apache.commons.lang3.StringUtils; -import org.opsli.api.wrapper.system.user.UserModel; -import org.opsli.common.constants.MyBatisConstants; -import org.opsli.common.utils.FieldUtil; -import org.opsli.core.base.entity.BaseEntity; -import org.opsli.core.utils.UserUtil; - -/** - * 组织赋值处理 - * - * @author Parker - * @date 2020-09-13 19:36 - */ -public class QueryOrgHandler implements QueryBuilderChain{ - - /** - * 子 责任链 - */ - private QueryBuilderChain queryBuilderChain; - - - public QueryOrgHandler(){} - - /** - * 构造函数 - * @param queryBuilderChain 责任链 - */ - public QueryOrgHandler(QueryBuilderChain queryBuilderChain){ - this.queryBuilderChain = queryBuilderChain; - } - - @Override - public QueryWrapper handler(Class entityClazz, QueryWrapper wrapper) { - // 执行 子 责任链 - if(queryBuilderChain != null){ - wrapper = queryBuilderChain.handler(entityClazz, wrapper); - } - - // 自身责任 -- 判断组织 - boolean flag = ReflectUtil.hasField(entityClazz, MyBatisConstants.FIELD_ORG_GROUP); - if(flag) { - // 1. 获得 用户 数据权限 - - // 2. 获得 角色 数据权限 - - } - - - return wrapper; - } - -} diff --git a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/persistence/querybuilder/chain/QueryTenantHandler.java b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/persistence/querybuilder/chain/QueryTenantHandler.java index 786ad32..b3b1be2 100644 --- a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/persistence/querybuilder/chain/QueryTenantHandler.java +++ b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/persistence/querybuilder/chain/QueryTenantHandler.java @@ -22,6 +22,7 @@ import org.opsli.api.wrapper.system.user.UserModel; import org.opsli.common.constants.MyBatisConstants; import org.opsli.common.utils.FieldUtil; import org.opsli.core.base.entity.BaseEntity; +import org.opsli.core.persistence.querybuilder.conf.WebQueryConf; import org.opsli.core.utils.UserUtil; /** @@ -70,4 +71,31 @@ public class QueryTenantHandler implements QueryBuilderChain{ return wrapper; } + @Override + public QueryWrapper handler(Class entityClazz, WebQueryConf webQueryConf, QueryWrapper wrapper) { + // 执行 子 责任链 + if(queryBuilderChain != null){ + wrapper = queryBuilderChain.handler(entityClazz, webQueryConf, wrapper); + } + + // 自身责任 -- 判断多租户 + boolean tenantFlag = ReflectUtil.hasField(entityClazz, MyBatisConstants.FIELD_TENANT); + if(tenantFlag) { + String tenantId = UserUtil.getTenantId(); + UserModel user = UserUtil.getUser(); + // 超级管理员可以操作 无租户限制, 其余用户全部有租户限制 + if(!UserUtil.SUPER_ADMIN.equals(user.getUsername()) && + StringUtils.isNotEmpty(tenantId) + ){ + + String fieldName = webQueryConf.get(MyBatisConstants.FIELD_TENANT); + if(StringUtils.isEmpty(fieldName)){ + fieldName = FieldUtil.humpToUnderline(MyBatisConstants.FIELD_TENANT); + } + wrapper.eq(fieldName, tenantId); + } + } + return wrapper; + } + } diff --git a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/persistence/querybuilder/conf/WebQueryConf.java b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/persistence/querybuilder/conf/WebQueryConf.java index 2ea38c2..e520b3e 100644 --- a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/persistence/querybuilder/conf/WebQueryConf.java +++ b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/persistence/querybuilder/conf/WebQueryConf.java @@ -15,6 +15,10 @@ */ package org.opsli.core.persistence.querybuilder.conf; +import org.apache.poi.ss.formula.functions.T; +import org.opsli.common.utils.FieldUtil; + +import java.lang.reflect.Field; import java.util.HashMap; import java.util.Map; @@ -34,29 +38,30 @@ public class WebQueryConf { /** - * 判断是否包含 Key - * @param key key + * 存放 + * @param fieldFn 字段 * @param value 值 */ - public void pub(String key, String value){ - queryMap.putIfAbsent(key, value); + public void pub(FieldUtil.SFunction fieldFn, String value){ + String fileName = FieldUtil.getFileName(fieldFn); + queryMap.putIfAbsent(fileName, value); } /** - * 判断是否包含 Key - * @param key key + * 获取 + * @param field 字段 */ - public String get(String key){ - return queryMap.get(key); + public String get(String field){ + return queryMap.get(field); } /** - * 判断是否包含 Key - * @param key key + * 判断是否包含 field + * @param field 字段 * @return boolean */ - public boolean hashKey(String key){ - return queryMap.containsKey(key); + public boolean hashKey(String field){ + return queryMap.containsKey(field); } } \ No newline at end of file diff --git a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/OrgUtil.java b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/OrgUtil.java index 3e24599..19a5f3f 100644 --- a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/OrgUtil.java +++ b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/OrgUtil.java @@ -16,34 +16,17 @@ package org.opsli.core.utils; import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.collection.ListUtil; -import cn.hutool.core.convert.Convert; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.google.common.collect.Lists; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; -import org.opsli.api.base.result.ResultVo; -import org.opsli.api.web.system.user.UserApi; -import org.opsli.api.web.system.user.UserOrgRefApi; -import org.opsli.api.wrapper.system.menu.MenuModel; import org.opsli.api.wrapper.system.org.SysOrgModel; -import org.opsli.api.wrapper.system.user.UserModel; import org.opsli.api.wrapper.system.user.UserOrgRefModel; -import org.opsli.api.wrapper.system.user.UserOrgRefWebModel; import org.opsli.common.enums.DictType; import org.opsli.common.utils.FieldUtil; import org.opsli.common.utils.ListDistinctUtil; -import org.opsli.core.cache.local.CacheUtil; -import org.opsli.core.msg.CoreMsg; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Lazy; -import org.springframework.core.annotation.Order; -import org.springframework.stereotype.Component; import java.util.List; -import static org.opsli.common.constants.OrderConstants.UTIL_ORDER; - /** * 组织机构工具类 * @@ -51,13 +34,7 @@ import static org.opsli.common.constants.OrderConstants.UTIL_ORDER; * @date 2020-09-19 20:03 */ @Slf4j -@Order(UTIL_ORDER) -@Component -@Lazy(false) -public class OrgUtil { - - /** 前缀 */ - public static final String PREFIX_CODE = "org:userId:"; +public final class OrgUtil { /** 用户表 是否分配组织 状态标识 */ public static final String USER_ORG_FIELD = "iz_exist_org"; @@ -66,79 +43,9 @@ public class OrgUtil { /** 未分组 */ public static final String ORG_NULL = "org_null"; - /** 用户组织 Api */ - private static UserOrgRefApi userOrgRefApi; - /** 增加初始状态开关 防止异常使用 */ private static boolean IS_INIT; - /** - * 根据 userId 获得用户菜单 - * @param userId 用户ID - * @return List - */ - public static List getOrgListByUserId(String userId){ - // 判断 工具类是否初始化完成 - ThrowExceptionUtil.isThrowException(!IS_INIT, - CoreMsg.OTHER_EXCEPTION_UTILS_INIT); - - // 缓存Key - String cacheKey = PREFIX_CODE + userId; - - List orgList; - - // 先从缓存里拿 - Object obj = CacheUtil.getTimed(cacheKey); - orgList = Convert.toList(UserOrgRefModel.class, obj); - if(CollUtil.isNotEmpty(orgList)){ - return orgList; - } - - // 拿不到 -------- - // 防止缓存穿透判断 - boolean hasNilFlag = CacheUtil.hasNilFlag(cacheKey); - if(hasNilFlag){ - return ListUtil.empty(); - } - - - try { - // 分布式加锁 - if(!DistributedLockUtil.lock(cacheKey)){ - // 无法申领分布式锁 - log.error(CoreMsg.REDIS_EXCEPTION_LOCK.getMessage()); - return ListUtil.empty(); - } - - // 如果获得锁 则 再次检查缓存里有没有, 如果有则直接退出, 没有的话才发起数据库请求 - obj = CacheUtil.getTimed(cacheKey); - orgList = Convert.toList(UserOrgRefModel.class, obj); - if(CollUtil.isNotEmpty(orgList)){ - return orgList; - } - - // 查询数据库 - ResultVo> resultVo = userOrgRefApi.findListByUserId(userId); - if(resultVo.isSuccess()){ - orgList = resultVo.getData(); - // 存入缓存 - CacheUtil.put(cacheKey, orgList); - } - }catch (Exception e){ - log.error(e.getMessage(), e); - }finally { - // 释放锁 - DistributedLockUtil.unlock(cacheKey); - } - - if(CollUtil.isEmpty(orgList)){ - // 设置空变量 用于防止穿透判断 - CacheUtil.putNilFlag(cacheKey); - return ListUtil.empty(); - } - - return orgList; - } /** * 处理展示节点 @@ -179,8 +86,7 @@ public class OrgUtil { if(!ORG_NULL.equals(orgIdGroup)){ wra.and(wraConfine -> { // 增加自身 组织限制 - UserModel currUser = UserUtil.getUser(); - List orgListByUserId = OrgUtil.getOrgListByUserId(currUser.getId()); + List orgListByUserId = UserUtil.getOrgByCurrUser(); if(CollUtil.isEmpty(orgListByUserId)){ // 如果为空 则默认 不查询 wraConfine.eq("1", "2"); @@ -240,60 +146,8 @@ public class OrgUtil { }); } - // ============== 刷新缓存 ============== - - /** - * 刷新用户组织 - 删就完了 - * @param userId 用户ID - * @return boolean - */ - public static boolean refreshOrg(String userId){ - // 判断 工具类是否初始化完成 - ThrowExceptionUtil.isThrowException(!IS_INIT, - CoreMsg.OTHER_EXCEPTION_UTILS_INIT); - - if(StringUtils.isEmpty(userId)){ - return true; - } - - // 计数器 - int count = 0; - - UserOrgRefWebModel orgRefModel = CacheUtil.getTimed(UserOrgRefWebModel.class, PREFIX_CODE + userId); - boolean hasNilFlag = CacheUtil.hasNilFlag(PREFIX_CODE + userId); - - // 只要不为空 则执行刷新 - if (hasNilFlag){ - count++; - // 清除空拦截 - boolean tmp = CacheUtil.delNilFlag(PREFIX_CODE + userId); - if(tmp){ - count--; - } - } - - if(orgRefModel != null){ - count++; - // 先删除 - boolean tmp = CacheUtil.del(PREFIX_CODE + userId); - if(tmp){ - count--; - } - } - return count == 0; - } - - - // ===================================== + // =========== - /** - * 初始化 - */ - @Autowired - public void init(UserOrgRefApi userOrgRefApi) { - OrgUtil.userOrgRefApi = userOrgRefApi; - - IS_INIT = true; - } + private OrgUtil() {} } diff --git a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/UserTokenUtil.java b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/UserTokenUtil.java index 77ad6d8..47e84aa 100644 --- a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/UserTokenUtil.java +++ b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/UserTokenUtil.java @@ -254,12 +254,15 @@ public class UserTokenUtil { // 如果缓存中 无该用户任何Token信息 则删除用户缓存 Long size = redisPlugin.sSize( CacheUtil.getPrefixName() + TICKET_PREFIX + user.getUsername()); - if(size == null || size == 0L){ + if(size == null || size == 0L) { // 删除相关信息 UserUtil.refreshUser(user); UserUtil.refreshUserRoles(user.getId()); UserUtil.refreshUserAllPerms(user.getId()); UserUtil.refreshUserMenus(user.getId()); + UserUtil.refreshUserOrgs(user.getId()); + UserUtil.refreshUserDefRole(userId); + UserUtil.refreshUserDefOrg(userId); } } diff --git a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/UserUtil.java b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/UserUtil.java index 1e8ffd3..848bb25 100644 --- a/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/UserUtil.java +++ b/opsli-base-support/opsli-core/src/main/java/org/opsli/core/utils/UserUtil.java @@ -23,11 +23,15 @@ import org.apache.commons.lang3.StringUtils; import org.apache.shiro.crypto.hash.Md5Hash; import org.opsli.api.base.result.ResultVo; import org.opsli.api.web.system.user.UserApi; +import org.opsli.api.web.system.user.UserOrgRefApi; +import org.opsli.api.web.system.user.UserRoleRefApi; import org.opsli.api.wrapper.system.menu.MenuModel; +import org.opsli.api.wrapper.system.role.RoleModel; import org.opsli.api.wrapper.system.user.UserModel; -import org.opsli.common.exception.ServiceException; -import org.opsli.core.api.TokenThreadLocal; +import org.opsli.api.wrapper.system.user.UserOrgRefModel; +import org.opsli.api.wrapper.system.user.UserOrgRefWebModel; import org.opsli.common.exception.TokenException; +import org.opsli.core.api.TokenThreadLocal; import org.opsli.core.autoconfigure.properties.GlobalProperties; import org.opsli.core.cache.local.CacheUtil; import org.opsli.core.msg.CoreMsg; @@ -36,6 +40,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; + import java.util.List; import static org.opsli.common.constants.OrderConstants.UTIL_ORDER; @@ -55,6 +60,9 @@ public class UserUtil { /** 前缀 */ public static final String PREFIX_ID = "userId:"; public static final String PREFIX_ID_ROLES = "userId:roles:"; + public static final String PREFIX_ID_DEF_ROLE = "userId:def_role:"; + public static final String PREFIX_ID_ORGS = "userId:orgs"; + public static final String PREFIX_ID_DEF_ORG = "userId:def_org:"; public static final String PREFIX_ID_PERMISSIONS = "userId:permissions:"; public static final String PREFIX_ID_MENUS = "userId:menus:"; public static final String PREFIX_USERNAME = "username:"; @@ -65,6 +73,12 @@ public class UserUtil { /** 用户Service */ private static UserApi userApi; + /** 用户角色 Api */ + private static UserRoleRefApi userRoleRefApi; + + /** 用户组织 Api */ + private static UserOrgRefApi userOrgRefApi; + /** 超级管理员 */ public static String SUPER_ADMIN; @@ -274,7 +288,7 @@ public class UserUtil { } // 查询数据库 - ResultVo> resultVo = userApi.getRolesByUserId(userId); + ResultVo> resultVo = userRoleRefApi.getRolesByUserId(userId); if(resultVo.isSuccess()){ roles = resultVo.getData(); // 存入缓存 @@ -342,7 +356,7 @@ public class UserUtil { } // 查询数据库 - ResultVo> resultVo = userApi.getAllPerms(userId); + ResultVo> resultVo = userRoleRefApi.getAllPerms(userId); if(resultVo.isSuccess()){ permissions = resultVo.getData(); // 存入缓存 @@ -364,6 +378,87 @@ public class UserUtil { return permissions; } + /** + * 根据 userId 获得用户组织机构 + * @param userId 用户ID + * @return List + */ + public static List getOrgListByUserId(String userId){ + // 判断 工具类是否初始化完成 + ThrowExceptionUtil.isThrowException(!IS_INIT, + CoreMsg.OTHER_EXCEPTION_UTILS_INIT); + + // 缓存Key + String cacheKey = PREFIX_ID_ORGS + userId; + + List orgList; + + // 先从缓存里拿 + Object obj = CacheUtil.getTimed(cacheKey); + orgList = Convert.toList(UserOrgRefModel.class, obj); + if(CollUtil.isNotEmpty(orgList)){ + return orgList; + } + + // 拿不到 -------- + // 防止缓存穿透判断 + boolean hasNilFlag = CacheUtil.hasNilFlag(cacheKey); + if(hasNilFlag){ + return ListUtil.empty(); + } + + + try { + // 分布式加锁 + if(!DistributedLockUtil.lock(cacheKey)){ + // 无法申领分布式锁 + log.error(CoreMsg.REDIS_EXCEPTION_LOCK.getMessage()); + return ListUtil.empty(); + } + + // 如果获得锁 则 再次检查缓存里有没有, 如果有则直接退出, 没有的话才发起数据库请求 + obj = CacheUtil.getTimed(cacheKey); + orgList = Convert.toList(UserOrgRefModel.class, obj); + if(CollUtil.isNotEmpty(orgList)){ + return orgList; + } + + // 查询数据库 + ResultVo> resultVo = userOrgRefApi.findListByUserId(userId); + if(resultVo.isSuccess()){ + orgList = resultVo.getData(); + // 存入缓存 + CacheUtil.put(cacheKey, orgList); + } + }catch (Exception e){ + log.error(e.getMessage(), e); + }finally { + // 释放锁 + DistributedLockUtil.unlock(cacheKey); + } + + if(CollUtil.isEmpty(orgList)){ + // 设置空变量 用于防止穿透判断 + CacheUtil.putNilFlag(cacheKey); + return ListUtil.empty(); + } + + return orgList; + } + + /** + * 根据 当前用户的组织机构 + * @return List + */ + public static List getOrgByCurrUser(){ + // 判断 工具类是否初始化完成 + ThrowExceptionUtil.isThrowException(!IS_INIT, + CoreMsg.OTHER_EXCEPTION_UTILS_INIT); + + UserModel user = UserUtil.getUser(); + return getOrgListByUserId(user.getId()); + } + /** * 根据 userId 获得用户菜单 * @param userId 用户ID @@ -410,7 +505,7 @@ public class UserUtil { } // 查询数据库 - ResultVo> resultVo = userApi.getMenuListByUserId(userId); + ResultVo> resultVo = userRoleRefApi.getMenuListByUserId(userId); if(resultVo.isSuccess()){ menus = resultVo.getData(); // 存入缓存 @@ -432,6 +527,136 @@ public class UserUtil { return menus; } + /** + * 根据 userId 获得用户默认角色 + * @param userId 用户ID + * @return List + */ + public static RoleModel getUserDefRoleByUserId(String userId){ + + // 判断 工具类是否初始化完成 + ThrowExceptionUtil.isThrowException(!IS_INIT, + CoreMsg.OTHER_EXCEPTION_UTILS_INIT); + + // 缓存Key + String cacheKey = PREFIX_ID_DEF_ROLE + userId; + + // 先从缓存里拿 + RoleModel roleModel = CacheUtil.getTimed(RoleModel.class, cacheKey); + if (roleModel != null){ + return roleModel; + } + + // 拿不到 -------- + // 防止缓存穿透判断 + boolean hasNilFlag = CacheUtil.hasNilFlag(cacheKey); + if(hasNilFlag){ + return null; + } + + try { + // 分布式加锁 + if(!DistributedLockUtil.lock(cacheKey)){ + // 无法申领分布式锁 + log.error(CoreMsg.REDIS_EXCEPTION_LOCK.getMessage()); + return null; + } + + // 如果获得锁 则 再次检查缓存里有没有, 如果有则直接退出, 没有的话才发起数据库请求 + roleModel = CacheUtil.getTimed(RoleModel.class, cacheKey); + if (roleModel != null){ + return roleModel; + } + + // 查询数据库 + ResultVo resultVo = userRoleRefApi.getDefRoleByUserId(userId); + if(resultVo.isSuccess()){ + roleModel = resultVo.getData(); + // 存入缓存 + CacheUtil.put(cacheKey, roleModel); + } + }catch (Exception e){ + log.error(e.getMessage(),e); + }finally { + // 释放锁 + DistributedLockUtil.unlock(cacheKey); + } + + if(roleModel == null){ + // 设置空变量 用于防止穿透判断 + CacheUtil.putNilFlag(cacheKey); + return null; + } + + return roleModel; + } + + + /** + * 根据 userId 获得用户默认组织 + * @param userId 用户ID + * @return List + */ + public static UserOrgRefModel getUserDefOrgByUserId(String userId){ + + // 判断 工具类是否初始化完成 + ThrowExceptionUtil.isThrowException(!IS_INIT, + CoreMsg.OTHER_EXCEPTION_UTILS_INIT); + + // 缓存Key + String cacheKey = PREFIX_ID_DEF_ORG + userId; + + // 先从缓存里拿 + UserOrgRefModel orgModel = CacheUtil.getTimed(UserOrgRefModel.class, cacheKey); + if (orgModel != null){ + return orgModel; + } + + // 拿不到 -------- + // 防止缓存穿透判断 + boolean hasNilFlag = CacheUtil.hasNilFlag(cacheKey); + if(hasNilFlag){ + return null; + } + + try { + // 分布式加锁 + if(!DistributedLockUtil.lock(cacheKey)){ + // 无法申领分布式锁 + log.error(CoreMsg.REDIS_EXCEPTION_LOCK.getMessage()); + return null; + } + + // 如果获得锁 则 再次检查缓存里有没有, 如果有则直接退出, 没有的话才发起数据库请求 + orgModel = CacheUtil.getTimed(UserOrgRefModel.class, cacheKey); + if (orgModel != null){ + return orgModel; + } + + // 查询数据库 + ResultVo resultVo = userOrgRefApi.getDefOrgByUserId(userId); + if(resultVo.isSuccess()){ + orgModel = resultVo.getData(); + // 存入缓存 + CacheUtil.put(cacheKey, orgModel); + } + }catch (Exception e){ + log.error(e.getMessage(),e); + }finally { + // 释放锁 + DistributedLockUtil.unlock(cacheKey); + } + + if(orgModel == null){ + // 设置空变量 用于防止穿透判断 + CacheUtil.putNilFlag(cacheKey); + return null; + } + + return orgModel; + } + + // ============== 刷新缓存 ============== /** @@ -536,6 +761,50 @@ public class UserUtil { return count == 0; } + /** + * 刷新用户默认角色 - 删就完了 + * @param userId 用户ID + * @return boolean + */ + public static boolean refreshUserDefRole(String userId){ + // 判断 工具类是否初始化完成 + ThrowExceptionUtil.isThrowException(!IS_INIT, + CoreMsg.OTHER_EXCEPTION_UTILS_INIT); + + if(StringUtils.isEmpty(userId)){ + return true; + } + + // 计数器 + int count = 0; + + RoleModel roleModel = CacheUtil.getTimed(RoleModel.class, PREFIX_ID_DEF_ROLE + userId); + boolean hasNilFlag = CacheUtil.hasNilFlag(PREFIX_ID_DEF_ROLE + userId); + + // 只要不为空 则执行刷新 + if (hasNilFlag){ + count++; + // 清除空拦截 + boolean tmp = CacheUtil.delNilFlag(PREFIX_ID_DEF_ROLE + userId); + if(tmp){ + count--; + } + } + + if(roleModel != null){ + count++; + // 先删除 + boolean tmp = CacheUtil.del(PREFIX_ID_DEF_ROLE + userId); + if(tmp){ + count--; + } + } + + return count == 0; + } + + + /** * 刷新用户权限 - 删就完了 * @param userId 用户ID @@ -576,6 +845,90 @@ public class UserUtil { return count == 0; } + /** + * 刷新用户组织 - 删就完了 + * @param userId 用户ID + * @return boolean + */ + public static boolean refreshUserOrgs(String userId){ + // 判断 工具类是否初始化完成 + ThrowExceptionUtil.isThrowException(!IS_INIT, + CoreMsg.OTHER_EXCEPTION_UTILS_INIT); + + if(StringUtils.isEmpty(userId)){ + return true; + } + + // 计数器 + int count = 0; + + UserOrgRefWebModel orgRefModel = CacheUtil.getTimed(UserOrgRefWebModel.class, PREFIX_ID_ORGS + userId); + boolean hasNilFlag = CacheUtil.hasNilFlag(PREFIX_ID_ORGS + userId); + + // 只要不为空 则执行刷新 + if (hasNilFlag){ + count++; + // 清除空拦截 + boolean tmp = CacheUtil.delNilFlag(PREFIX_ID_ORGS + userId); + if(tmp){ + count--; + } + } + + if(orgRefModel != null){ + count++; + // 先删除 + boolean tmp = CacheUtil.del(PREFIX_ID_ORGS + userId); + if(tmp){ + count--; + } + } + return count == 0; + } + + /** + * 刷新用户默认组织 - 删就完了 + * @param userId 用户ID + * @return boolean + */ + public static boolean refreshUserDefOrg(String userId){ + // 判断 工具类是否初始化完成 + ThrowExceptionUtil.isThrowException(!IS_INIT, + CoreMsg.OTHER_EXCEPTION_UTILS_INIT); + + if(StringUtils.isEmpty(userId)){ + return true; + } + + // 计数器 + int count = 0; + + UserOrgRefModel orgModel = CacheUtil.getTimed(UserOrgRefModel.class, PREFIX_ID_DEF_ORG + userId); + boolean hasNilFlag = CacheUtil.hasNilFlag(PREFIX_ID_DEF_ORG + userId); + + // 只要不为空 则执行刷新 + if (hasNilFlag){ + count++; + // 清除空拦截 + boolean tmp = CacheUtil.delNilFlag(PREFIX_ID_DEF_ORG + userId); + if(tmp){ + count--; + } + } + + if(orgModel != null){ + count++; + // 先删除 + boolean tmp = CacheUtil.del(PREFIX_ID_DEF_ORG + userId); + if(tmp){ + count--; + } + } + + return count == 0; + } + + /** * 刷新用户菜单 - 删就完了 * @param userId 用户ID @@ -692,7 +1045,10 @@ public class UserUtil { * 初始化 */ @Autowired - public void init(GlobalProperties globalProperties, UserApi userApi){ + public void init(GlobalProperties globalProperties, + UserApi userApi, + UserRoleRefApi userRoleRefApi, + UserOrgRefApi userOrgRefApi){ if(globalProperties != null && globalProperties.getAuth() != null && globalProperties.getAuth().getToken() != null ){ @@ -702,6 +1058,10 @@ public class UserUtil { UserUtil.userApi = userApi; + UserUtil.userRoleRefApi = userRoleRefApi; + + UserUtil.userOrgRefApi = userOrgRefApi; + IS_INIT = true; } diff --git a/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/login/web/LoginRestController.java b/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/login/web/LoginRestController.java index f0f5b7c..cb8f0c4 100644 --- a/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/login/web/LoginRestController.java +++ b/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/login/web/LoginRestController.java @@ -139,6 +139,13 @@ public class LoginRestController { // 用户暂无角色菜单,请设置后登录 throw new TokenException(TokenMsg.EXCEPTION_USER_MENU_NOT_NULL); } + + // 检测用户是否有角色权限 + List userAllPermsList = UserUtil.getUserAllPermsByUserId(user.getId()); + if(CollUtil.isEmpty(userAllPermsList)){ + // 用户暂无角色菜单,请设置后登录 + throw new TokenException(TokenMsg.EXCEPTION_USER_PERMS_NOT_NULL); + } } // 失败次数超过 验证次数阈值 开启验证码验证 diff --git a/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/menu/service/impl/MenuServiceImpl.java b/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/menu/service/impl/MenuServiceImpl.java index 584451b..38b90c8 100644 --- a/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/menu/service/impl/MenuServiceImpl.java +++ b/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/menu/service/impl/MenuServiceImpl.java @@ -374,7 +374,7 @@ public class MenuServiceImpl extends CrudServiceImpl userIdList = iUserRoleRefService.getUserIdListByMenuId(menuModel.getId()); if(CollUtil.isNotEmpty(userIdList)){ for (String userId : userIdList) { - cacheCount += 3; + cacheCount += 6; // 清空当期用户缓存角色、权限、菜单 cacheRet = UserUtil.refreshUserRoles(userId); if(cacheRet){ @@ -388,6 +388,18 @@ public class MenuServiceImpl extends CrudServiceImpl menuModelList = iUserService.getMenuAllListByUserId(user.getId()); + List menuModelList = iUserRoleRefService.getMenuAllListByUserId(user.getId()); // 这里有坑 如果 为 菜单数据 且 组件(Component)地址为空 不会跳转到主页 也不报错 // 修复菜单问题导致无法跳转主页 diff --git a/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/org/web/SysOrgRestController.java b/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/org/web/SysOrgRestController.java index b7a31da..ca7b249 100644 --- a/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/org/web/SysOrgRestController.java +++ b/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/org/web/SysOrgRestController.java @@ -92,7 +92,7 @@ public class SysOrgRestController extends BaseRestController queryBuilder = new GenQueryBuilder<>(); QueryWrapper wrapper = queryBuilder.build(); - List orgListByUserId = OrgUtil.getOrgByCurrUser(); + List orgListByUserId = UserUtil.getOrgByCurrUser(); if(!CollUtil.isEmpty(orgListByUserId)){ List parentIdList = Lists.newArrayListWithCapacity(orgListByUserId.size()); diff --git a/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/role/entity/SysRole.java b/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/role/entity/SysRole.java index 0be5ca2..c5b1e78 100644 --- a/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/role/entity/SysRole.java +++ b/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/role/entity/SysRole.java @@ -39,9 +39,12 @@ public class SysRole extends BaseEntity { /** 角色名称 */ private String roleName; - /** 是否内置数据 0否 1是*/ + /** 是否内置数据 0否 1是 */ private String izLock; + /** 授权数据范围 */ + private String dataScope; + /** 备注 */ @TableField(updateStrategy = FieldStrategy.IGNORED) private String remark; diff --git a/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/role/service/impl/RoleMenuRefServiceImpl.java b/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/role/service/impl/RoleMenuRefServiceImpl.java index 439fdd1..7272267 100644 --- a/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/role/service/impl/RoleMenuRefServiceImpl.java +++ b/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/role/service/impl/RoleMenuRefServiceImpl.java @@ -113,7 +113,7 @@ public class RoleMenuRefServiceImpl extends ServiceImpl getPerms(RoleMenuRefModel model) { if(model == null){ @@ -99,11 +99,11 @@ public class RoleMenuRefRestController implements RoleMenuRefApi { } /** - * 设置权限 + * 设置菜單权限 * @param model 模型 * @return ResultVo */ - @RequiresPermissions("system_role_setPerms") + @RequiresPermissions("system_role_setMenuPerms") @EnableLog @Override public ResultVo setPerms(RoleMenuRefModel model) { diff --git a/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/role/web/RoleRestController.java b/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/role/web/RoleRestController.java index 84b8e3c..61cbc6f 100644 --- a/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/role/web/RoleRestController.java +++ b/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/role/web/RoleRestController.java @@ -32,6 +32,7 @@ import org.opsli.common.annotation.EnableLog; import org.opsli.common.annotation.RequiresPermissionsCus; import org.opsli.common.constants.MyBatisConstants; import org.opsli.common.exception.ServiceException; +import org.opsli.common.utils.FieldUtil; import org.opsli.core.base.controller.BaseRestController; import org.opsli.core.persistence.Page; import org.opsli.core.persistence.querybuilder.GenQueryBuilder; @@ -93,8 +94,17 @@ public class RoleRestController extends BaseRestController findPage(Integer pageNo, Integer pageSize, HttpServletRequest request) { QueryBuilder queryBuilder = new WebQueryBuilder<>(entityClazz, request.getParameterMap()); + QueryWrapper wrapper = queryBuilder.build(); + + UserModel user = UserUtil.getUser(); + // 如果是超级管理员 则查询为空的角色 + if(StringUtils.equals(UserUtil.SUPER_ADMIN, user.getUsername())){ + // 角色分页 增加租户权限 + wrapper.isNull(FieldUtil.humpToUnderline(MyBatisConstants.FIELD_TENANT)); + } + Page page = new Page<>(pageNo, pageSize); - page.setQueryWrapper(queryBuilder.build()); + page.setQueryWrapper(wrapper); page = IService.findPage(page); return ResultVo.success(page.getPageData()); diff --git a/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/user/entity/SysUserRoleRef.java b/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/user/entity/SysUserRoleRef.java index d16d118..e0c434f 100644 --- a/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/user/entity/SysUserRoleRef.java +++ b/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/user/entity/SysUserRoleRef.java @@ -49,5 +49,7 @@ public class SysUserRoleRef implements Serializable { /** 角色ID */ private String roleId; + /** 是否默认 */ + private String izDef; } diff --git a/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/user/mapper/UserMapper.java b/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/user/mapper/UserMapper.java index 78153f6..4f091bd 100644 --- a/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/user/mapper/UserMapper.java +++ b/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/user/mapper/UserMapper.java @@ -37,41 +37,6 @@ import java.util.List; public interface UserMapper extends BaseMapper { - /** - * 根据用户ID 获得当前角色编码集合 - * @param userId 用户ID - * @return List - */ - List getRoleCodeList(String userId); - - /** - * 根据用户ID 获得当前角色Id集合 - * @param userId 用户ID - * @return List - */ - List getRoleIdList(String userId); - - /** - * 根据用户ID 获得权限 - * @param userId 用户ID - * @return List - */ - List queryAllPerms(String userId); - - /** - * 根据用户ID 获得菜单集合 - * @param userId 用户ID - * @return List - */ - List findMenuListByUserId(String userId); - - /** - * 根据用户ID 获得全部菜单集合 - * @param userId 用户ID - * @return List - */ - List findMenuAllListByUserId(String userId); - /** * 修改密码 * @param userPassword 账号密码 diff --git a/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/user/mapper/UserRoleRefMapper.java b/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/user/mapper/UserRoleRefMapper.java index cb3c6c0..6c85833 100644 --- a/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/user/mapper/UserRoleRefMapper.java +++ b/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/user/mapper/UserRoleRefMapper.java @@ -17,6 +17,7 @@ package org.opsli.modulars.system.user.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import org.apache.ibatis.annotations.Mapper; +import org.opsli.modulars.system.menu.entity.SysMenu; import org.opsli.modulars.system.user.entity.SysUserRoleRef; import java.util.List; @@ -30,6 +31,41 @@ import java.util.List; @Mapper public interface UserRoleRefMapper extends BaseMapper { + /** + * 根据用户ID 获得当前角色编码集合 + * @param userId 用户ID + * @return List + */ + List getRoleCodeList(String userId); + + /** + * 根据用户ID 获得当前角色Id集合 + * @param userId 用户ID + * @return List + */ + List getRoleIdList(String userId); + + /** + * 根据用户ID 获得权限 + * @param userId 用户ID + * @return List + */ + List queryAllPerms(String userId); + + /** + * 根据用户ID 获得菜单集合 + * @param userId 用户ID + * @return List + */ + List findMenuListByUserId(String userId); + + /** + * 根据用户ID 获得全部菜单集合 + * @param userId 用户ID + * @return List + */ + List findMenuAllListByUserId(String userId); + /** * 根据角色ID 获得当前用户Id集合 * @param roleId 角色ID diff --git a/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/user/mapper/xml/UserMapper.xml b/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/user/mapper/xml/UserMapper.xml index 680ed3a..af1807f 100644 --- a/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/user/mapper/xml/UserMapper.xml +++ b/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/user/mapper/xml/UserMapper.xml @@ -45,99 +45,6 @@ ${ew.customSqlSegment} - - - - - - - - - - - - update sys_user set diff --git a/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/user/mapper/xml/UserRoleRefMapper.xml b/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/user/mapper/xml/UserRoleRefMapper.xml index 48064be..f3e351b 100644 --- a/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/user/mapper/xml/UserRoleRefMapper.xml +++ b/opsli-modulars/opsli-modulars-system/src/main/java/org/opsli/modulars/system/user/mapper/xml/UserRoleRefMapper.xml @@ -2,6 +2,99 @@ + + + + + + + + + + + +