角色模块的 CRUD + 分配资源

This commit is contained in:
YunaiV 2019-03-01 19:03:13 +08:00
parent 814ca633aa
commit 16d33b25be
26 changed files with 824 additions and 85 deletions

View File

@ -1,22 +1,72 @@
package cn.iocoder.mall.admin.application.controller; package cn.iocoder.mall.admin.application.controller;
import cn.iocoder.common.framework.vo.CommonResult; import cn.iocoder.common.framework.vo.CommonResult;
import cn.iocoder.mall.admin.api.ResourceService;
import cn.iocoder.mall.admin.api.bo.ResourceBO;
import cn.iocoder.mall.admin.api.constant.ResourceConstants;
import cn.iocoder.mall.admin.application.convert.ResourceConvert;
import cn.iocoder.mall.admin.application.vo.AdminMenuTreeNodeVO;
import cn.iocoder.mall.admin.sdk.context.AdminSecurityContextHolder; import cn.iocoder.mall.admin.sdk.context.AdminSecurityContextHolder;
import cn.iocoder.mall.admin.application.convert.AdminConvert; import cn.iocoder.mall.admin.application.convert.AdminConvert;
import cn.iocoder.mall.admin.application.vo.AdminInfoVO; import cn.iocoder.mall.admin.application.vo.AdminInfoVO;
import com.alibaba.dubbo.config.annotation.Reference;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import java.util.*;
import java.util.stream.Collectors;
@RestController @RestController
@RequestMapping("admin/admin") @RequestMapping("admin/admin")
@Api("管理员模块") @Api("管理员模块")
public class AdminController { public class AdminController {
@Reference(validation = "true")
private ResourceService resourceService;
@GetMapping("/info") @GetMapping("/info")
public CommonResult<AdminInfoVO> info() { public CommonResult<AdminInfoVO> info() {
return CommonResult.success(AdminConvert.INSTANCE.convert(AdminSecurityContextHolder.getContext())); return CommonResult.success(AdminConvert.INSTANCE.convert(AdminSecurityContextHolder.getContext()));
} }
// =========== 当前管理员相关的资源 API ===========
@SuppressWarnings("Duplicates")
@GetMapping("/menu_resource_tree")
@ApiOperation(value = "获得当前登陆的管理员拥有的菜单权限", notes = "以树结构返回")
public CommonResult<List<AdminMenuTreeNodeVO>> menuResourceTree() {
List<ResourceBO> resources = resourceService.getResourcesByTypeAndRoleIds(ResourceConstants.TYPE_MENU, AdminSecurityContextHolder.getContext().getRoleIds());
// 创建 AdminMenuTreeNodeVO Map
Map<Integer, AdminMenuTreeNodeVO> treeNodeMap = resources.stream().collect(Collectors.toMap(ResourceBO::getId, ResourceConvert.INSTANCE::convert));
// 处理父子关系
treeNodeMap.values().stream()
.filter(node -> !node.getPid().equals(ResourceConstants.PID_ROOT))
.forEach((childNode) -> {
// 获得父节点
AdminMenuTreeNodeVO parentNode = treeNodeMap.get(childNode.getPid());
if (parentNode.getChildren() == null) { // 初始化 children 数组
parentNode.setChildren(new ArrayList<>());
}
// 将自己添加到父节点中
parentNode.getChildren().add(childNode);
});
// 获得到所有的根节点
List<AdminMenuTreeNodeVO> rootNodes = treeNodeMap.values().stream()
.filter(node -> node.getPid().equals(ResourceConstants.PID_ROOT))
.sorted(Comparator.comparing(AdminMenuTreeNodeVO::getSort))
.collect(Collectors.toList());
return CommonResult.success(rootNodes);
}
@GetMapping("/url_resource_list")
@ApiOperation(value = "获得当前登陆的管理员拥有的 URL 权限列表")
// @ApiModelProperty(value = "data", example = "['/admin/role/add', '/admin/role/update']") 没效果
public CommonResult<Set<String>> urlResourceList() {
List<ResourceBO> resources = resourceService.getResourcesByTypeAndRoleIds(ResourceConstants.TYPE_URL, AdminSecurityContextHolder.getContext().getRoleIds());
return CommonResult.success(resources.stream().map(ResourceBO::getHandler).collect(Collectors.toSet()));
}
} }

View File

