houzhongjian
2024-07-23 d9f9ba31913bb9f5053ad78109e8a3c1c00f1e6a
提交 | 用户 | 时间
e7c126 1 package com.iailab.module.system.service.permission;
H 2
3 import cn.hutool.core.collection.CollUtil;
4 import cn.hutool.core.collection.CollectionUtil;
5 import cn.hutool.core.util.ObjectUtil;
6 import cn.hutool.extra.spring.SpringUtil;
7 import com.iailab.framework.common.enums.CommonStatusEnum;
8 import com.iailab.framework.common.pojo.PageResult;
9 import com.iailab.framework.common.util.collection.CollectionUtils;
10 import com.iailab.framework.common.util.object.BeanUtils;
d9f9ba 11 import com.iailab.framework.mybatis.core.query.LambdaQueryWrapperX;
e7c126 12 import com.iailab.module.system.controller.admin.permission.vo.role.RolePageReqVO;
H 13 import com.iailab.module.system.controller.admin.permission.vo.role.RoleSaveReqVO;
14 import com.iailab.module.system.dal.dataobject.permission.RoleDO;
15 import com.iailab.module.system.dal.mysql.permission.RoleMapper;
16 import com.iailab.module.system.dal.redis.RedisKeyConstants;
17 import com.iailab.module.system.enums.permission.DataScopeEnum;
18 import com.iailab.module.system.enums.permission.RoleCodeEnum;
19 import com.iailab.module.system.enums.permission.RoleTypeEnum;
20 import com.google.common.annotations.VisibleForTesting;
21 import com.mzt.logapi.context.LogRecordContext;
22 import com.mzt.logapi.service.impl.DiffParseFunction;
23 import com.mzt.logapi.starter.annotation.LogRecord;
24 import lombok.extern.slf4j.Slf4j;
25 import org.springframework.cache.annotation.CacheEvict;
26 import org.springframework.cache.annotation.Cacheable;
27 import org.springframework.stereotype.Service;
28 import org.springframework.transaction.annotation.Transactional;
29 import org.springframework.util.StringUtils;
30
31 import javax.annotation.Resource;
32 import java.util.*;
33
34 import static com.iailab.framework.common.exception.util.ServiceExceptionUtil.exception;
35 import static com.iailab.framework.common.util.collection.CollectionUtils.convertMap;
36 import static com.iailab.module.system.enums.ErrorCodeConstants.*;
37 import static com.iailab.module.system.enums.LogRecordConstants.*;
38
39 /**
40  * 角色 Service 实现类
41  *
42  * @author iailab
43  */
44 @Service
45 @Slf4j
46 public class RoleServiceImpl implements RoleService {
47
48     @Resource
49     private PermissionService permissionService;
50
51     @Resource
52     private RoleMapper roleMapper;
53
54     @Override
55     @Transactional(rollbackFor = Exception.class)
56     @LogRecord(type = SYSTEM_ROLE_TYPE, subType = SYSTEM_ROLE_CREATE_SUB_TYPE, bizNo = "{{#role.id}}",
57             success = SYSTEM_ROLE_CREATE_SUCCESS)
58     public Long createRole(RoleSaveReqVO createReqVO, Integer type) {
59         // 1. 校验角色
60         validateRoleDuplicate(createReqVO.getName(), createReqVO.getCode(), null);
61
62         // 2. 插入到数据库
63         RoleDO role = BeanUtils.toBean(createReqVO, RoleDO.class)
64                 .setType(ObjectUtil.defaultIfNull(type, RoleTypeEnum.CUSTOM.getType()))
65                 .setStatus(CommonStatusEnum.ENABLE.getStatus())
66                 .setDataScope(DataScopeEnum.ALL.getScope()); // 默认可查看所有数据。原因是,可能一些项目不需要项目权限
67         roleMapper.insert(role);
68
69         // 3. 记录操作日志上下文
70         LogRecordContext.putVariable("role", role);
71         return role.getId();
72     }
73
74     @Override
75     @CacheEvict(value = RedisKeyConstants.ROLE, key = "#updateReqVO.id")
76     @LogRecord(type = SYSTEM_ROLE_TYPE, subType = SYSTEM_ROLE_UPDATE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}",
77             success = SYSTEM_ROLE_UPDATE_SUCCESS)
78     public void updateRole(RoleSaveReqVO updateReqVO) {
79         // 1.1 校验是否可以更新
80         RoleDO role = validateRoleForUpdate(updateReqVO.getId());
81         // 1.2 校验角色的唯一字段是否重复
82         validateRoleDuplicate(updateReqVO.getName(), updateReqVO.getCode(), updateReqVO.getId());
83
84         // 2. 更新到数据库
85         RoleDO updateObj = BeanUtils.toBean(updateReqVO, RoleDO.class);
86         roleMapper.updateById(updateObj);
87
88         // 3. 记录操作日志上下文
89         LogRecordContext.putVariable("role", role);
90     }
91
92     @Override
93     @CacheEvict(value = RedisKeyConstants.ROLE, key = "#id")
94     public void updateRoleDataScope(Long id, Integer dataScope, Set<Long> dataScopeDeptIds) {
95         // 校验是否可以更新
96         validateRoleForUpdate(id);
97
98         // 更新数据范围
99         RoleDO updateObject = new RoleDO();
100         updateObject.setId(id);
101         updateObject.setDataScope(dataScope);
102         updateObject.setDataScopeDeptIds(dataScopeDeptIds);
103         roleMapper.updateById(updateObject);
104     }
105
106     @Override
107     @Transactional(rollbackFor = Exception.class)
108     @CacheEvict(value = RedisKeyConstants.ROLE, key = "#id")
109     @LogRecord(type = SYSTEM_ROLE_TYPE, subType = SYSTEM_ROLE_DELETE_SUB_TYPE, bizNo = "{{#id}}",
110             success = SYSTEM_ROLE_DELETE_SUCCESS)
111     public void deleteRole(Long id) {
112         // 1. 校验是否可以更新
113         RoleDO role = validateRoleForUpdate(id);
114
115         // 2.1 标记删除
116         roleMapper.deleteById(id);
117         // 2.2 删除相关数据
118         permissionService.processRoleDeleted(id);
119
120         // 3. 记录操作日志上下文
121         LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(role, RoleSaveReqVO.class));
122         LogRecordContext.putVariable("role", role);
123     }
124
125     /**
126      * 校验角色的唯一字段是否重复
127      *
128      * 1. 是否存在相同名字的角色
129      * 2. 是否存在相同编码的角色
130      *
131      * @param name 角色名字
132      * @param code 角色额编码
133      * @param id 角色编号
134      */
135     @VisibleForTesting
136     void validateRoleDuplicate(String name, String code, Long id) {
137         // 0. 超级管理员,不允许创建
138         if (RoleCodeEnum.isSuperAdmin(code)) {
139             throw exception(ROLE_ADMIN_CODE_ERROR, code);
140         }
141         // 1. 该 name 名字被其它角色所使用
142         RoleDO role = roleMapper.selectByName(name);
143         if (role != null && !role.getId().equals(id)) {
144             throw exception(ROLE_NAME_DUPLICATE, name);
145         }
146         // 2. 是否存在相同编码的角色
147         if (!StringUtils.hasText(code)) {
148             return;
149         }
150         // 该 code 编码被其它角色所使用
151         role = roleMapper.selectByCode(code);
152         if (role != null && !role.getId().equals(id)) {
153             throw exception(ROLE_CODE_DUPLICATE, code);
154         }
155     }
156
157     /**
158      * 校验角色是否可以被更新
159      *
160      * @param id 角色编号
161      */
162     @VisibleForTesting
163     RoleDO validateRoleForUpdate(Long id) {
164         RoleDO role = roleMapper.selectById(id);
165         if (role == null) {
166             throw exception(ROLE_NOT_EXISTS);
167         }
168         // 内置角色,不允许删除
169         if (RoleTypeEnum.SYSTEM.getType().equals(role.getType())) {
170             throw exception(ROLE_CAN_NOT_UPDATE_SYSTEM_TYPE_ROLE);
171         }
172         return role;
173     }
174
175     @Override
176     public RoleDO getRole(Long id) {
177         return roleMapper.selectById(id);
178     }
179
180     @Override
181     @Cacheable(value = RedisKeyConstants.ROLE, key = "#id",
182             unless = "#result == null")
183     public RoleDO getRoleFromCache(Long id) {
184         return roleMapper.selectById(id);
185     }
186
187
188     @Override
189     public List<RoleDO> getRoleListByStatus(Collection<Integer> statuses) {
190         return roleMapper.selectListByStatus(statuses);
191     }
192
193     @Override
194     public List<RoleDO> getRoleList() {
195         return roleMapper.selectList();
196     }
197
198     @Override
199     public List<RoleDO> getRoleList(Collection<Long> ids) {
200         if (CollectionUtil.isEmpty(ids)) {
201             return Collections.emptyList();
202         }
203         return roleMapper.selectBatchIds(ids);
204     }
205
206     @Override
207     public List<RoleDO> getRoleListFromCache(Collection<Long> ids) {
208         if (CollectionUtil.isEmpty(ids)) {
209             return Collections.emptyList();
210         }
211         // 这里采用 for 循环从缓存中获取,主要考虑 Spring CacheManager 无法批量操作的问题
212         RoleServiceImpl self = getSelf();
213         return CollectionUtils.convertList(ids, self::getRoleFromCache);
214     }
215
216     @Override
217     public PageResult<RoleDO> getRolePage(RolePageReqVO reqVO) {
218         return roleMapper.selectPage(reqVO);
219     }
220
221     @Override
222     public boolean hasAnySuperAdmin(Collection<Long> ids) {
223         if (CollectionUtil.isEmpty(ids)) {
224             return false;
225         }
226         RoleServiceImpl self = getSelf();
227         return ids.stream().anyMatch(id -> {
228             RoleDO role = self.getRoleFromCache(id);
229             return role != null && RoleCodeEnum.isSuperAdmin(role.getCode());
230         });
231     }
232
233     @Override
234     public void validateRoleList(Collection<Long> ids) {
235         if (CollUtil.isEmpty(ids)) {
236             return;
237         }
238         // 获得角色信息
239         List<RoleDO> roles = roleMapper.selectBatchIds(ids);
240         Map<Long, RoleDO> roleMap = convertMap(roles, RoleDO::getId);
241         // 校验
242         ids.forEach(id -> {
243             RoleDO role = roleMap.get(id);
244             if (role == null) {
245                 throw exception(ROLE_NOT_EXISTS);
246             }
247             if (!CommonStatusEnum.ENABLE.getStatus().equals(role.getStatus())) {
248                 throw exception(ROLE_IS_DISABLE, role.getName());
249             }
250         });
251     }
252
d9f9ba 253     @Override
H 254     public RoleDO getRoleByName(String name) {
255         return roleMapper.selectOne(new LambdaQueryWrapperX<RoleDO>().eq(RoleDO::getName, name));
256     }
257
258     @Override
259     public void insert(RoleDO role) {
260         roleMapper.insert(role);
261     }
262
e7c126 263     /**
H 264      * 获得自身的代理对象,解决 AOP 生效问题
265      *
266      * @return 自己
267      */
268     private RoleServiceImpl getSelf() {
269         return SpringUtil.getBean(getClass());
270     }
271
272 }