diff --git a/admin/admin-application/src/main/java/cn/iocoder/mall/admin/application/controller/PassportController.java b/admin/admin-application/src/main/java/cn/iocoder/mall/admin/application/controller/PassportController.java index e2cc2bdd3..dcb15a6f0 100644 --- a/admin/admin-application/src/main/java/cn/iocoder/mall/admin/application/controller/PassportController.java +++ b/admin/admin-application/src/main/java/cn/iocoder/mall/admin/application/controller/PassportController.java @@ -24,7 +24,7 @@ public class PassportController { private OAuth2Service oauth2Service; @PostMapping("/login") - @ApiOperation(value = "手机号 + 验证码登陆(注册)", notes = "如果手机对应的账号不存在,则会自动创建") + @ApiOperation(value = "手机号 + 密码登陆") @ApiImplicitParams({ @ApiImplicitParam(name = "username", value = "账号", required = true, example = "15601691300"), @ApiImplicitParam(name = "password", value = "密码", required = true, example = "future") diff --git a/admin/admin-application/src/main/java/cn/iocoder/mall/admin/application/controller/ResourceController.java b/admin/admin-application/src/main/java/cn/iocoder/mall/admin/application/controller/ResourceController.java index 12808e6f9..4c71ca14e 100644 --- a/admin/admin-application/src/main/java/cn/iocoder/mall/admin/application/controller/ResourceController.java +++ b/admin/admin-application/src/main/java/cn/iocoder/mall/admin/application/controller/ResourceController.java @@ -3,8 +3,9 @@ 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.bo.ResourceBO; -import cn.iocoder.mall.admin.api.constant.ResourceType; +import cn.iocoder.mall.admin.api.constant.ResourceConstants; import cn.iocoder.mall.admin.api.dto.ResourceAddDTO; +import cn.iocoder.mall.admin.api.dto.ResourceUpdateDTO; import cn.iocoder.mall.admin.application.convert.ResourceConvert; import cn.iocoder.mall.admin.application.vo.AdminMenuTreeNodeVO; import cn.iocoder.mall.admin.sdk.context.AdminSecurityContextHolder; @@ -32,7 +33,7 @@ public class ResourceController { @GetMapping("/admin_menu_tree") @ApiOperation(value = "获得当前登陆的管理员拥有的菜单权限", notes = "以树结构返回") public CommonResult> adminMenuTree() { - List resources = resourceService.getResourceByTypeAndRoleIds(ResourceType.MENU, AdminSecurityContextHolder.getContext().getRoleIds()); + List resources = resourceService.getResourcesByTypeAndRoleIds(ResourceConstants.TYPE_MENU, AdminSecurityContextHolder.getContext().getRoleIds()); // 创建 AdminMenuTreeNodeVO Map Map treeNodeMap = resources.stream().collect(Collectors.toMap(ResourceBO::getId, ResourceConvert.INSTANCE::convert)); // 处理父子关系 @@ -58,33 +59,40 @@ public class ResourceController { @ApiOperation(value = "获得当前登陆的管理员拥有的 URL 权限列表") // @ApiModelProperty(value = "data", example = "['/admin/role/add', '/admin/role/update']") 没效果 public CommonResult> adminUrlList() { - List resources = resourceService.getResourceByTypeAndRoleIds(ResourceType.URL, AdminSecurityContextHolder.getContext().getRoleIds()); + List resources = resourceService.getResourcesByTypeAndRoleIds(ResourceConstants.TYPE_URL, AdminSecurityContextHolder.getContext().getRoleIds()); return CommonResult.success(resources.stream().map(ResourceBO::getHandler).collect(Collectors.toSet())); } - // =========== 资源管理 API =========== // TODO 芋艿,注释 @PostMapping("/add") @ApiOperation(value = "创建资源", notes = "例如说,菜单资源,Url 资源") - public void add(@RequestParam("name") String name, - @RequestParam("type") Integer type, - @RequestParam("sort") Integer sort, - @RequestParam("displayName") String displayName, - @RequestParam("pid") Integer pid, - @RequestParam("handler") String handler) { + public CommonResult add(@RequestParam("name") String name, + @RequestParam("type") Integer type, + @RequestParam("sort") Integer sort, + @RequestParam("displayName") String displayName, + @RequestParam("pid") Integer pid, + @RequestParam("handler") String handler) { ResourceAddDTO resourceAddDTO = new ResourceAddDTO().setName(name).setType(type).setSort(sort) .setDisplayName(displayName).setPid(pid).setHandler(handler); - CommonResult result = resourceService.addResource(resourceAddDTO); + return resourceService.addResource(AdminSecurityContextHolder.getContext().getAdminId(), resourceAddDTO); } - public void update() { - + @PostMapping("/update") + public CommonResult update(@RequestParam("id") Integer id, + @RequestParam("name") String name, + @RequestParam("sort") Integer sort, + @RequestParam("displayName") String displayName, + @RequestParam("pid") Integer pid, + @RequestParam("handler") String handler) { + ResourceUpdateDTO resourceUpdateDTO = new ResourceUpdateDTO().setId(id).setName(name).setSort(sort).setDisplayName(displayName).setPid(pid).setHandler(handler); + return resourceService.updateResource(AdminSecurityContextHolder.getContext().getAdminId(), resourceUpdateDTO); } - public void delete() { - + @PostMapping("/delete") + public CommonResult delete(@RequestParam("id") Integer id) { + return resourceService.deleteResource(AdminSecurityContextHolder.getContext().getAdminId(), id); } } \ No newline at end of file diff --git a/admin/admin-service-api/src/main/java/cn/iocoder/mall/admin/api/ResourceService.java b/admin/admin-service-api/src/main/java/cn/iocoder/mall/admin/api/ResourceService.java index 61f54a5c3..fa0f87812 100644 --- a/admin/admin-service-api/src/main/java/cn/iocoder/mall/admin/api/ResourceService.java +++ b/admin/admin-service-api/src/main/java/cn/iocoder/mall/admin/api/ResourceService.java @@ -3,14 +3,35 @@ package cn.iocoder.mall.admin.api; import cn.iocoder.common.framework.vo.CommonResult; import cn.iocoder.mall.admin.api.bo.ResourceBO; import cn.iocoder.mall.admin.api.dto.ResourceAddDTO; +import cn.iocoder.mall.admin.api.dto.ResourceUpdateDTO; +import org.springframework.lang.Nullable; import java.util.List; import java.util.Set; public interface ResourceService { - List getResourceByTypeAndRoleIds(Integer type, Set roleIds); + /** + * 查询指定类型 + 指定角色的资源列表 + * + * @param type 指定类型。 + * @param roleIds 指定角色的数组。 + * @return 资源列表 + */ + List getResourcesByTypeAndRoleIds(Integer type, Set roleIds); - CommonResult addResource(ResourceAddDTO resourceAddDTO); + /** + * 查询指定类型的资源列表 + * + * @param type 指定类型。可以为空,此时不做为过滤条件 + * @return 资源列表 + */ + List getResourcesByType(@Nullable Integer type); + + CommonResult addResource(Integer adminId, ResourceAddDTO resourceAddDTO); + + CommonResult updateResource(Integer adminId, ResourceUpdateDTO resourceUpdateDTO); + + CommonResult deleteResource(Integer adminId, Integer resourceId); } \ No newline at end of file diff --git a/admin/admin-service-api/src/main/java/cn/iocoder/mall/admin/api/constant/AdminErrorCodeEnum.java b/admin/admin-service-api/src/main/java/cn/iocoder/mall/admin/api/constant/AdminErrorCodeEnum.java index 3c17cc666..ff053fb9e 100644 --- a/admin/admin-service-api/src/main/java/cn/iocoder/mall/admin/api/constant/AdminErrorCodeEnum.java +++ b/admin/admin-service-api/src/main/java/cn/iocoder/mall/admin/api/constant/AdminErrorCodeEnum.java @@ -20,10 +20,17 @@ public enum AdminErrorCodeEnum { OAUTH_INVALID_TOKEN(1002001020, ""), // 预留 - // ========== 管理员模块 ========== + // ========== 管理员模块 1002002000 ========== ADMIN_USERNAME_NOT_REGISTERED(1002002000, "账号不存在"), ADMIN_PASSWORD_ERROR(1002002001, "密码不正确"), - ADMIN_IS_DISABLE(1002002002, "账号被禁用"); + ADMIN_IS_DISABLE(1002002002, "账号被禁用"), + + // ========== 资源模块 1002003000 ========== + RESOURCE_NAME_DUPLICATE(1002003000, "已经存在该名字的资源"), + RESOURCE_PARENT_NOT_EXISTS(1002003001, "父资源不存在"), + RESOURCE_PARENT_ERROR(1002003002, "不能设置自己为父资源"), + RESOURCE_NOT_EXISTS(1002003002, "资源不存在"), + ; private final int code; private final String message; diff --git a/admin/admin-service-api/src/main/java/cn/iocoder/mall/admin/api/constant/ResourceConstants.java b/admin/admin-service-api/src/main/java/cn/iocoder/mall/admin/api/constant/ResourceConstants.java new file mode 100644 index 000000000..863192b59 --- /dev/null +++ b/admin/admin-service-api/src/main/java/cn/iocoder/mall/admin/api/constant/ResourceConstants.java @@ -0,0 +1,22 @@ +package cn.iocoder.mall.admin.api.constant; + +/** + * 资源类型 + */ +public interface ResourceConstants { + + /** + * 类型 - 菜单 + */ + Integer TYPE_MENU = 1; + /** + * 类型 - URL + */ + Integer TYPE_URL = 2; + + /** + * 父资源编号 - 根节点 + */ + Integer PID_ROOT = 0; + +} \ No newline at end of file diff --git a/admin/admin-service-api/src/main/java/cn/iocoder/mall/admin/api/constant/ResourceType.java b/admin/admin-service-api/src/main/java/cn/iocoder/mall/admin/api/constant/ResourceType.java deleted file mode 100644 index 1b87eca00..000000000 --- a/admin/admin-service-api/src/main/java/cn/iocoder/mall/admin/api/constant/ResourceType.java +++ /dev/null @@ -1,17 +0,0 @@ -package cn.iocoder.mall.admin.api.constant; - -/** - * 资源类型 - */ -public interface ResourceType { - - /** - * 彩蛋 - */ - Integer MENU = 1; - /** - * URL - */ - Integer URL = 2; - -} \ No newline at end of file diff --git a/admin/admin-service-api/src/main/java/cn/iocoder/mall/admin/api/dto/ResourceAddDTO.java b/admin/admin-service-api/src/main/java/cn/iocoder/mall/admin/api/dto/ResourceAddDTO.java index ae3a41e8f..9c6966960 100644 --- a/admin/admin-service-api/src/main/java/cn/iocoder/mall/admin/api/dto/ResourceAddDTO.java +++ b/admin/admin-service-api/src/main/java/cn/iocoder/mall/admin/api/dto/ResourceAddDTO.java @@ -29,7 +29,7 @@ public class ResourceAddDTO { @NotEmpty(message = "资源名字不能为空") private String displayName; /** - * 父资源比那好 + * 父资源编号 */ private Integer pid; /** diff --git a/admin/admin-service-api/src/main/java/cn/iocoder/mall/admin/api/dto/ResourceUpdateDTO.java b/admin/admin-service-api/src/main/java/cn/iocoder/mall/admin/api/dto/ResourceUpdateDTO.java new file mode 100644 index 000000000..b77aeefda --- /dev/null +++ b/admin/admin-service-api/src/main/java/cn/iocoder/mall/admin/api/dto/ResourceUpdateDTO.java @@ -0,0 +1,94 @@ +package cn.iocoder.mall.admin.api.dto; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +/** + * 资源更新 DTO + */ +public class ResourceUpdateDTO { + + /** + * 资源编号 + */ + @NotNull(message = "资源编号不能为空") + private Integer id; + /** + * 资源名字(标识) + */ + @NotEmpty(message = "资源名字不能为空") + private String name; + /** + * 排序值 + */ + @NotNull(message = "类型不能为空") + private Integer sort; + /** + * 展示名 + */ + @NotEmpty(message = "资源名字不能为空") + private String displayName; + /** + * 父资源编号 + */ + private Integer pid; + /** + * 操作 + */ + private String handler; + + public Integer getId() { + return id; + } + + public ResourceUpdateDTO setId(Integer id) { + this.id = id; + return this; + } + + public String getName() { + return name; + } + + public ResourceUpdateDTO setName(String name) { + this.name = name; + return this; + } + + public Integer getSort() { + return sort; + } + + public ResourceUpdateDTO setSort(Integer sort) { + this.sort = sort; + return this; + } + + public String getDisplayName() { + return displayName; + } + + public ResourceUpdateDTO setDisplayName(String displayName) { + this.displayName = displayName; + return this; + } + + public Integer getPid() { + return pid; + } + + public ResourceUpdateDTO setPid(Integer pid) { + this.pid = pid; + return this; + } + + public String getHandler() { + return handler; + } + + public ResourceUpdateDTO setHandler(String handler) { + this.handler = handler; + return this; + } + +} \ No newline at end of file diff --git a/admin/admin-service-impl/src/main/java/cn/iocoder/mall/admin/convert/ResourceConvert.java b/admin/admin-service-impl/src/main/java/cn/iocoder/mall/admin/convert/ResourceConvert.java index 093ddf9a6..49b168941 100644 --- a/admin/admin-service-impl/src/main/java/cn/iocoder/mall/admin/convert/ResourceConvert.java +++ b/admin/admin-service-impl/src/main/java/cn/iocoder/mall/admin/convert/ResourceConvert.java @@ -1,6 +1,8 @@ package cn.iocoder.mall.admin.convert; import cn.iocoder.mall.admin.api.bo.ResourceBO; +import cn.iocoder.mall.admin.api.dto.ResourceAddDTO; +import cn.iocoder.mall.admin.api.dto.ResourceUpdateDTO; import cn.iocoder.mall.admin.dataobject.ResourceDO; import org.mapstruct.Mapper; import org.mapstruct.Mappings; @@ -19,4 +21,10 @@ public interface ResourceConvert { @Mappings({}) List convert(List resourceDOs); + @Mappings({}) + ResourceDO convert(ResourceAddDTO resourceAddDTO); + + @Mappings({}) + ResourceDO convert(ResourceUpdateDTO resourceUpdateDTO); + } \ No newline at end of file diff --git a/admin/admin-service-impl/src/main/java/cn/iocoder/mall/admin/dao/ResourceMapper.java b/admin/admin-service-impl/src/main/java/cn/iocoder/mall/admin/dao/ResourceMapper.java index 7b68eed41..0aaa79ba3 100644 --- a/admin/admin-service-impl/src/main/java/cn/iocoder/mall/admin/dao/ResourceMapper.java +++ b/admin/admin-service-impl/src/main/java/cn/iocoder/mall/admin/dao/ResourceMapper.java @@ -16,4 +16,13 @@ public interface ResourceMapper { List selectListByTypeAndRoleIds(@Param("type") Integer type, @Param("roleIds") Set roleIds); + List selectListByType(@Param("type") Integer type); + + ResourceDO selectByName(@Param("name") String name); + + ResourceDO selectById(@Param("id") Integer id); + + void insert(ResourceDO resource); + + int update(ResourceDO resource); } \ No newline at end of file diff --git a/admin/admin-service-impl/src/main/java/cn/iocoder/mall/admin/service/ResourceServiceImpl.java b/admin/admin-service-impl/src/main/java/cn/iocoder/mall/admin/service/ResourceServiceImpl.java index cbfb165fd..466f58bce 100644 --- a/admin/admin-service-impl/src/main/java/cn/iocoder/mall/admin/service/ResourceServiceImpl.java +++ b/admin/admin-service-impl/src/main/java/cn/iocoder/mall/admin/service/ResourceServiceImpl.java @@ -1,9 +1,15 @@ package cn.iocoder.mall.admin.service; +import cn.iocoder.common.framework.constant.SysErrorCodeEnum; +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.ResourceService; import cn.iocoder.mall.admin.api.bo.ResourceBO; +import cn.iocoder.mall.admin.api.constant.AdminErrorCodeEnum; +import cn.iocoder.mall.admin.api.constant.ResourceConstants; import cn.iocoder.mall.admin.api.dto.ResourceAddDTO; +import cn.iocoder.mall.admin.api.dto.ResourceUpdateDTO; import cn.iocoder.mall.admin.convert.ResourceConvert; import cn.iocoder.mall.admin.dao.ResourceMapper; import cn.iocoder.mall.admin.dataobject.ResourceDO; @@ -11,6 +17,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.Collections; +import java.util.Date; import java.util.List; import java.util.Set; @@ -26,7 +33,7 @@ public class ResourceServiceImpl implements ResourceService { } @Override - public List getResourceByTypeAndRoleIds(Integer type, Set roleIds) { + public List getResourcesByTypeAndRoleIds(Integer type, Set roleIds) { if (roleIds == null || roleIds.isEmpty()) { return Collections.emptyList(); } @@ -34,8 +41,100 @@ public class ResourceServiceImpl implements ResourceService { } @Override - public CommonResult addResource(ResourceAddDTO resourceAddDTO) { - return null; + public List getResourcesByType(Integer type) { + return ResourceConvert.INSTANCE.convert(resourceMapper.selectListByType (type)); + } + + @Override + @SuppressWarnings("Duplicates") + public CommonResult addResource(Integer adminId, ResourceAddDTO resourceAddDTO) { + // 补充未在 Validation 中校验的参数校验 + if (!isValidResourceType(resourceAddDTO.getType())) { + return CommonResult.error(SysErrorCodeEnum.VALIDATION_REQUEST_PARAM_ERROR.getCode(), "资源类型必须是菜单或 Url"); // TODO 有点搓 + } + // 校验资源唯一性 + if (resourceMapper.selectByName(resourceAddDTO.getName()) != null) { + return ServiceExceptionUtil.error(AdminErrorCodeEnum.RESOURCE_NAME_DUPLICATE.getCode()); + } + // 校验父资源存在 + if (resourceAddDTO.getPid() == null) { + resourceAddDTO.setPid(ResourceConstants.PID_ROOT); + } + if (checkParentExists(resourceAddDTO.getPid())) { + return ServiceExceptionUtil.error(AdminErrorCodeEnum.RESOURCE_PARENT_NOT_EXISTS.getCode()); + } + // 存储到数据库 + ResourceDO resource = ResourceConvert.INSTANCE.convert(resourceAddDTO); + if (ResourceConstants.PID_ROOT.equals(resourceAddDTO.getPid())) { // 根节点,必须没有操作 + resource.setHandler(null); + } + resource.setCreateTime(new Date()); + resource.setDeleted(BaseDO.DELETED_NO); + resourceMapper.insert(resource); + // TODO 操作日志 + // 返回成功 + return CommonResult.success(ResourceConvert.INSTANCE.convert(resource)); + } + + @Override + @SuppressWarnings("Duplicates") + public CommonResult updateResource(Integer adminId, ResourceUpdateDTO resourceUpdateDTO) { + // 校验更新的资源是否存在 + if (resourceMapper.selectById(resourceUpdateDTO.getId()) == null) { + return ServiceExceptionUtil.error(AdminErrorCodeEnum.RESOURCE_NOT_EXISTS.getCode()); + } + // 校验资源唯一性 + ResourceDO existNameResource = resourceMapper.selectByName(resourceUpdateDTO.getName()); + if (existNameResource != null && existNameResource.getId().equals(resourceUpdateDTO.getId())) { + return ServiceExceptionUtil.error(AdminErrorCodeEnum.RESOURCE_NAME_DUPLICATE.getCode()); + } + // 不能设置自己为父资源 + if (resourceUpdateDTO.getId().equals(resourceUpdateDTO.getPid())) { + return ServiceExceptionUtil.error(AdminErrorCodeEnum.RESOURCE_PARENT_ERROR.getCode()); + } + // 校验父资源存在 + if (resourceUpdateDTO.getPid() == null) { + resourceUpdateDTO.setPid(ResourceConstants.PID_ROOT); + } + if (checkParentExists(resourceUpdateDTO.getPid())) { + return ServiceExceptionUtil.error(AdminErrorCodeEnum.RESOURCE_PARENT_NOT_EXISTS.getCode()); + } + // 更新到数据库 + ResourceDO resource = ResourceConvert.INSTANCE.convert(resourceUpdateDTO); + if (ResourceConstants.PID_ROOT.equals(resourceUpdateDTO.getPid())) { // 根节点,必须没有操作 + resource.setHandler(null); + } + resourceMapper.update(resource); + // TODO 操作日志 + // 返回成功 + return CommonResult.success(true); + } + + @Override + public CommonResult deleteResource(Integer adminId, Integer resourceId) { + // 校验更新的资源是否存在 + if (resourceMapper.selectById(resourceId) == null) { + return ServiceExceptionUtil.error(AdminErrorCodeEnum.RESOURCE_NOT_EXISTS.getCode()); + } + // TODO 还有校验 + // 更新到数据库 + ResourceDO resource = new ResourceDO().setId(resourceId); + resource.setDeleted(BaseDO.DELETED_YES); + resourceMapper.update(resource); + // 返回成功 + return CommonResult.success(true); + } + + private boolean isValidResourceType(Integer type) { + return ResourceConstants.TYPE_MENU.equals(type) + || ResourceConstants.TYPE_URL.equals(type); + } + + private boolean checkParentExists(Integer pid) { + if (!ResourceConstants.PID_ROOT.equals(pid)) { + return resourceMapper.selectById(pid) == null; + } + return false; } } \ No newline at end of file diff --git a/admin/admin-service-impl/src/main/resources/mapper/ResourceMapper.xml b/admin/admin-service-impl/src/main/resources/mapper/ResourceMapper.xml index eeb7caeaa..fb829e8ce 100644 --- a/admin/admin-service-impl/src/main/resources/mapper/ResourceMapper.xml +++ b/admin/admin-service-impl/src/main/resources/mapper/ResourceMapper.xml @@ -10,28 +10,92 @@ - + SELECT + + FROM resource + WHERE type = #{type} + AND handler = #{handler} + AND deleted = 0 + LIMIT 1 + + + + + + + + INSERT INTO resource ( + name, type, sort, display_name, handler, + pid, create_time, deleted + ) VALUES ( + #{name}, #{type}, #{sort}, #{displayName}, #{handler}, + #{pid}, #{createTime}, #{deleted} + ) + + + + UPDATE resource + + + name = #{name}, + + + sort = #{sort}, + + + display_name = #{displayName}, + + + pid = #{pid}, + + + handler = #{handler}, + + + deleted = #{deleted} + + + WHERE id = #{id} + + \ No newline at end of file diff --git a/common/common-framework/src/main/java/cn/iocoder/common/framework/dataobject/BaseDO.java b/common/common-framework/src/main/java/cn/iocoder/common/framework/dataobject/BaseDO.java index 51e3ee09e..54cf1c7bb 100644 --- a/common/common-framework/src/main/java/cn/iocoder/common/framework/dataobject/BaseDO.java +++ b/common/common-framework/src/main/java/cn/iocoder/common/framework/dataobject/BaseDO.java @@ -7,6 +7,15 @@ import java.util.Date; */ public class BaseDO { + /** + * 是否删除 - 是 + */ + public static final Integer DELETED_YES = 1; + /** + * 是否删除 - 否 + */ + public static final Integer DELETED_NO = 0; + /** * 创建时间 */ @@ -15,7 +24,10 @@ public class BaseDO { * 最后更新时间 */ private Date updateTime; - private Boolean deleted; + /** + * 是否删除 + */ + private Integer deleted; public Date getCreateTime() { return createTime; @@ -35,11 +47,11 @@ public class BaseDO { return this; } - public Boolean getDeleted() { + public Integer getDeleted() { return deleted; } - public BaseDO setDeleted(Boolean deleted) { + public BaseDO setDeleted(Integer deleted) { this.deleted = deleted; return this; }