1. 迁移角色相关逻辑

This commit is contained in:
YunaiV
2020-04-28 09:25:29 +08:00
parent 4e38bf75ca
commit 4e5b6ff2cf
22 changed files with 466 additions and 300 deletions

View File

@@ -1,8 +1,13 @@
package cn.iocoder.mall.system.biz.convert.authorization;
import cn.iocoder.common.framework.vo.PageResult;
import cn.iocoder.mall.system.biz.bo.authorization.RoleBO;
import cn.iocoder.mall.system.biz.dataobject.authorization.RoleDO;
import cn.iocoder.mall.system.biz.dto.authorization.RoleAddDTO;
import cn.iocoder.mall.system.biz.dto.authorization.RoleUpdateDTO;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
import java.util.List;
@@ -16,4 +21,11 @@ public interface RoleConvert {
List<RoleBO> convertList(List<RoleDO> beans);
@Mapping(source = "records", target = "list")
PageResult<RoleBO> convertPage(IPage<RoleDO> page);
RoleDO convert(RoleAddDTO bean);
RoleDO convert(RoleUpdateDTO bean);
}

View File

@@ -16,6 +16,11 @@ public interface ResourceMapper extends BaseMapper<ResourceDO> {
return selectOne(new QueryWrapper<ResourceDO>().eq("permission", permission));
}
default ResourceDO selectByPidAndName(Integer pid, String name) {
return selectOne(new QueryWrapperX<ResourceDO>().eqIfPresent("pid", pid)
.eqIfPresent("name", name));
}
default List<ResourceDO> selectListByPermissions(Collection<String> permissions) {
return selectList(new QueryWrapper<ResourceDO>().in("permission", permissions));
}

View File

@@ -23,4 +23,12 @@ public interface RoleMapper extends BaseMapper<RoleDO> {
new QueryWrapperX<RoleDO>().likeIfPresent("name", rolePageDTO.getName()));
}
default RoleDO selectByName(String name) {
return selectOne(new QueryWrapperX<RoleDO>().eqIfPresent("name", name));
}
default RoleDO selectByCode(String code) {
return selectOne(new QueryWrapperX<RoleDO>().eqIfPresent("code", code));
}
}

View File

@@ -2,13 +2,11 @@ package cn.iocoder.mall.system.biz.dto.authorization;
import cn.iocoder.common.framework.validator.InEnum;
import cn.iocoder.mall.system.biz.enums.authorization.ResourceTypeEnum;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.List;
/**
* 资源模块 - 更新资源 DTO
@@ -20,34 +18,33 @@ public class ResourceUpdateDTO {
@NotNull(message = "管理员编号不能为空")
private Integer adminId;
@ApiModelProperty(value = "资源编号", required = true, example = "1")
@NotNull(message = "资源编号不能为空")
private Integer id;
@ApiModelProperty(value = "资源类型。1 代表【菜单】2 代表【按钮】", required = true, example = "1")
@NotNull(message = "类型不能为空")
@InEnum(value = ResourceTypeEnum.class, message = "资源类型必须是 {value}")
private Integer type;
@ApiModelProperty(value = "排序", required = true, example = "1")
@NotNull(message = "类型不能为空")
private Integer sort;
@ApiModelProperty(value = "菜单展示名", required = true, example = "商品管理")
@NotEmpty(message = "资源名字不能为空")
private String displayName;
private String name;
@ApiModelProperty(value = "父级资源编号", required = true, example = "1")
@NotNull(message = "父级资源编号不能为空")
private Integer pid;
@ApiModelProperty(value = "操作", example = "/order/list")
private String handler;
@ApiModelProperty(value = "图标", example = "add")
/**
* 前端路由
*/
private String route;
/**
* 图标
*/
private String icon;
@ApiModelProperty(value = "权限标识数组", example = "system.order.add,system.order.update")
private List<String> permissions;
/**
* 权限标识
*/
private String permission;
}

View File

@@ -1,7 +1,6 @@
package cn.iocoder.mall.system.biz.dto.authorization;
import cn.iocoder.common.framework.vo.PageParam;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
@@ -14,7 +13,9 @@ import lombok.experimental.Accessors;
@Accessors(chain = true)
public class RolePageDTO extends PageParam {
@ApiModelProperty( value = "角色名,模糊匹配", example = "系统管理员")
/**
* 角色名,模糊匹配
*/
private String name;
}