@ -7,7 +7,6 @@ import cn.iocoder.mall.admin.api.constant.ResourceConstants;
import cn.iocoder.mall.admin.api.dto.ResourceAddDTO; import cn.iocoder.mall.admin.api.dto.ResourceAddDTO;
import cn.iocoder.mall.admin.api.dto.ResourceUpdateDTO; import cn.iocoder.mall.admin.api.dto.ResourceUpdateDTO;
import cn.iocoder.mall.admin.application.convert.ResourceConvert; import cn.iocoder.mall.admin.application.convert.ResourceConvert;
import cn.iocoder.mall.admin.application.vo.AdminMenuTreeNodeVO;
import cn.iocoder.mall.admin.application.vo.ResourceTreeNodeVO; import cn.iocoder.mall.admin.application.vo.ResourceTreeNodeVO;
import cn.iocoder.mall.admin.application.vo.ResourceVO; import cn.iocoder.mall.admin.application.vo.ResourceVO;
import cn.iocoder.mall.admin.sdk.context.AdminSecurityContextHolder; import cn.iocoder.mall.admin.sdk.context.AdminSecurityContextHolder;
@ -18,7 +17,10 @@ import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.util.*; import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@RestController @RestController
@ -29,43 +31,6 @@ public class ResourceController {
@Reference(validation = "true") @Reference(validation = "true")
private ResourceService resourceService; private ResourceService resourceService;
// =========== 当前管理员相关的资源 API ===========
@SuppressWarnings("Duplicates")
@GetMapping("/admin_menu_tree")
@ApiOperation(value = "获得当前登陆的管理员拥有的菜单权限", notes = "以树结构返回")
public CommonResult<List<AdminMenuTreeNodeVO>> adminMenuTree() {
List<ResourceBO> resources = resourceService.getResourcesByTypeAndRoleIds(ResourceConstants.TYPE_MENU, AdminSecurityContextHolder.getContext().getRoleIds());
// 创建 AdminMenuTreeNodeVO Map
Map<Integer, AdminMenuTreeNodeVO> treeNodeMap = resources.stream().collect(Collectors.toMap(ResourceBO::getId, ResourceConvert.INSTANCE::convert));
// 处理父子关系
treeNodeMap.values().stream()
.filter(node -> !node.getPid().equals(ResourceConstants.PID_ROOT))
.forEach((childNode) -> {
// 获得父节点
AdminMenuTreeNodeVO parentNode = treeNodeMap.get(childNode.getPid());
if (parentNode.getChildren() == null) { // 初始化 children 数组
parentNode.setChildren(new ArrayList<>());
}
// 将自己添加到父节点中
parentNode.getChildren().add(childNode);
});
// 获得到所有的根节点
List<AdminMenuTreeNodeVO> rootNodes = treeNodeMap.values().stream()
.filter(node -> node.getPid().equals(ResourceConstants.PID_ROOT))
.sorted(Comparator.comparing(AdminMenuTreeNodeVO::getSort))
.collect(Collectors.toList());
return CommonResult.success(rootNodes);
}
@GetMapping("/admin_url_list")
@ApiOperation(value = "获得当前登陆的管理员拥有的 URL 权限列表")
// @ApiModelProperty(value = "data", example = "['/admin/role/add', '/admin/role/update']") 没效果
public CommonResult<Set<String>> adminUrlList() {
List<ResourceBO> resources = resourceService.getResourcesByTypeAndRoleIds(ResourceConstants.TYPE_URL, AdminSecurityContextHolder.getContext().getRoleIds());
return CommonResult.success(resources.stream().map(ResourceBO::getHandler).collect(Collectors.toSet()));
}
// =========== 资源管理 API =========== // =========== 资源管理 API ===========
@SuppressWarnings("Duplicates") @SuppressWarnings("Duplicates")

View File

@ -0,0 +1,116 @@
package cn.iocoder.mall.admin.application.controller;
import cn.iocoder.common.framework.vo.CommonResult;
import cn.iocoder.mall.admin.api.ResourceService;
import cn.iocoder.mall.admin.api.RoleService;
import cn.iocoder.mall.admin.api.bo.ResourceBO;
import cn.iocoder.mall.admin.api.bo.RolePageBO;
import cn.iocoder.mall.admin.api.constant.ResourceConstants;
import cn.iocoder.mall.admin.api.dto.RoleAddDTO;
import cn.iocoder.mall.admin.api.dto.RolePageDTO;
import cn.iocoder.mall.admin.api.dto.RoleUpdateDTO;
import cn.iocoder.mall.admin.application.convert.ResourceConvert;
import cn.iocoder.mall.admin.application.convert.RoleConvert;
import cn.iocoder.mall.admin.application.vo.RolePageVO;
import cn.iocoder.mall.admin.application.vo.RoleResourceTreeNodeVO;
import cn.iocoder.mall.admin.application.vo.RoleVO;
import cn.iocoder.mall.admin.sdk.context.AdminSecurityContextHolder;
import com.alibaba.dubbo.config.annotation.Reference;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;
import java.util.*;
import java.util.stream.Collectors;
@RestController
@RequestMapping("admin/role")
public class RoleController {
@Reference(validation = "true")
private RoleService roleService;
@Reference(validation = "true")
private ResourceService resourceService;
@GetMapping("/page")
@ApiOperation(value = "角色分页")
public CommonResult<RolePageVO> page(@RequestParam(value = "name", required = false) String name,
@RequestParam(value = "pageNo", defaultValue = "0") Integer pageNo,
@RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize) {
CommonResult<RolePageBO> result = roleService.getRolePage(new RolePageDTO().setName(name).setPageNo(pageNo).setPageSize(pageSize));
return RoleConvert.INSTANCE.convert2(result);
}
@PostMapping("/add")
@ApiOperation(value = "创建角色")
@ApiImplicitParams({
@ApiImplicitParam(name = "name", value = "角色", required = true, example = "系统管理员"),
})
public CommonResult<RoleVO> add(@RequestParam("name") String name) {
RoleAddDTO roleAddDTO = new RoleAddDTO().setName(name);
return RoleConvert.INSTANCE.convert(roleService.addRole(AdminSecurityContextHolder.getContext().getAdminId(), roleAddDTO));
}
@PostMapping("/update")
@ApiOperation(value = "更新角色")
@ApiImplicitParams({
@ApiImplicitParam(name = "id", value = "角色编号", required = true, example = "1"),
@ApiImplicitParam(name = "name", value = "角色名", required = true, example = "系统管理员"),
})
public CommonResult<Boolean> update(@RequestParam("id") Integer id,
@RequestParam("name") String name) {
RoleUpdateDTO roleUpdateDTO = new RoleUpdateDTO().setId(id).setName(name);
return roleService.updateRole(AdminSecurityContextHolder.getContext().getAdminId(), roleUpdateDTO);
}
@PostMapping("/delete")
@ApiOperation(value = "删除角色")
@ApiImplicitParam(name = "id", value = "角色编号", required = true, example = "1")
public CommonResult<Boolean> delete(@RequestParam("id") Integer id) {
return roleService.deleteRole(AdminSecurityContextHolder.getContext().getAdminId(), id);
}
@SuppressWarnings("Duplicates")
@GetMapping("/resource_tree")
@ApiOperation(value = "获得角色拥有的菜单权限", notes = "以树结构返回")
@ApiImplicitParam(name = "id", value = "角色编号", required = true, example = "1")
public CommonResult<List<RoleResourceTreeNodeVO>> resourceTree(@RequestParam("id") Integer id) {
// 芋艿此处严格来说可以在校验下角色是否存在不过呢校验了也没啥意义因为一般不存在这个情况且不会有业务上的影响并且反倒多了一次 rpc 调用
Set<Integer> roleIds = new HashSet<>();
roleIds.add(id);
List<ResourceBO> resources = resourceService.getResourcesByTypeAndRoleIds(null, roleIds);
// 创建 AdminMenuTreeNodeVO Map
Map<Integer, RoleResourceTreeNodeVO> treeNodeMap = resources.stream().collect(Collectors.toMap(ResourceBO::getId, ResourceConvert.INSTANCE::convert4));
// 处理父子关系
treeNodeMap.values().stream()
.filter(node -> !node.getPid().equals(ResourceConstants.PID_ROOT))
.forEach((childNode) -> {
// 获得父节点
RoleResourceTreeNodeVO parentNode = treeNodeMap.get(childNode.getPid());
if (parentNode.getChildren() == null) { // 初始化 children 数组
parentNode.setChildren(new ArrayList<>());
}
// 将自己添加到父节点中
parentNode.getChildren().add(childNode);
});
// 获得到所有的根节点
List<RoleResourceTreeNodeVO> rootNodes = treeNodeMap.values().stream()
.filter(node -> node.getPid().equals(ResourceConstants.PID_ROOT))
.sorted(Comparator.comparing(RoleResourceTreeNodeVO::getSort))
.collect(Collectors.toList());
return CommonResult.success(rootNodes);
}
@PostMapping("/assign_resource")
@ApiOperation(value = "分配角色资源")
@ApiImplicitParams({
@ApiImplicitParam(name = "id", value = "角色编号", required = true, example = "1"),
@ApiImplicitParam(name = "resourceIds", value = "资源数组", required = true, example = "1,2,3"),
})
public CommonResult<Boolean> assignResource(@RequestParam("id") Integer id,
@RequestParam(value = "resourceIds", required = false) Set<Integer> resourceIds) {
return roleService.assignResource(AdminSecurityContextHolder.getContext().getAdminId(), id, resourceIds);
}
}

View File

@ -5,6 +5,7 @@ import cn.iocoder.mall.admin.api.bo.ResourceBO;
import cn.iocoder.mall.admin.application.vo.AdminMenuTreeNodeVO; import cn.iocoder.mall.admin.application.vo.AdminMenuTreeNodeVO;
import cn.iocoder.mall.admin.application.vo.ResourceTreeNodeVO; import cn.iocoder.mall.admin.application.vo.ResourceTreeNodeVO;
import cn.iocoder.mall.admin.application.vo.ResourceVO; import cn.iocoder.mall.admin.application.vo.ResourceVO;
import cn.iocoder.mall.admin.application.vo.RoleResourceTreeNodeVO;
import org.mapstruct.Mapper; import org.mapstruct.Mapper;
import org.mapstruct.Mappings; import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers; import org.mapstruct.factory.Mappers;
@ -20,6 +21,9 @@ public interface ResourceConvert {
@Mappings({}) @Mappings({})
ResourceTreeNodeVO convert2(ResourceBO resourceBO); ResourceTreeNodeVO convert2(ResourceBO resourceBO);
@Mappings({})
RoleResourceTreeNodeVO convert4(ResourceBO resourceBO);
@Mappings({}) @Mappings({})
ResourceVO convert3(ResourceBO resourceBO); ResourceVO convert3(ResourceBO resourceBO);

View File

@ -0,0 +1,26 @@
package cn.iocoder.mall.admin.application.convert;
import cn.iocoder.common.framework.vo.CommonResult;
import cn.iocoder.mall.admin.api.bo.RoleBO;
import cn.iocoder.mall.admin.api.bo.RolePageBO;
import cn.iocoder.mall.admin.application.vo.RolePageVO;
import cn.iocoder.mall.admin.application.vo.RoleVO;
import org.mapstruct.Mapper;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
@Mapper
public interface RoleConvert {
RoleConvert INSTANCE = Mappers.getMapper(RoleConvert.class);
@Mappings({})
RoleVO convert(RoleBO roleBO);
@Mappings({})
CommonResult<RoleVO> convert(CommonResult<RoleBO> resourceBO);
@Mappings({})
CommonResult<RolePageVO> convert2(CommonResult<RolePageBO> resourceBO);
}

View File

@ -0,0 +1,34 @@
package cn.iocoder.mall.admin.application.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.util.List;
@ApiModel("角色分页 VO")
public class RolePageVO {
@ApiModelProperty(value = "角色数组")
private List<RoleVO> roles;
@ApiModelProperty(value = "角色总数")
private Integer count;
public List<RoleVO> getRoles() {
return roles;
}
public RolePageVO setRoles(List<RoleVO> roles) {
this.roles = roles;
return this;
}
public Integer getCount() {
return count;
}
public RolePageVO setCount(Integer count) {
this.count = count;
return this;
}
}

View File

@ -0,0 +1,80 @@
package cn.iocoder.mall.admin.application.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.util.List;
@ApiModel("角色拥有的资源 VO")
public class RoleResourceTreeNodeVO {
@ApiModelProperty(value = "菜单编号", required = true, example = "1")
private Integer id;
// @ApiModelProperty(value = "菜单名", required = true, example = "商品管理")
// private String name;
@ApiModelProperty(value = "菜单操作", required = true, example = "/order/list")
private String handler;
@ApiModelProperty(value = "父菜单编号", required = true, example = "1", notes = "如果无父菜单,则值为 0")
private Integer pid;
@ApiModelProperty(value = "排序", required = true, example = "1")
private Integer sort;
@ApiModelProperty(value = "菜单展示名", required = true, example = "商品管理")
private String displayName;
@ApiModelProperty(value = "子节点数组")
private List<RoleResourceTreeNodeVO> children;
public Integer getId() {
return id;
}
public RoleResourceTreeNodeVO setId(Integer id) {
this.id = id;
return this;
}
public String getHandler() {
return handler;
}
public RoleResourceTreeNodeVO setHandler(String handler) {
this.handler = handler;
return this;
}
public Integer getPid() {
return pid;
}
public RoleResourceTreeNodeVO setPid(Integer pid) {
this.pid = pid;
return this;
}
public Integer getSort() {
return sort;
}
public RoleResourceTreeNodeVO setSort(Integer sort) {
this.sort = sort;
return this;
}
public String getDisplayName() {
return displayName;
}
public RoleResourceTreeNodeVO setDisplayName(String displayName) {
this.displayName = displayName;
return this;
}
public List<RoleResourceTreeNodeVO> getChildren() {
return children;
}
public RoleResourceTreeNodeVO setChildren(List<RoleResourceTreeNodeVO> children) {
this.children = children;
return this;
}
}

View File

@ -0,0 +1,45 @@
package cn.iocoder.mall.admin.application.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.util.Date;
@ApiModel("角色 VO")
public class RoleVO {
@ApiModelProperty(value = "角色编号", required = true, example = "1")
private Integer id;
@ApiModelProperty(value = "角色名字", required = true, example = "系统管理员")
private String name;
@ApiModelProperty(value = "创建时间", required = true, example = "时间戳格式")
private Date createTime;
public Integer getId() {
return id;
}
public RoleVO setId(Integer id) {
this.id = id;
return this;
}
public String getName() {
return name;
}
public RoleVO setName(String name) {
this.name = name;
return this;
}
public Date getCreateTime() {
return createTime;
}
public RoleVO setCreateTime(Date createTime) {
this.createTime = createTime;
return this;
}
}

View File

@ -14,11 +14,11 @@ public interface ResourceService {
/** /**
* 查询指定类型 + 指定角色的资源列表 * 查询指定类型 + 指定角色的资源列表
* *
* @param type 指定类型 * @param type 指定类型可以为空此时不作为过滤条件
* @param roleIds 指定角色的数组 * @param roleIds 指定角色的数组
* @return 资源列表 * @return 资源列表
*/ */
List<ResourceBO> getResourcesByTypeAndRoleIds(Integer type, Set<Integer> roleIds); List<ResourceBO> getResourcesByTypeAndRoleIds(@Nullable Integer type, Set<Integer> roleIds);
/** /**
* 查询指定类型的资源列表 * 查询指定类型的资源列表

View File

@ -1,4 +1,24 @@
package cn.iocoder.mall.admin.api; package cn.iocoder.mall.admin.api;
import cn.iocoder.common.framework.vo.CommonResult;
import cn.iocoder.mall.admin.api.bo.RoleBO;
import cn.iocoder.mall.admin.api.bo.RolePageBO;
import cn.iocoder.mall.admin.api.dto.RoleAddDTO;
import cn.iocoder.mall.admin.api.dto.RolePageDTO;
import cn.iocoder.mall.admin.api.dto.RoleUpdateDTO;
import java.util.Set;
public interface RoleService { public interface RoleService {
}
CommonResult<RolePageBO> getRolePage(RolePageDTO rolePageDTO);
CommonResult<RoleBO> addRole(Integer adminId, RoleAddDTO roleAddDTO);
CommonResult<Boolean> updateRole(Integer adminId, RoleUpdateDTO roleUpdateDTO);
CommonResult<Boolean> deleteRole(Integer adminId, Integer roleId);
CommonResult<Boolean> assignResource(Integer adminId, Integer roleId, Set<Integer> resourceIds);
}

View File

@ -0,0 +1,50 @@
package cn.iocoder.mall.admin.api.bo;
import java.util.Date;
/**
* 角色 BO
*/
public class RoleBO {
/**
* 角色编号
*/
private Integer id;
/**
* 角色名字
*/
private String name;
/**
* 添加时间
*/
private Date createTime;
public Integer getId() {
return id;
}
public RoleBO setId(Integer id) {
this.id = id;
return this;
}
public String getName() {
return name;
}
public RoleBO setName(String name) {
this.name = name;
return this;
}
public Date getCreateTime() {
return createTime;
}
public RoleBO setCreateTime(Date createTime) {
this.createTime = createTime;
return this;
}
}

View File

@ -0,0 +1,34 @@
package cn.iocoder.mall.admin.api.bo;
import java.util.List;
public class RolePageBO {
/**
* 角色数组
*/
private List<RoleBO> roles;
/**
* 总量
*/
private Integer count;
public List<RoleBO> getRoles() {
return roles;
}
public RolePageBO setRoles(List<RoleBO> roles) {
this.roles = roles;
return this;
}
public Integer getCount() {
return count;
}
public RolePageBO setCount(Integer count) {
this.count = count;
return this;
}
}

View File

@ -31,6 +31,10 @@ public enum AdminErrorCodeEnum {
RESOURCE_PARENT_ERROR(1002003002, "不能设置自己为父资源"), RESOURCE_PARENT_ERROR(1002003002, "不能设置自己为父资源"),
RESOURCE_NOT_EXISTS(1002003003, "资源不存在"), RESOURCE_NOT_EXISTS(1002003003, "资源不存在"),
RESOURCE_EXISTS_CHILDREN(1002003004, "存在子资源,无法删除"), RESOURCE_EXISTS_CHILDREN(1002003004, "存在子资源,无法删除"),
// ========== 角色模块 1002004000 ==========
ROLE_NOT_EXISTS(1002004000, "角色不存在"),
ROLE_ASSIGN_RESOURCE_NOT_EXISTS(1002004001, "分配角色资源时,有资源不存在"),
; ;
private final int code; private final int code;

View File

@ -0,0 +1,25 @@
package cn.iocoder.mall.admin.api.dto;
import javax.validation.constraints.NotEmpty;
/**
* 角色添加 DTO
*/
public class RoleAddDTO {
/**
* 角色名字标识
*/
@NotEmpty(message = "角色名字不能为空")
private String name;
public String getName() {
return name;
}
public RoleAddDTO setName(String name) {
this.name = name;
return this;
}
}

View File

@ -0,0 +1,35 @@
package cn.iocoder.mall.admin.api.dto;
public class RolePageDTO {
private Integer pageNo;
private Integer pageSize;
private String name;
public Integer getPageNo() {
return pageNo;
}
public RolePageDTO setPageNo(Integer pageNo) {
this.pageNo = pageNo;
return this;
}
public Integer getPageSize() {
return pageSize;
}
public RolePageDTO setPageSize(Integer pageSize) {
this.pageSize = pageSize;
return this;
}
public String getName() {
return name;
}
public RolePageDTO setName(String name) {
this.name = name;
return this;
}
}

View File

@ -0,0 +1,40 @@
package cn.iocoder.mall.admin.api.dto;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
/**
* 角色添加 DTO
*/
public class RoleUpdateDTO {
/**
* 角色编号
*/
@NotNull(message = "角色编号不能为空")
private Integer id;
/**
* 角色名字标识
*/
@NotEmpty(message = "角色名字不能为空")
private String name;
public Integer getId() {
return id;
}
public RoleUpdateDTO setId(Integer id) {
this.id = id;
return this;
}
public String getName() {
return name;
}
public RoleUpdateDTO setName(String name) {
this.name = name;
return this;
}
}

View File

@ -0,0 +1,30 @@
package cn.iocoder.mall.admin.convert;
import cn.iocoder.mall.admin.api.bo.RoleBO;
import cn.iocoder.mall.admin.api.dto.RoleAddDTO;
import cn.iocoder.mall.admin.api.dto.RoleUpdateDTO;
import cn.iocoder.mall.admin.dataobject.RoleDO;
import org.mapstruct.Mapper;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
import java.util.List;
@Mapper
public interface RoleConvert {
RoleConvert INSTANCE = Mappers.getMapper(RoleConvert.class);
@Mappings({})
RoleDO convert(RoleAddDTO roleAddDTO);
@Mappings({})
RoleDO convert(RoleUpdateDTO roleUpdateDTO);
@Mappings({})
RoleBO convert(RoleDO roleDO);
@Mappings({})
List<RoleBO> convert(List<RoleDO> roleDOs);
}

View File

@ -22,6 +22,8 @@ public interface ResourceMapper {
ResourceDO selectById(@Param("id") Integer id); ResourceDO selectById(@Param("id") Integer id);
List<ResourceDO> selectListByIds(@Param("ids") Set<Integer> ids);
void insert(ResourceDO resource); void insert(ResourceDO resource);
int update(ResourceDO resource); int update(ResourceDO resource);

View File

@ -0,0 +1,24 @@
package cn.iocoder.mall.admin.dao;
import cn.iocoder.mall.admin.dataobject.RoleDO;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface RoleMapper {
void insert(RoleDO roleDO);
int update(RoleDO roleDO);
RoleDO selectById(@Param("id") Integer id);
List<RoleDO> selectListByNameLike(@Param("name") String name,
@Param("offset") Integer offset,
@Param("limit") Integer limit);
Integer selectCountByNameLike(@Param("name") String name);
}

View File

@ -9,6 +9,8 @@ import java.util.List;
@Repository @Repository
public interface RoleResourceMapper { public interface RoleResourceMapper {
int insertList(@Param("roleResources") List<RoleResourceDO> resourceDOs);
List<RoleResourceDO> selectByResourceHandler(@Param("resourceHandler") String resourceHandler); List<RoleResourceDO> selectByResourceHandler(@Param("resourceHandler") String resourceHandler);
List<RoleResourceDO> selectByResourceId(@Param("resourceId") Integer resourceId); List<RoleResourceDO> selectByResourceId(@Param("resourceId") Integer resourceId);

View File

@ -1,20 +1,11 @@
package cn.iocoder.mall.admin.dataobject; package cn.iocoder.mall.admin.dataobject;
import java.util.Date; import cn.iocoder.common.framework.dataobject.BaseDO;
/** /**
* 角色实体 * 角色实体
*/ */
public class RoleDO { public class RoleDO extends BaseDO {
/**
* 账号状态 - 开启
*/
public static final Integer STATUS_ENABLE = 1;
/**
* 账号状态 - 禁用
*/
public static final Integer STATUS_DISABLE = 2;
/** /**
* 角色编号 * 角色编号
@ -24,14 +15,6 @@ public class RoleDO {
* 角色名 * 角色名
*/ */
private String name; private String name;
/**
* 创建时间
*/
private Date createTime;
/**
* 状态
*/
private Integer status;
public Integer getId() { public Integer getId() {
return id; return id;
@ -51,22 +34,4 @@ public class RoleDO {
return this; return this;
} }
public Date getCreateTime() {
return createTime;
}
public RoleDO setCreateTime(Date createTime) {
this.createTime = createTime;
return this;
}
public Integer getStatus() {
return status;
}
public RoleDO setStatus(Integer status) {
this.status = status;
return this;
}
} }

View File

@ -31,7 +31,6 @@ public class ResourceServiceImpl implements ResourceService {
@Autowired @Autowired
private RoleResourceMapper roleResourceMapper; private RoleResourceMapper roleResourceMapper;
public ResourceDO getResourceByTypeAndHandler(Integer type, String handler) { public ResourceDO getResourceByTypeAndHandler(Integer type, String handler) {
return resourceMapper.selectByTypeAndHandler(type, handler); return resourceMapper.selectByTypeAndHandler(type, handler);
} }
@ -136,6 +135,13 @@ public class ResourceServiceImpl implements ResourceService {
return CommonResult.success(true); return CommonResult.success(true);
} }
public List<ResourceDO> getResources(Set<Integer> resourceIds) {
if (resourceIds == null || resourceIds.isEmpty()) {
return Collections.emptyList();
}
return resourceMapper.selectListByIds(resourceIds);
}
private boolean isValidResourceType(Integer type) { private boolean isValidResourceType(Integer type) {
return ResourceConstants.TYPE_MENU.equals(type) return ResourceConstants.TYPE_MENU.equals(type)
|| ResourceConstants.TYPE_URL.equals(type); || ResourceConstants.TYPE_URL.equals(type);

View File

@ -1,12 +1,28 @@
package cn.iocoder.mall.admin.service; package cn.iocoder.mall.admin.service;
import cn.iocoder.common.framework.dataobject.BaseDO;
import cn.iocoder.common.framework.util.ServiceExceptionUtil;
import cn.iocoder.common.framework.vo.CommonResult;
import cn.iocoder.mall.admin.api.RoleService; import cn.iocoder.mall.admin.api.RoleService;
import cn.iocoder.mall.admin.api.bo.RoleBO;
import cn.iocoder.mall.admin.api.bo.RolePageBO;
import cn.iocoder.mall.admin.api.constant.AdminErrorCodeEnum;
import cn.iocoder.mall.admin.api.dto.RoleAddDTO;
import cn.iocoder.mall.admin.api.dto.RolePageDTO;
import cn.iocoder.mall.admin.api.dto.RoleUpdateDTO;
import cn.iocoder.mall.admin.convert.RoleConvert;
import cn.iocoder.mall.admin.dao.RoleMapper;
import cn.iocoder.mall.admin.dao.RoleResourceMapper; import cn.iocoder.mall.admin.dao.RoleResourceMapper;
import cn.iocoder.mall.admin.dataobject.ResourceDO;
import cn.iocoder.mall.admin.dataobject.RoleDO;
import cn.iocoder.mall.admin.dataobject.RoleResourceDO; import cn.iocoder.mall.admin.dataobject.RoleResourceDO;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
@Service @Service
@com.alibaba.dubbo.config.annotation.Service @com.alibaba.dubbo.config.annotation.Service
@ -14,6 +30,11 @@ public class RoleServiceImpl implements RoleService {
@Autowired @Autowired
private RoleResourceMapper roleResourceMapper; private RoleResourceMapper roleResourceMapper;
@Autowired
private RoleMapper roleMapper;
@Autowired
private ResourceServiceImpl resourceService;
public List<RoleResourceDO> getRoleByResourceHandler(String resourceHandler) { public List<RoleResourceDO> getRoleByResourceHandler(String resourceHandler) {
return roleResourceMapper.selectByResourceHandler(resourceHandler); return roleResourceMapper.selectByResourceHandler(resourceHandler);
@ -23,4 +44,86 @@ public class RoleServiceImpl implements RoleService {
return roleResourceMapper.selectByResourceId(resourceId); return roleResourceMapper.selectByResourceId(resourceId);
} }
@Override
public CommonResult<RolePageBO> getRolePage(RolePageDTO rolePageDTO) {
RolePageBO rolePage = new RolePageBO();
// 查询分页数据
int offset = rolePageDTO.getPageNo() * rolePageDTO.getPageSize();
rolePage.setRoles(RoleConvert.INSTANCE.convert(roleMapper.selectListByNameLike(rolePageDTO.getName(),
offset, rolePageDTO.getPageSize())));
// 查询分页总数
rolePage.setCount(roleMapper.selectCountByNameLike(rolePageDTO.getName()));
return CommonResult.success(rolePage);
}
@Override
public CommonResult<RoleBO> addRole(Integer adminId, RoleAddDTO roleAddDTO) {
// TODO 芋艿角色名是否要唯一呢貌似一般系统都是允许的
// 保存到数据库
RoleDO role = RoleConvert.INSTANCE.convert(roleAddDTO);
role.setCreateTime(new Date()).setDeleted(BaseDO.DELETED_NO);
roleMapper.insert(role);
// TODO 插入操作日志
// 返回成功
return CommonResult.success(RoleConvert.INSTANCE.convert(role));
}
@Override
public CommonResult<Boolean> updateRole(Integer adminId, RoleUpdateDTO roleUpdateDTO) {
// TODO 芋艿角色名是否要唯一呢貌似一般系统都是允许的
// 校验角色是否存在
if (roleMapper.selectById(roleUpdateDTO.getId()) == null) {
return ServiceExceptionUtil.error(AdminErrorCodeEnum.RESOURCE_NOT_EXISTS.getCode());
}
// 更新到数据库
RoleDO roleDO = RoleConvert.INSTANCE.convert(roleUpdateDTO);
roleMapper.update(roleDO);
// TODO 插入操作日志
// 返回成功
return CommonResult.success(true);
}
@Override
public CommonResult<Boolean> deleteRole(Integer adminId, Integer roleId) {
// 校验角色是否存在
if (roleMapper.selectById(roleId) == null) {
return ServiceExceptionUtil.error(AdminErrorCodeEnum.RESOURCE_NOT_EXISTS.getCode());
}
// 更新到数据库标记删除
RoleDO roleDO = new RoleDO().setId(roleId);
roleDO.setDeleted(RoleDO.DELETED_YES);
roleMapper.update(roleDO);
// TODO 插入操作日志
// 返回成功
return CommonResult.success(true);
}
@Override
public CommonResult<Boolean> assignResource(Integer adminId, Integer roleId, Set<Integer> resourceIds) {
// 校验角色是否存在
if (roleMapper.selectById(roleId) == null) {
return ServiceExceptionUtil.error(AdminErrorCodeEnum.RESOURCE_NOT_EXISTS.getCode());
}
// 校验是否有不存在的资源
List<ResourceDO> resources = resourceService.getResources(resourceIds);
if (resources.size() != resourceIds.size()) {
return ServiceExceptionUtil.error(AdminErrorCodeEnum.ROLE_ASSIGN_RESOURCE_NOT_EXISTS.getCode());
}
// TODO 芋艿这里先简单实现即方式是删除老的分配的资源关系然后添加新的分配的资源关系
// 标记角色原资源关系都为删除
roleResourceMapper.updateToDeletedByRoleId(roleId);
// 创建 RoleResourceDO 数组并插入到数据库
if (!resourceIds.isEmpty()) {
List<RoleResourceDO> roleResources = resourceIds.stream().map(resourceId -> {
RoleResourceDO roleResource = new RoleResourceDO().setRoleId(roleId).setResourceId(resourceId);
roleResource.setCreateTime(new Date()).setDeleted(BaseDO.DELETED_NO);
return roleResource;
}).collect(Collectors.toList());
roleResourceMapper.insertList(roleResources);
}
// TODO 插入操作日志
// 返回成功
return CommonResult.success(true);
}
} }

View File

@ -42,12 +42,14 @@
r.id, r.name, r.type, r.sort, r.display_name, r.id, r.name, r.type, r.sort, r.display_name,
r.create_time, r.pid, r.handler r.create_time, r.pid, r.handler
FROM resource r, role_resource rr FROM resource r, role_resource rr
WHERE r.type = #{type} WHERE r.deleted = 0
AND deleted = 0 <if test="type != null">
AND r.type = #{type}
</if>
AND rr.role_id IN AND rr.role_id IN
<foreach item="roleId" collection="roleIds" separator="," open="(" close=")" index=""> <foreach item="roleId" collection="roleIds" separator="," open="(" close=")" index="">
#{roleId} #{roleId}
</foreach> </foreach>
AND r.id = rr.resource_id AND r.id = rr.resource_id
</select> </select>
@ -68,6 +70,17 @@
AND deleted = 0 AND deleted = 0
</select> </select>
<select id="selectListByIds" resultType="ResourceDO">
SELECT
<include refid="FIELDS"/>
FROM resource
WHERE id IN
<foreach item="id" collection="ids" separator="," open="(" close=")" index="">
#{id}
</foreach>
AND deleted = 0
</select>
<select id="selectCountByPid" resultType="int"> <select id="selectCountByPid" resultType="int">
SELECT SELECT
COUNT(1) COUNT(1)

View File

@ -0,0 +1,57 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.iocoder.mall.admin.dao.RoleMapper">
<insert id="insert" parameterType="RoleDO" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
INSERT INTO role (
name, create_time, deleted
) VALUES (
#{name}, #{createTime}, #{deleted}
)
</insert>
<update id="update" parameterType="RoleDO">
UPDATE role
<set>
<if test="name != null">
, name = #{name}
</if>
<if test="deleted != null">
, deleted = #{deleted}
</if>
</set>
WHERE id = #{id}
</update>
<select id="selectById" parameterType="Integer" resultType="RoleDO">
SELECT
id, name, create_time
FROM role
WHERE id = #{id}
AND deleted = 0
</select>
<select id="selectListByNameLike" resultType="RoleDO">
SELECT
id, name, create_time
FROM role
<where>
<if test="name != null">
name LIKE "%"#{name}"%"
</if>
</where>
LIMIT #{offset}, #{limit}
</select>
<select id="selectCountByNameLike" resultType="RoleDO">
SELECT
COUNT(1)
FROM role
<where>
<if test="name != null">
name LIKE "%"#{name}"%"
</if>
</where>
</select>
</mapper>

View File

@ -41,4 +41,13 @@
AND deleted = 0 AND deleted = 0
</update> </update>
<insert id="insertList">
INSERT INTO role_resource (
resource_id, role_id, create_time, deleted
) VALUES
<foreach collection="roleResources" item="roleResource" separator=",">
(#{roleResource.resourceId}, #{roleResource.roleId}, #{roleResource.createTime}, #{roleResource.deleted})
</foreach>
</insert>
</mapper> </mapper>