mirror of
				https://github.com/continew-org/continew-admin.git
				synced 2025-10-31 22:57:17 +08:00 
			
		
		
		
	新增:新增角色数据权限功能(基于 MyBatis Plus DataPermissionInterceptor 插件实现)
1.基于 MyBatis Plus DataPermissionInterceptor 插件实现的数据权限功能 2.通过在指定 Mapper 接口层方法添加 @DataPermission 注解实现数据权限
This commit is contained in:
		| @@ -0,0 +1,36 @@ | |||||||
|  | /* | ||||||
|  |  * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. | ||||||
|  |  * | ||||||
|  |  * 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 top.charles7c.cnadmin.common.annotation; | ||||||
|  |  | ||||||
|  | import java.lang.annotation.*; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * 数据权限注解 | ||||||
|  |  * | ||||||
|  |  * @author Charles7c | ||||||
|  |  * @since 2023/3/6 23:34 | ||||||
|  |  */ | ||||||
|  | @Target(ElementType.METHOD) | ||||||
|  | @Retention(RetentionPolicy.RUNTIME) | ||||||
|  | @Documented | ||||||
|  | public @interface DataPermission { | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 表别名 | ||||||
|  |      */ | ||||||
|  |     String value() default ""; | ||||||
|  | } | ||||||
| @@ -47,6 +47,17 @@ public interface BaseMapper<T> extends com.baomidou.mybatisplus.core.mapper.Base | |||||||
|         return Db.saveBatch(entityList); |         return Db.saveBatch(entityList); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 批量更新记录 | ||||||
|  |      * | ||||||
|  |      * @param entityList | ||||||
|  |      *            实体列表 | ||||||
|  |      * @return 是否成功 | ||||||
|  |      */ | ||||||
|  |     default boolean updateBatchById(Collection<T> entityList) { | ||||||
|  |         return Db.updateBatchById(entityList); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 链式查询 |      * 链式查询 | ||||||
|      * |      * | ||||||
|   | |||||||
| @@ -0,0 +1,187 @@ | |||||||
|  | /* | ||||||
|  |  * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. | ||||||
|  |  * | ||||||
|  |  * 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 top.charles7c.cnadmin.common.config.mybatis; | ||||||
|  |  | ||||||
|  | import java.lang.reflect.Method; | ||||||
|  | import java.util.Collections; | ||||||
|  |  | ||||||
|  | import lombok.extern.slf4j.Slf4j; | ||||||
|  |  | ||||||
|  | import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; | ||||||
|  | import com.baomidou.mybatisplus.core.toolkit.StringUtils; | ||||||
|  | import com.baomidou.mybatisplus.extension.plugins.handler.DataPermissionHandler; | ||||||
|  |  | ||||||
|  | import top.charles7c.cnadmin.common.annotation.DataPermission; | ||||||
|  | import top.charles7c.cnadmin.common.constant.StringConsts; | ||||||
|  | import top.charles7c.cnadmin.common.enums.DataScopeEnum; | ||||||
|  | import top.charles7c.cnadmin.common.model.dto.LoginUser; | ||||||
|  | import top.charles7c.cnadmin.common.model.dto.RoleDTO; | ||||||
|  | import top.charles7c.cnadmin.common.util.helper.LoginHelper; | ||||||
|  |  | ||||||
|  | import net.sf.jsqlparser.expression.*; | ||||||
|  | import net.sf.jsqlparser.expression.operators.conditional.AndExpression; | ||||||
|  | import net.sf.jsqlparser.expression.operators.conditional.OrExpression; | ||||||
|  | import net.sf.jsqlparser.expression.operators.relational.EqualsTo; | ||||||
|  | import net.sf.jsqlparser.expression.operators.relational.ExpressionList; | ||||||
|  | import net.sf.jsqlparser.expression.operators.relational.InExpression; | ||||||
|  | import net.sf.jsqlparser.schema.Column; | ||||||
|  | import net.sf.jsqlparser.schema.Table; | ||||||
|  | import net.sf.jsqlparser.statement.select.PlainSelect; | ||||||
|  | import net.sf.jsqlparser.statement.select.SelectExpressionItem; | ||||||
|  | import net.sf.jsqlparser.statement.select.SubSelect; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * 数据权限处理器实现类 | ||||||
|  |  * <p> | ||||||
|  |  * 来源:<a href="https://gitee.com/baomidou/mybatis-plus/issues/I37I90">DataPermissionInterceptor 如何使用?</a> | ||||||
|  |  * </p> | ||||||
|  |  * | ||||||
|  |  * @author Charles7c | ||||||
|  |  * @since 2023/3/6 23:19 | ||||||
|  |  */ | ||||||
|  | @Slf4j | ||||||
|  | public class DataPermissionHandlerImpl implements DataPermissionHandler { | ||||||
|  |  | ||||||
|  |     /** ID */ | ||||||
|  |     private static final String ID = "id"; | ||||||
|  |     /** 部门 ID */ | ||||||
|  |     private static final String DEPT_ID = "dept_id"; | ||||||
|  |     /** 创建人 */ | ||||||
|  |     private static final String CREATE_USER = "create_user"; | ||||||
|  |     /** 部门表 */ | ||||||
|  |     private static final String DEPT_TABLE = "sys_dept"; | ||||||
|  |     /** 角色和部门关联表 */ | ||||||
|  |     private static final String ROLE_DEPT_TABLE = "sys_role_dept"; | ||||||
|  |     /** 角色和部门关联表:角色 ID */ | ||||||
|  |     private static final String ROLE_ID = "role_id"; | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public Expression getSqlSegment(Expression where, String mappedStatementId) { | ||||||
|  |         try { | ||||||
|  |             Class<?> clazz = | ||||||
|  |                 Class.forName(mappedStatementId.substring(0, mappedStatementId.lastIndexOf(StringConsts.DOT))); | ||||||
|  |             String methodName = mappedStatementId.substring(mappedStatementId.lastIndexOf(StringConsts.DOT) + 1); | ||||||
|  |             Method[] methods = clazz.getDeclaredMethods(); | ||||||
|  |             for (Method method : methods) { | ||||||
|  |                 DataPermission annotation = method.getAnnotation(DataPermission.class); | ||||||
|  |                 if (ObjectUtils.isNotEmpty(annotation) | ||||||
|  |                     && (method.getName().equals(methodName) || (method.getName() + "_COUNT").equals(methodName))) { | ||||||
|  |                     // 获取当前登录用户 | ||||||
|  |                     LoginUser loginUser = LoginHelper.getLoginUser(); | ||||||
|  |                     if (ObjectUtils.isNotEmpty(loginUser) && !loginUser.isAdmin()) { | ||||||
|  |                         return buildDataScopeFilter(loginUser, annotation.value(), where); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } catch (ClassNotFoundException e) { | ||||||
|  |             log.error("Data permission handler build data scope filter occurred an error: {}.", e.getMessage(), e); | ||||||
|  |         } | ||||||
|  |         return where; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 构建数据范围过滤条件 | ||||||
|  |      * | ||||||
|  |      * @param user | ||||||
|  |      *            当前登录用户 | ||||||
|  |      * @param tableAlias | ||||||
|  |      *            表别名 | ||||||
|  |      * @param where | ||||||
|  |      *            当前查询条件 | ||||||
|  |      * @return 构建后查询条件 | ||||||
|  |      */ | ||||||
|  |     private static Expression buildDataScopeFilter(LoginUser user, String tableAlias, Expression where) { | ||||||
|  |         Expression expression = null; | ||||||
|  |         for (RoleDTO role : user.getRoleSet()) { | ||||||
|  |             DataScopeEnum dataScope = role.getDataScope(); | ||||||
|  |             if (DataScopeEnum.ALL.equals(dataScope)) { | ||||||
|  |                 return where; | ||||||
|  |             } | ||||||
|  |             if (DataScopeEnum.DEPT_AND_CHILD.equals(dataScope)) { | ||||||
|  |                 // select t1.* from table as t1 where t1.`dept_id` in (select `id` from `sys_dept` where `id` = xxx or | ||||||
|  |                 // find_in_set(xxx, `ancestors`)); | ||||||
|  |                 // 构建子查询 | ||||||
|  |                 SubSelect subSelect = new SubSelect(); | ||||||
|  |                 PlainSelect select = new PlainSelect(); | ||||||
|  |                 select.setSelectItems(Collections.singletonList(new SelectExpressionItem(new Column(ID)))); | ||||||
|  |                 select.setFromItem(new Table(DEPT_TABLE)); | ||||||
|  |                 EqualsTo equalsTo = new EqualsTo(); | ||||||
|  |                 equalsTo.setLeftExpression(new Column(ID)); | ||||||
|  |                 equalsTo.setRightExpression(new LongValue(user.getDeptId())); | ||||||
|  |                 Function function = new Function(); | ||||||
|  |                 function.setName("find_in_set"); | ||||||
|  |                 function.setParameters(new ExpressionList(new LongValue(user.getDeptId()), new Column("ancestors"))); | ||||||
|  |                 select.setWhere(new OrExpression(equalsTo, function)); | ||||||
|  |                 subSelect.setSelectBody(select); | ||||||
|  |                 // 构建父查询 | ||||||
|  |                 InExpression inExpression = new InExpression(); | ||||||
|  |                 inExpression.setLeftExpression(buildColumn(tableAlias, DEPT_ID)); | ||||||
|  |                 inExpression.setRightExpression(subSelect); | ||||||
|  |                 expression = | ||||||
|  |                     ObjectUtils.isNotEmpty(expression) ? new OrExpression(expression, inExpression) : inExpression; | ||||||
|  |             } else if (DataScopeEnum.DEPT.equals(dataScope)) { | ||||||
|  |                 // select t1.* from table as t1 where t1.`dept_id` = xxx; | ||||||
|  |                 EqualsTo equalsTo = new EqualsTo(); | ||||||
|  |                 equalsTo.setLeftExpression(buildColumn(tableAlias, DEPT_ID)); | ||||||
|  |                 equalsTo.setRightExpression(new LongValue(user.getDeptId())); | ||||||
|  |                 expression = ObjectUtils.isNotEmpty(expression) ? new OrExpression(expression, equalsTo) : equalsTo; | ||||||
|  |             } else if (DataScopeEnum.SELF.equals(dataScope)) { | ||||||
|  |                 // select t1.* from table as t1 where t1.`create_user` = xxx; | ||||||
|  |                 EqualsTo equalsTo = new EqualsTo(); | ||||||
|  |                 equalsTo.setLeftExpression(buildColumn(tableAlias, CREATE_USER)); | ||||||
|  |                 equalsTo.setRightExpression(new LongValue(user.getId())); | ||||||
|  |                 expression = ObjectUtils.isNotEmpty(expression) ? new OrExpression(expression, equalsTo) : equalsTo; | ||||||
|  |             } else if (DataScopeEnum.CUSTOM.equals(dataScope)) { | ||||||
|  |                 // select t1.* from table as t1 where t1.`dept_id` in (select `dept_id` from `sys_role_dept` where | ||||||
|  |                 // `role_id` = xxx); | ||||||
|  |                 // 构建子查询 | ||||||
|  |                 SubSelect subSelect = new SubSelect(); | ||||||
|  |                 PlainSelect select = new PlainSelect(); | ||||||
|  |                 select.setSelectItems(Collections.singletonList(new SelectExpressionItem(new Column(DEPT_ID)))); | ||||||
|  |                 select.setFromItem(new Table(ROLE_DEPT_TABLE)); | ||||||
|  |                 EqualsTo equalsTo = new EqualsTo(); | ||||||
|  |                 equalsTo.setLeftExpression(new Column(ROLE_ID)); | ||||||
|  |                 equalsTo.setRightExpression(new LongValue(role.getId())); | ||||||
|  |                 select.setWhere(equalsTo); | ||||||
|  |                 subSelect.setSelectBody(select); | ||||||
|  |                 // 构建父查询 | ||||||
|  |                 InExpression inExpression = new InExpression(); | ||||||
|  |                 inExpression.setLeftExpression(buildColumn(tableAlias, DEPT_ID)); | ||||||
|  |                 inExpression.setRightExpression(subSelect); | ||||||
|  |                 expression = | ||||||
|  |                     ObjectUtils.isNotEmpty(expression) ? new OrExpression(expression, inExpression) : inExpression; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return ObjectUtils.isNotEmpty(where) ? new AndExpression(where, new Parenthesis(expression)) : expression; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 构建 Column | ||||||
|  |      * | ||||||
|  |      * @param tableAlias | ||||||
|  |      *            表别名 | ||||||
|  |      * @param columnName | ||||||
|  |      *            字段名称 | ||||||
|  |      * @return 带表别名字段 | ||||||
|  |      */ | ||||||
|  |     private static Column buildColumn(String tableAlias, String columnName) { | ||||||
|  |         if (StringUtils.isNotEmpty(tableAlias)) { | ||||||
|  |             columnName = String.format("%s.%s", tableAlias, columnName); | ||||||
|  |         } | ||||||
|  |         return new Column(columnName); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -26,6 +26,7 @@ import com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator; | |||||||
| import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator; | import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator; | ||||||
| import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; | import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; | ||||||
| import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor; | import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor; | ||||||
|  | import com.baomidou.mybatisplus.extension.plugins.inner.DataPermissionInterceptor; | ||||||
| import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; | import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; | ||||||
|  |  | ||||||
| import cn.hutool.core.net.NetUtil; | import cn.hutool.core.net.NetUtil; | ||||||
| @@ -48,6 +49,8 @@ public class MybatisPlusConfiguration { | |||||||
|     @Bean |     @Bean | ||||||
|     public MybatisPlusInterceptor mybatisPlusInterceptor() { |     public MybatisPlusInterceptor mybatisPlusInterceptor() { | ||||||
|         MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); |         MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); | ||||||
|  |         // 数据权限插件 | ||||||
|  |         interceptor.addInnerInterceptor(new DataPermissionInterceptor(new DataPermissionHandlerImpl())); | ||||||
|         // 分页插件 |         // 分页插件 | ||||||
|         interceptor.addInnerInterceptor(paginationInnerInterceptor()); |         interceptor.addInnerInterceptor(paginationInnerInterceptor()); | ||||||
|         // 防全表更新与删除插件 |         // 防全表更新与删除插件 | ||||||
|   | |||||||
| @@ -29,20 +29,20 @@ import lombok.NoArgsConstructor; | |||||||
| public class SysConsts { | public class SysConsts { | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 超级管理员角色编码 |      * 管理员角色编码 | ||||||
|      */ |      */ | ||||||
|     public static final String SUPER_ADMIN = "admin"; |     public static final String ADMIN_ROLE_CODE = "admin"; | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * 全部权限标识 |  | ||||||
|      */ |  | ||||||
|     public static final String ALL_PERMISSION = "*"; |  | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 顶级父 ID |      * 顶级父 ID | ||||||
|      */ |      */ | ||||||
|     public static final Long SUPER_PARENT_ID = 0L; |     public static final Long SUPER_PARENT_ID = 0L; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 全部权限标识 | ||||||
|  |      */ | ||||||
|  |     public static final String ALL_PERMISSION = "*"; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 默认密码 |      * 默认密码 | ||||||
|      */ |      */ | ||||||
|   | |||||||
| @@ -22,6 +22,9 @@ import java.util.Set; | |||||||
|  |  | ||||||
| import lombok.Data; | import lombok.Data; | ||||||
|  |  | ||||||
|  | import cn.hutool.core.collection.CollUtil; | ||||||
|  |  | ||||||
|  | import top.charles7c.cnadmin.common.constant.SysConsts; | ||||||
| import top.charles7c.cnadmin.common.enums.GenderEnum; | import top.charles7c.cnadmin.common.enums.GenderEnum; | ||||||
|  |  | ||||||
| /** | /** | ||||||
| @@ -129,4 +132,21 @@ public class LoginUser implements Serializable { | |||||||
|      * 角色编码集合 |      * 角色编码集合 | ||||||
|      */ |      */ | ||||||
|     private Set<String> roles; |     private Set<String> roles; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 角色集合 | ||||||
|  |      */ | ||||||
|  |     private Set<RoleDTO> roleSet; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 是否为管理员 | ||||||
|  |      * | ||||||
|  |      * @return true:是,false:否 | ||||||
|  |      */ | ||||||
|  |     public boolean isAdmin() { | ||||||
|  |         if (CollUtil.isEmpty(roles)) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         return roles.contains(SysConsts.ADMIN_ROLE_CODE); | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -0,0 +1,50 @@ | |||||||
|  | /* | ||||||
|  |  * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. | ||||||
|  |  * | ||||||
|  |  * 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 top.charles7c.cnadmin.common.model.dto; | ||||||
|  |  | ||||||
|  | import java.io.Serializable; | ||||||
|  |  | ||||||
|  | import lombok.Data; | ||||||
|  |  | ||||||
|  | import top.charles7c.cnadmin.common.enums.DataScopeEnum; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * 角色信息 | ||||||
|  |  * | ||||||
|  |  * @author Charles7c | ||||||
|  |  * @since 2023/3/7 22:08 | ||||||
|  |  */ | ||||||
|  | @Data | ||||||
|  | public class RoleDTO implements Serializable { | ||||||
|  |  | ||||||
|  |     private static final long serialVersionUID = 1L; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * ID | ||||||
|  |      */ | ||||||
|  |     private Long id; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 角色编码 | ||||||
|  |      */ | ||||||
|  |     private String code; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 数据权限(1:全部数据权限,2:本部门及以下数据权限,3:本部门数据权限,4:仅本人数据权限,5:自定义数据权限) | ||||||
|  |      */ | ||||||
|  |     private DataScopeEnum dataScope; | ||||||
|  | } | ||||||
| @@ -33,6 +33,7 @@ import top.charles7c.cnadmin.common.util.helper.LoginHelper; | |||||||
| import top.charles7c.cnadmin.common.util.validate.CheckUtils; | import top.charles7c.cnadmin.common.util.validate.CheckUtils; | ||||||
| import top.charles7c.cnadmin.system.model.entity.UserDO; | import top.charles7c.cnadmin.system.model.entity.UserDO; | ||||||
| import top.charles7c.cnadmin.system.service.DeptService; | import top.charles7c.cnadmin.system.service.DeptService; | ||||||
|  | import top.charles7c.cnadmin.system.service.RoleService; | ||||||
| import top.charles7c.cnadmin.system.service.UserService; | import top.charles7c.cnadmin.system.service.UserService; | ||||||
|  |  | ||||||
| /** | /** | ||||||
| @@ -47,6 +48,7 @@ public class LoginServiceImpl implements LoginService { | |||||||
|  |  | ||||||
|     private final UserService userService; |     private final UserService userService; | ||||||
|     private final DeptService deptService; |     private final DeptService deptService; | ||||||
|  |     private final RoleService roleService; | ||||||
|     private final PermissionService permissionService; |     private final PermissionService permissionService; | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
| @@ -62,6 +64,7 @@ public class LoginServiceImpl implements LoginService { | |||||||
|         loginUser.setDeptName(ExceptionUtils.exToNull(() -> deptService.get(loginUser.getDeptId()).getName())); |         loginUser.setDeptName(ExceptionUtils.exToNull(() -> deptService.get(loginUser.getDeptId()).getName())); | ||||||
|         loginUser.setPermissions(permissionService.listPermissionByUserId(userId)); |         loginUser.setPermissions(permissionService.listPermissionByUserId(userId)); | ||||||
|         loginUser.setRoles(permissionService.listRoleCodeByUserId(userId)); |         loginUser.setRoles(permissionService.listRoleCodeByUserId(userId)); | ||||||
|  |         loginUser.setRoleSet(roleService.listByUserId(userId)); | ||||||
|         LoginHelper.login(loginUser); |         LoginHelper.login(loginUser); | ||||||
|  |  | ||||||
|         // 返回令牌 |         // 返回令牌 | ||||||
|   | |||||||
| @@ -46,7 +46,7 @@ public class PermissionServiceImpl implements PermissionService { | |||||||
|     public Set<String> listPermissionByUserId(Long userId) { |     public Set<String> listPermissionByUserId(Long userId) { | ||||||
|         Set<String> roleCodeSet = this.listRoleCodeByUserId(userId); |         Set<String> roleCodeSet = this.listRoleCodeByUserId(userId); | ||||||
|         // 超级管理员赋予全部权限 |         // 超级管理员赋予全部权限 | ||||||
|         if (roleCodeSet.contains(SysConsts.SUPER_ADMIN)) { |         if (roleCodeSet.contains(SysConsts.ADMIN_ROLE_CODE)) { | ||||||
|             return CollUtil.newHashSet(SysConsts.ALL_PERMISSION); |             return CollUtil.newHashSet(SysConsts.ALL_PERMISSION); | ||||||
|         } |         } | ||||||
|         return menuService.listPermissionByUserId(userId); |         return menuService.listPermissionByUserId(userId); | ||||||
|   | |||||||
| @@ -45,6 +45,11 @@ public class DeptDO extends BaseDO { | |||||||
|      */ |      */ | ||||||
|     private Long parentId; |     private Long parentId; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 祖级列表 | ||||||
|  |      */ | ||||||
|  |     private String ancestors; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 描述 |      * 描述 | ||||||
|      */ |      */ | ||||||
|   | |||||||
| @@ -72,4 +72,10 @@ public class DeptRequest extends BaseRequest { | |||||||
|      */ |      */ | ||||||
|     @Schema(description = "状态(1启用 2禁用)", type = "Integer", allowableValues = {"1", "2"}) |     @Schema(description = "状态(1启用 2禁用)", type = "Integer", allowableValues = {"1", "2"}) | ||||||
|     private DisEnableStatusEnum status; |     private DisEnableStatusEnum status; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 祖级列表 | ||||||
|  |      */ | ||||||
|  |     @Schema(description = "祖级列表") | ||||||
|  |     private String ancestors; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -84,7 +84,7 @@ public class RoleVO extends BaseVO { | |||||||
|     private Boolean disabled; |     private Boolean disabled; | ||||||
|  |  | ||||||
|     public Boolean getDisabled() { |     public Boolean getDisabled() { | ||||||
|         if (SysConsts.SUPER_ADMIN.equals(code)) { |         if (SysConsts.ADMIN_ROLE_CODE.equals(code)) { | ||||||
|             return true; |             return true; | ||||||
|         } |         } | ||||||
|         return disabled; |         return disabled; | ||||||
|   | |||||||
| @@ -20,6 +20,7 @@ import java.util.List; | |||||||
| import java.util.Set; | import java.util.Set; | ||||||
|  |  | ||||||
| import top.charles7c.cnadmin.common.base.BaseService; | import top.charles7c.cnadmin.common.base.BaseService; | ||||||
|  | import top.charles7c.cnadmin.common.model.dto.RoleDTO; | ||||||
| import top.charles7c.cnadmin.common.model.vo.LabelValueVO; | import top.charles7c.cnadmin.common.model.vo.LabelValueVO; | ||||||
| import top.charles7c.cnadmin.system.model.query.RoleQuery; | import top.charles7c.cnadmin.system.model.query.RoleQuery; | ||||||
| import top.charles7c.cnadmin.system.model.request.RoleRequest; | import top.charles7c.cnadmin.system.model.request.RoleRequest; | ||||||
| @@ -60,4 +61,13 @@ public interface RoleService extends BaseService<RoleVO, RoleDetailVO, RoleQuery | |||||||
|      * @return 角色编码集合 |      * @return 角色编码集合 | ||||||
|      */ |      */ | ||||||
|     Set<String> listCodeByUserId(Long userId); |     Set<String> listCodeByUserId(Long userId); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 根据用户 ID 查询角色 | ||||||
|  |      * | ||||||
|  |      * @param userId | ||||||
|  |      *            用户 ID | ||||||
|  |      * @return 角色集合 | ||||||
|  |      */ | ||||||
|  |     Set<RoleDTO> listByUserId(Long userId); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -16,6 +16,7 @@ | |||||||
|  |  | ||||||
| package top.charles7c.cnadmin.system.service.impl; | package top.charles7c.cnadmin.system.service.impl; | ||||||
|  |  | ||||||
|  | import java.util.ArrayList; | ||||||
| import java.util.List; | import java.util.List; | ||||||
| import java.util.Objects; | import java.util.Objects; | ||||||
|  |  | ||||||
| @@ -26,6 +27,8 @@ import lombok.RequiredArgsConstructor; | |||||||
| import org.springframework.stereotype.Service; | import org.springframework.stereotype.Service; | ||||||
| import org.springframework.transaction.annotation.Transactional; | import org.springframework.transaction.annotation.Transactional; | ||||||
|  |  | ||||||
|  | import cn.hutool.core.collection.CollUtil; | ||||||
|  |  | ||||||
| import top.charles7c.cnadmin.common.base.BaseServiceImpl; | import top.charles7c.cnadmin.common.base.BaseServiceImpl; | ||||||
| import top.charles7c.cnadmin.common.constant.SysConsts; | import top.charles7c.cnadmin.common.constant.SysConsts; | ||||||
| import top.charles7c.cnadmin.common.enums.DisEnableStatusEnum; | import top.charles7c.cnadmin.common.enums.DisEnableStatusEnum; | ||||||
| @@ -62,6 +65,9 @@ public class DeptServiceImpl extends BaseServiceImpl<DeptMapper, DeptDO, DeptVO, | |||||||
|         CheckUtils.throwIf(() -> isExists, String.format("新增失败,'%s'已存在", name)); |         CheckUtils.throwIf(() -> isExists, String.format("新增失败,'%s'已存在", name)); | ||||||
|  |  | ||||||
|         request.setStatus(DisEnableStatusEnum.ENABLE); |         request.setStatus(DisEnableStatusEnum.ENABLE); | ||||||
|  |         DeptDO parentDept = baseMapper.selectById(request.getParentId()); | ||||||
|  |         CheckUtils.throwIfNull(parentDept, "上级部门不存在"); | ||||||
|  |         request.setAncestors(String.format("%s,%s", parentDept.getAncestors(), request.getParentId())); | ||||||
|         return super.add(request); |         return super.add(request); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -72,6 +78,14 @@ public class DeptServiceImpl extends BaseServiceImpl<DeptMapper, DeptDO, DeptVO, | |||||||
|         boolean isExists = this.checkNameExists(name, request.getParentId(), request.getId()); |         boolean isExists = this.checkNameExists(name, request.getParentId(), request.getId()); | ||||||
|         CheckUtils.throwIf(() -> isExists, String.format("修改失败,'%s'已存在", name)); |         CheckUtils.throwIf(() -> isExists, String.format("修改失败,'%s'已存在", name)); | ||||||
|  |  | ||||||
|  |         DeptDO oldDept = baseMapper.selectById(request.getId()); | ||||||
|  |         // 更新祖级列表 | ||||||
|  |         if (!Objects.equals(oldDept.getParentId(), request.getParentId())) { | ||||||
|  |             DeptDO newParentDept = baseMapper.selectById(request.getParentId()); | ||||||
|  |             CheckUtils.throwIfNull(newParentDept, "上级部门不存在"); | ||||||
|  |             request.setAncestors(String.format("%s,%s", newParentDept.getAncestors(), request.getParentId())); | ||||||
|  |             this.updateChildrenAncestors(request.getId(), request.getAncestors(), oldDept.getAncestors()); | ||||||
|  |         } | ||||||
|         super.update(request); |         super.update(request); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -110,4 +124,30 @@ public class DeptServiceImpl extends BaseServiceImpl<DeptMapper, DeptDO, DeptVO, | |||||||
|         return baseMapper.lambdaQuery().eq(DeptDO::getName, name).eq(DeptDO::getParentId, parentId) |         return baseMapper.lambdaQuery().eq(DeptDO::getName, name).eq(DeptDO::getParentId, parentId) | ||||||
|             .ne(id != null, DeptDO::getId, id).exists(); |             .ne(id != null, DeptDO::getId, id).exists(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 更新子部门祖级列表 | ||||||
|  |      * | ||||||
|  |      * @param id | ||||||
|  |      *            ID | ||||||
|  |      * @param newAncestors | ||||||
|  |      *            新祖级列表 | ||||||
|  |      * @param oldAncestors | ||||||
|  |      *            原祖级列表 | ||||||
|  |      */ | ||||||
|  |     private void updateChildrenAncestors(Long id, String newAncestors, String oldAncestors) { | ||||||
|  |         List<DeptDO> children = | ||||||
|  |             baseMapper.lambdaQuery().apply(String.format("find_in_set(%s, `ancestors`)", id)).list(); | ||||||
|  |         if (CollUtil.isEmpty(children)) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         List<DeptDO> list = new ArrayList<>(children.size()); | ||||||
|  |         for (DeptDO child : children) { | ||||||
|  |             DeptDO dept = new DeptDO(); | ||||||
|  |             dept.setId(child.getId()); | ||||||
|  |             dept.setAncestors(child.getAncestors().replaceFirst(oldAncestors, newAncestors)); | ||||||
|  |             list.add(dept); | ||||||
|  |         } | ||||||
|  |         baseMapper.updateBatchById(list); | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -17,6 +17,7 @@ | |||||||
| package top.charles7c.cnadmin.system.service.impl; | package top.charles7c.cnadmin.system.service.impl; | ||||||
|  |  | ||||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||||
|  | import java.util.HashSet; | ||||||
| import java.util.List; | import java.util.List; | ||||||
| import java.util.Set; | import java.util.Set; | ||||||
| import java.util.stream.Collectors; | import java.util.stream.Collectors; | ||||||
| @@ -26,11 +27,13 @@ import lombok.RequiredArgsConstructor; | |||||||
| import org.springframework.stereotype.Service; | import org.springframework.stereotype.Service; | ||||||
| import org.springframework.transaction.annotation.Transactional; | import org.springframework.transaction.annotation.Transactional; | ||||||
|  |  | ||||||
|  | import cn.hutool.core.bean.BeanUtil; | ||||||
| import cn.hutool.core.collection.CollUtil; | import cn.hutool.core.collection.CollUtil; | ||||||
|  |  | ||||||
| import top.charles7c.cnadmin.common.base.BaseServiceImpl; | import top.charles7c.cnadmin.common.base.BaseServiceImpl; | ||||||
| import top.charles7c.cnadmin.common.constant.SysConsts; | import top.charles7c.cnadmin.common.constant.SysConsts; | ||||||
| import top.charles7c.cnadmin.common.enums.DisEnableStatusEnum; | import top.charles7c.cnadmin.common.enums.DisEnableStatusEnum; | ||||||
|  | import top.charles7c.cnadmin.common.model.dto.RoleDTO; | ||||||
| import top.charles7c.cnadmin.common.model.vo.LabelValueVO; | import top.charles7c.cnadmin.common.model.vo.LabelValueVO; | ||||||
| import top.charles7c.cnadmin.common.util.validate.CheckUtils; | import top.charles7c.cnadmin.common.util.validate.CheckUtils; | ||||||
| import top.charles7c.cnadmin.system.mapper.RoleMapper; | import top.charles7c.cnadmin.system.mapper.RoleMapper; | ||||||
| @@ -106,7 +109,7 @@ public class RoleServiceImpl extends BaseServiceImpl<RoleMapper, RoleDO, RoleVO, | |||||||
|         if (detailObj instanceof RoleDetailVO) { |         if (detailObj instanceof RoleDetailVO) { | ||||||
|             RoleDetailVO detailVO = (RoleDetailVO)detailObj; |             RoleDetailVO detailVO = (RoleDetailVO)detailObj; | ||||||
|             Long roleId = detailVO.getId(); |             Long roleId = detailVO.getId(); | ||||||
|             if (SysConsts.SUPER_ADMIN.equals(detailVO.getCode())) { |             if (SysConsts.ADMIN_ROLE_CODE.equals(detailVO.getCode())) { | ||||||
|                 List<MenuVO> list = menuService.list(null, null); |                 List<MenuVO> list = menuService.list(null, null); | ||||||
|                 List<Long> menuIds = list.stream().map(MenuVO::getId).collect(Collectors.toList()); |                 List<Long> menuIds = list.stream().map(MenuVO::getId).collect(Collectors.toList()); | ||||||
|                 detailVO.setMenuIds(menuIds); |                 detailVO.setMenuIds(menuIds); | ||||||
| @@ -138,6 +141,13 @@ public class RoleServiceImpl extends BaseServiceImpl<RoleMapper, RoleDO, RoleVO, | |||||||
|         return roleList.stream().map(RoleDO::getCode).collect(Collectors.toSet()); |         return roleList.stream().map(RoleDO::getCode).collect(Collectors.toSet()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public Set<RoleDTO> listByUserId(Long userId) { | ||||||
|  |         List<Long> roleIds = userRoleService.listRoleIdByUserId(userId); | ||||||
|  |         List<RoleDO> roleList = baseMapper.lambdaQuery().in(RoleDO::getId, roleIds).list(); | ||||||
|  |         return new HashSet<>(BeanUtil.copyToList(roleList, RoleDTO.class)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 检查名称是否存在 |      * 检查名称是否存在 | ||||||
|      * |      * | ||||||
|   | |||||||
| @@ -35,14 +35,14 @@ INSERT IGNORE INTO `sys_menu` VALUES (10000, 'Arco Design Vue', 0, 1, 'https://a | |||||||
| INSERT IGNORE INTO `sys_menu` VALUES (10001, 'GitHub', 0, 1, 'https://github.com/Charles7c/continew-admin', NULL, NULL, 'github', b'1', b'0', b'0', NULL, 101, 1, 1, NOW(), 1, NOW()); | INSERT IGNORE INTO `sys_menu` VALUES (10001, 'GitHub', 0, 1, 'https://github.com/Charles7c/continew-admin', NULL, NULL, 'github', b'1', b'0', b'0', NULL, 101, 1, 1, NOW(), 1, NOW()); | ||||||
|  |  | ||||||
| -- 初始化默认部门 | -- 初始化默认部门 | ||||||
| INSERT IGNORE INTO `sys_dept` VALUES (1, 'Xxx科技有限公司', 0, '系统初始部门', 1, 1, 1, NOW(), 1, NOW()); | INSERT IGNORE INTO `sys_dept` VALUES (1, 'Xxx科技有限公司', 0, '0', '系统初始部门', 1, 1, 1, NOW(), 1, NOW()); | ||||||
| INSERT IGNORE INTO `sys_dept` VALUES (2, '天津总部', 1, '系统初始部门', 1, 1, 1, NOW(), 1, NOW()); | INSERT IGNORE INTO `sys_dept` VALUES (2, '天津总部', 1, '0,1', '系统初始部门', 1, 1, 1, NOW(), 1, NOW()); | ||||||
| INSERT IGNORE INTO `sys_dept` VALUES (3, '研发部', 2, '系统初始部门', 1, 1, 1, NOW(), 1, NOW()); | INSERT IGNORE INTO `sys_dept` VALUES (3, '研发部', 2, '0,1,2', '系统初始部门', 1, 1, 1, NOW(), 1, NOW()); | ||||||
| INSERT IGNORE INTO `sys_dept` VALUES (4, 'UI部', 2, '系统初始部门', 2, 1, 1, NOW(), 1, NOW()); | INSERT IGNORE INTO `sys_dept` VALUES (4, 'UI部', 2, '0,1,2', '系统初始部门', 2, 1, 1, NOW(), 1, NOW()); | ||||||
| INSERT IGNORE INTO `sys_dept` VALUES (5, '测试部', 2, '系统初始部门', 3, 1, 1, NOW(), 1, NOW()); | INSERT IGNORE INTO `sys_dept` VALUES (5, '测试部', 2, '0,1,2', '系统初始部门', 3, 1, 1, NOW(), 1, NOW()); | ||||||
| INSERT IGNORE INTO `sys_dept` VALUES (6, '运维部', 2, '系统初始部门', 4, 1, 1, NOW(), 1, NOW()); | INSERT IGNORE INTO `sys_dept` VALUES (6, '运维部', 2, '0,1,2', '系统初始部门', 4, 1, 1, NOW(), 1, NOW()); | ||||||
| INSERT IGNORE INTO `sys_dept` VALUES (7, '研发一组', 3, '系统初始部门', 1, 1, 1, NOW(), 1, NOW()); | INSERT IGNORE INTO `sys_dept` VALUES (7, '研发一组', 3, '0,1,2,3', '系统初始部门', 1, 1, 1, NOW(), 1, NOW()); | ||||||
| INSERT IGNORE INTO `sys_dept` VALUES (8, '研发二组', 3, '系统初始部门', 2, 2, 1, NOW(), 1, NOW()); | INSERT IGNORE INTO `sys_dept` VALUES (8, '研发二组', 3, '0,1,2,3', '系统初始部门', 2, 2, 1, NOW(), 1, NOW()); | ||||||
|  |  | ||||||
| -- 初始化默认角色 | -- 初始化默认角色 | ||||||
| INSERT IGNORE INTO `sys_role` VALUES (1, '超级管理员', 'admin', 1, '系统初始角色', 1, 1, 1, NOW(), 1, NOW()); | INSERT IGNORE INTO `sys_role` VALUES (1, '超级管理员', 'admin', 1, '系统初始角色', 1, 1, 1, NOW(), 1, NOW()); | ||||||
|   | |||||||
| @@ -30,6 +30,7 @@ CREATE TABLE IF NOT EXISTS `sys_dept` ( | |||||||
|     `id` bigint(20) unsigned AUTO_INCREMENT COMMENT 'ID', |     `id` bigint(20) unsigned AUTO_INCREMENT COMMENT 'ID', | ||||||
|     `name` varchar(255) NOT NULL COMMENT '部门名称', |     `name` varchar(255) NOT NULL COMMENT '部门名称', | ||||||
|     `parent_id` bigint(20) unsigned DEFAULT 0 COMMENT '上级部门ID', |     `parent_id` bigint(20) unsigned DEFAULT 0 COMMENT '上级部门ID', | ||||||
|  |     `ancestors` varchar(512) DEFAULT '' COMMENT '祖级列表', | ||||||
|     `description` varchar(512) DEFAULT NULL COMMENT '描述', |     `description` varchar(512) DEFAULT NULL COMMENT '描述', | ||||||
|     `sort` int(11) unsigned DEFAULT 999 COMMENT '部门排序', |     `sort` int(11) unsigned DEFAULT 999 COMMENT '部门排序', | ||||||
|     `status` tinyint(1) unsigned DEFAULT 1 COMMENT '状态(1:启用,2:禁用)', |     `status` tinyint(1) unsigned DEFAULT 1 COMMENT '状态(1:启用,2:禁用)', | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user