View File

@@ -0,0 +1,28 @@
package cn.iocoder.mall.system.biz.event.authorization;
import cn.iocoder.mall.system.biz.dataobject.authorization.RoleDO;
import org.springframework.context.ApplicationEvent;
/**
* {@link RoleDO} 删除事件
*/
public class RoleDeleteEvent extends ApplicationEvent {
/**
* 角色编号
*/
private Integer id;
public RoleDeleteEvent(Object source) {
super(source);
}
public RoleDeleteEvent(Object source, Integer id) {
super(source);
this.id = id;
}
public Integer getId() {
return id;
}
}

View File

@@ -124,4 +124,12 @@ public class AuthorizationServiceImpl implements AuthorizationService {
roleResourceMapper.deleteByResourceId(event.getId());
}
@EventListener
public void handleRoleDeleteEvent(ResourceDeleteEvent event) {
// 标记删除 RoleResource
roleResourceMapper.deleteByRoleId(event.getId());
// 标记删除 AdminRole
accountRoleMapper.deleteByRoleId(event.getId());
}
}

View File

@@ -16,6 +16,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import java.util.stream.Collectors;
@@ -77,6 +78,8 @@ public class ResourceServiceImpl implements ResourceService {
public Integer addResource(ResourceAddDTO addDTO) {
// 校验父资源存在
checkParentResource(addDTO.getPid(), null);
// 校验资源(自己)
checkResource(addDTO.getPid(), addDTO.getName(), null);
// 存储到数据库
ResourceDO resource = ResourceConvert.INSTANCE.convert(addDTO);
initResourceProperty(resource);
@@ -92,10 +95,12 @@ public class ResourceServiceImpl implements ResourceService {
public void updateResource(ResourceUpdateDTO updateDTO) {
// 校验更新的资源是否存在
if (resourceMapper.selectById(updateDTO.getId()) == null) {
throw ServiceExceptionUtil.exception(SystemErrorCodeEnum.RESOURCE_NOT_EXISTS.getCode());
throw ServiceExceptionUtil.exception(SystemErrorCodeEnum.RESOURCE_NOT_EXISTS);
}
// 校验父资源存在
checkParentResource(updateDTO.getPid(), updateDTO.getId());
// 校验资源(自己)
checkResource(updateDTO.getPid(), updateDTO.getName(), updateDTO.getId());
// 更新到数据库
ResourceDO resource = ResourceConvert.INSTANCE.convert(updateDTO);
initResourceProperty(resource);
@@ -104,24 +109,29 @@ public class ResourceServiceImpl implements ResourceService {
}
@Override
@Transactional
public void deleteResource(ResourceDeleteDTO deleteDTO) {
// 校验更新的资源是否存在
if (resourceMapper.selectById(deleteDTO.getId()) == null) {
throw ServiceExceptionUtil.exception(SystemErrorCodeEnum.RESOURCE_NOT_EXISTS.getCode());
throw ServiceExceptionUtil.exception(SystemErrorCodeEnum.RESOURCE_NOT_EXISTS);
}
// 校验是否还有子资源
if (resourceMapper.selectCountByPid(deleteDTO.getId()) > 0) {
throw ServiceExceptionUtil.exception(SystemErrorCodeEnum.RESOURCE_EXISTS_CHILDREN.getCode());
throw ServiceExceptionUtil.exception(SystemErrorCodeEnum.RESOURCE_EXISTS_CHILDREN);
}
// 更新到数据库
resourceMapper.deleteById(deleteDTO.getId());
// 删除资源关联表
// 发布资源删除事件,方便清理关联表
eventPublisher.publishEvent(new ResourceDeleteEvent(this, deleteDTO.getId()));
}
/**
* 校验父资源是否合法
*
* 1. 不能舌质红自己为父资源
* 2. 父资源不存在
* 3. 父资源必须是 {@link ResourceTypeEnum#MENU} 菜单类型
*
* @param pid 父资源编号
* @param childId 当前资源编号
*/
@@ -130,14 +140,37 @@ public class ResourceServiceImpl implements ResourceService {
return;
}
if (pid.equals(childId)) { // 不能设置自己为父资源
throw ServiceExceptionUtil.exception(SystemErrorCodeEnum.RESOURCE_PARENT_ERROR.getCode());
throw ServiceExceptionUtil.exception(SystemErrorCodeEnum.RESOURCE_PARENT_ERROR);
}
ResourceDO resource = resourceMapper.selectById(pid);
if (resource == null) { // 父资源不存在
throw ServiceExceptionUtil.exception(SystemErrorCodeEnum.RESOURCE_PARENT_NOT_EXISTS.getCode());
throw ServiceExceptionUtil.exception(SystemErrorCodeEnum.RESOURCE_PARENT_NOT_EXISTS);
}
if (!ResourceTypeEnum.MENU.getType().equals(resource.getType())) { // 父资源必须是菜单类型
throw ServiceExceptionUtil.exception(SystemErrorCodeEnum.RESOURCE_PARENT_NOT_MENU.getCode());
throw ServiceExceptionUtil.exception(SystemErrorCodeEnum.RESOURCE_PARENT_NOT_MENU);
}
}
/**
* 校验资源是否合法
*
* 1. 校验相同父资源编号下,是否存在相同的资源名
*
* @param name 资源名字
* @param pid 父资源编号
* @param id 资源编号
*/
private void checkResource(Integer pid, String name, Integer id) {
ResourceDO resource = resourceMapper.selectByPidAndName(pid, name);
if (resource == null) {
return;
}
// 如果 id 为空,说明不用比较是否为相同 id 的资源
if (id == null) {
throw ServiceExceptionUtil.exception(SystemErrorCodeEnum.RESOURCE_NAME_DUPLICATE);
}
if (!resource.getId().equals(id)) {
throw ServiceExceptionUtil.exception(SystemErrorCodeEnum.RESOURCE_NAME_DUPLICATE);
}
}
@@ -149,10 +182,6 @@ public class ResourceServiceImpl implements ResourceService {
* @param resource 资源
*/
private void initResourceProperty(ResourceDO resource) {
// 初始化根节点的情况
if (resource.getPid() == null) {
resource.setPid(ResourceIdEnum.ROOT.getId());
}
// 初始化资源为按钮类型时,无需 route 和 icon 属性
if (ResourceTypeEnum.BUTTON.getType().equals(resource.getType())) {
resource.setRoute(null);

View File

@@ -1,14 +1,24 @@
package cn.iocoder.mall.system.biz.service.authorization;
import cn.iocoder.common.framework.vo.PageResult;
import cn.iocoder.mall.system.biz.bo.authorization.RoleBO;
import cn.iocoder.mall.system.biz.dto.authorization.RoleAddDTO;
import cn.iocoder.mall.system.biz.dto.authorization.RoleDeleteDTO;
import cn.iocoder.mall.system.biz.dto.authorization.RolePageDTO;
import cn.iocoder.mall.system.biz.dto.authorization.RoleUpdateDTO;
import java.util.Collection;
import java.util.List;
/**
* 角色模块 - Service 接口
*/
public interface RoleService {
List<RoleBO> getRoleList(Collection<Integer> ids);
PageResult<RoleBO> getRolePage(RolePageDTO pageDTO);
/**
* 判断指定角色是否包含超级管理员角色
*
@@ -17,4 +27,10 @@ public interface RoleService {
*/
boolean hasSuperAdmin(Collection<Integer> ids);
Integer addRole(RoleAddDTO roleAddDTO);
void updateRole(RoleUpdateDTO roleUpdateDTO);
void deleteRole(RoleDeleteDTO roleDeleteDTO);
}

View File

@@ -1,19 +1,36 @@
package cn.iocoder.mall.system.biz.service.authorization;
import cn.iocoder.common.framework.util.ServiceExceptionUtil;
import cn.iocoder.common.framework.util.StringUtil;
import cn.iocoder.common.framework.vo.PageResult;
import cn.iocoder.mall.mybatis.enums.DeletedStatusEnum;
import cn.iocoder.mall.system.biz.bo.authorization.RoleBO;
import cn.iocoder.mall.system.biz.convert.authorization.RoleConvert;
import cn.iocoder.mall.system.biz.dao.authorization.RoleMapper;
import cn.iocoder.mall.system.biz.dataobject.authorization.RoleDO;
import cn.iocoder.mall.system.biz.dto.authorization.RoleAddDTO;
import cn.iocoder.mall.system.biz.dto.authorization.RoleDeleteDTO;
import cn.iocoder.mall.system.biz.dto.authorization.RolePageDTO;
import cn.iocoder.mall.system.biz.dto.authorization.RoleUpdateDTO;
import cn.iocoder.mall.system.biz.enums.SystemErrorCodeEnum;
import cn.iocoder.mall.system.biz.enums.authorization.RoleCodeEnum;
import cn.iocoder.mall.system.biz.event.authorization.ResourceDeleteEvent;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Collection;
import java.util.Date;
import java.util.List;
@Service
public class RoleServiceImpl implements RoleService {
@Autowired
private ApplicationEventPublisher eventPublisher;
@Autowired
private RoleMapper roleMapper;
@@ -23,6 +40,12 @@ public class RoleServiceImpl implements RoleService {
return RoleConvert.INSTANCE.convertList(roleDOs);
}
@Override
public PageResult<RoleBO> getRolePage(RolePageDTO pageDTO) {
IPage<RoleDO> pageResult = roleMapper.selectPage(pageDTO);
return RoleConvert.INSTANCE.convertPage(pageResult);
}
@Override
public boolean hasSuperAdmin(Collection<Integer> ids) {
List<RoleDO> roleDOs = roleMapper.selectBatchIds(ids);
@@ -34,4 +57,84 @@ public class RoleServiceImpl implements RoleService {
return false;
}
@Override
public Integer addRole(RoleAddDTO roleAddDTO) {
// 校验角色
checkRole(roleAddDTO.getName(), roleAddDTO.getCode(), null);
// 保存到数据库
RoleDO role = RoleConvert.INSTANCE.convert(roleAddDTO);
role.setCreateTime(new Date());
role.setDeleted(DeletedStatusEnum.DELETED_NO.getValue());
roleMapper.insert(role);
// TODO 插入操作日志
// 返回成功
return role.getId();
}
@Override
public void updateRole(RoleUpdateDTO roleUpdateDTO) {
// 校验角色是否存在
if (roleMapper.selectById(roleUpdateDTO.getId()) == null) {
throw ServiceExceptionUtil.exception(SystemErrorCodeEnum.ROLE_NOT_EXISTS);
}
// 校验角色
checkRole(roleUpdateDTO.getName(), roleUpdateDTO.getCode(), roleUpdateDTO.getId());
// 更新到数据库
RoleDO roleDO = RoleConvert.INSTANCE.convert(roleUpdateDTO);
roleMapper.updateById(roleDO);
// TODO 插入操作日志
}
@Override
@Transactional
public void deleteRole(RoleDeleteDTO roleDeleteDTO) {
// 校验角色是否存在
if (roleMapper.selectById(roleDeleteDTO.getId()) == null) {
throw ServiceExceptionUtil.exception(SystemErrorCodeEnum.ROLE_NOT_EXISTS);
}
// 更新到数据库,标记删除
roleMapper.deleteById(roleDeleteDTO.getId());
// TODO 插入操作日志
// 发布角色删除事件,方便清理关联表
eventPublisher.publishEvent(new ResourceDeleteEvent(this, roleDeleteDTO.getId()));
}
/**
* 校验角色是否合法
*
* 1. 是否存在相同名字的角色
* 2. 是否存在相同编码的角色
*
* @param name 角色名字
* @param code 角色额编码
* @param id 角色编号
*/
private void checkRole(String name, String code, Integer id) {
// 1. 是否存在相同名字的角色
RoleDO role = roleMapper.selectByName(name);
if (role != null) {
// 如果 id 为空,说明不用比较是否为相同 id 的资源
if (id == null) {
throw ServiceExceptionUtil.exception(SystemErrorCodeEnum.ROLE_NAME_DUPLICATE, name);
}
if (!role.getId().equals(id)) {
throw ServiceExceptionUtil.exception(SystemErrorCodeEnum.ROLE_NAME_DUPLICATE, name);
}
}
// 2. 是否存在相同编码的角色
if (!StringUtil.hasText(code)) {
return;
}
role = roleMapper.selectByCode(code);
if (role != null) {
// 如果 id 为空,说明不用比较是否为相同 id 的资源
if (id == null) {
throw ServiceExceptionUtil.exception(SystemErrorCodeEnum.ROLE_CODE_DUPLICATE, name);
}
if (!role.getId().equals(id)) {
throw ServiceExceptionUtil.exception(SystemErrorCodeEnum.ROLE_CODE_DUPLICATE, name);
}
}
}
}