资源添加开发完成

This commit is contained in:
YunaiV 2019-02-28 23:11:59 +08:00
parent f5b105973d
commit b1248d7e2a
13 changed files with 386 additions and 59 deletions

View File

@ -24,7 +24,7 @@ public class PassportController {
private OAuth2Service oauth2Service; private OAuth2Service oauth2Service;
@PostMapping("/login") @PostMapping("/login")
@ApiOperation(value = "手机号 + 验证码登陆(注册)", notes = "如果手机对应的账号不存在,则会自动创建") @ApiOperation(value = "手机号 + 密码登陆")
@ApiImplicitParams({ @ApiImplicitParams({
@ApiImplicitParam(name = "username", value = "账号", required = true, example = "15601691300"), @ApiImplicitParam(name = "username", value = "账号", required = true, example = "15601691300"),
@ApiImplicitParam(name = "password", value = "密码", required = true, example = "future") @ApiImplicitParam(name = "password", value = "密码", required = true, example = "future")

View File

@ -3,8 +3,9 @@ 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.ResourceService;
import cn.iocoder.mall.admin.api.bo.ResourceBO; 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.ResourceAddDTO;
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.AdminMenuTreeNodeVO;
import cn.iocoder.mall.admin.sdk.context.AdminSecurityContextHolder; import cn.iocoder.mall.admin.sdk.context.AdminSecurityContextHolder;
@ -32,7 +33,7 @@ public class ResourceController {
@GetMapping("/admin_menu_tree") @GetMapping("/admin_menu_tree")
@ApiOperation(value = "获得当前登陆的管理员拥有的菜单权限", notes = "以树结构返回") @ApiOperation(value = "获得当前登陆的管理员拥有的菜单权限", notes = "以树结构返回")
public CommonResult<List<AdminMenuTreeNodeVO>> adminMenuTree() { public CommonResult<List<AdminMenuTreeNodeVO>> adminMenuTree() {
List<ResourceBO> resources = resourceService.getResourceByTypeAndRoleIds(ResourceType.MENU, AdminSecurityContextHolder.getContext().getRoleIds()); List<ResourceBO> resources = resourceService.getResourcesByTypeAndRoleIds(ResourceConstants.TYPE_MENU, AdminSecurityContextHolder.getContext().getRoleIds());
// 创建 AdminMenuTreeNodeVO Map // 创建 AdminMenuTreeNodeVO Map
Map<Integer, AdminMenuTreeNodeVO> treeNodeMap = resources.stream().collect(Collectors.toMap(ResourceBO::getId, ResourceConvert.INSTANCE::convert)); Map<Integer, AdminMenuTreeNodeVO> treeNodeMap = resources.stream().collect(Collectors.toMap(ResourceBO::getId, ResourceConvert.INSTANCE::convert));
// 处理父子关系 // 处理父子关系
@ -58,17 +59,16 @@ public class ResourceController {
@ApiOperation(value = "获得当前登陆的管理员拥有的 URL 权限列表") @ApiOperation(value = "获得当前登陆的管理员拥有的 URL 权限列表")
// @ApiModelProperty(value = "data", example = "['/admin/role/add', '/admin/role/update']") 没效果 // @ApiModelProperty(value = "data", example = "['/admin/role/add', '/admin/role/update']") 没效果
public CommonResult<Set<String>> adminUrlList() { public CommonResult<Set<String>> adminUrlList() {
List<ResourceBO> resources = resourceService.getResourceByTypeAndRoleIds(ResourceType.URL, AdminSecurityContextHolder.getContext().getRoleIds()); List<ResourceBO> resources = resourceService.getResourcesByTypeAndRoleIds(ResourceConstants.TYPE_URL, AdminSecurityContextHolder.getContext().getRoleIds());
return CommonResult.success(resources.stream().map(ResourceBO::getHandler).collect(Collectors.toSet())); return CommonResult.success(resources.stream().map(ResourceBO::getHandler).collect(Collectors.toSet()));
} }
// =========== 资源管理 API =========== // =========== 资源管理 API ===========
// TODO 芋艿注释 // TODO 芋艿注释
@PostMapping("/add") @PostMapping("/add")
@ApiOperation(value = "创建资源", notes = "例如说菜单资源Url 资源") @ApiOperation(value = "创建资源", notes = "例如说菜单资源Url 资源")
public void add(@RequestParam("name") String name, public CommonResult<ResourceBO> add(@RequestParam("name") String name,
@RequestParam("type") Integer type, @RequestParam("type") Integer type,
@RequestParam("sort") Integer sort, @RequestParam("sort") Integer sort,
@RequestParam("displayName") String displayName, @RequestParam("displayName") String displayName,
@ -76,15 +76,23 @@ public class ResourceController {
@RequestParam("handler") String handler) { @RequestParam("handler") String handler) {
ResourceAddDTO resourceAddDTO = new ResourceAddDTO().setName(name).setType(type).setSort(sort) ResourceAddDTO resourceAddDTO = new ResourceAddDTO().setName(name).setType(type).setSort(sort)
.setDisplayName(displayName).setPid(pid).setHandler(handler); .setDisplayName(displayName).setPid(pid).setHandler(handler);
CommonResult<ResourceBO> result = resourceService.addResource(resourceAddDTO); return resourceService.addResource(AdminSecurityContextHolder.getContext().getAdminId(), resourceAddDTO);
} }
public void update() { @PostMapping("/update")
public CommonResult<Boolean> 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<Boolean> delete(@RequestParam("id") Integer id) {
return resourceService.deleteResource(AdminSecurityContextHolder.getContext().getAdminId(), id);
} }
} }

View File

@ -3,14 +3,35 @@ package cn.iocoder.mall.admin.api;
import cn.iocoder.common.framework.vo.CommonResult; import cn.iocoder.common.framework.vo.CommonResult;
import cn.iocoder.mall.admin.api.bo.ResourceBO; import cn.iocoder.mall.admin.api.bo.ResourceBO;
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 org.springframework.lang.Nullable;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
public interface ResourceService { public interface ResourceService {
List<ResourceBO> getResourceByTypeAndRoleIds(Integer type, Set<Integer> roleIds); /**
* 查询指定类型 + 指定角色的资源列表
*
* @param type 指定类型
* @param roleIds 指定角色的数组
* @return 资源列表
*/
List<ResourceBO> getResourcesByTypeAndRoleIds(Integer type, Set<Integer> roleIds);
CommonResult<ResourceBO> addResource(ResourceAddDTO resourceAddDTO); /**
* 查询指定类型的资源列表
*
* @param type 指定类型可以为空此时不做为过滤条件
* @return 资源列表
*/
List<ResourceBO> getResourcesByType(@Nullable Integer type);
CommonResult<ResourceBO> addResource(Integer adminId, ResourceAddDTO resourceAddDTO);
CommonResult<Boolean> updateResource(Integer adminId, ResourceUpdateDTO resourceUpdateDTO);
CommonResult<Boolean> deleteResource(Integer adminId, Integer resourceId);
} }

View File

@ -20,10 +20,17 @@ public enum AdminErrorCodeEnum {
OAUTH_INVALID_TOKEN(1002001020, ""), // 预留 OAUTH_INVALID_TOKEN(1002001020, ""), // 预留
// ========== 管理员模块 ========== // ========== 管理员模块 1002002000 ==========
ADMIN_USERNAME_NOT_REGISTERED(1002002000, "账号不存在"), ADMIN_USERNAME_NOT_REGISTERED(1002002000, "账号不存在"),
ADMIN_PASSWORD_ERROR(1002002001, "密码不正确"), 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 int code;
private final String message; private final String message;

View File

@ -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;
}

View File

@ -1,17 +0,0 @@
package cn.iocoder.mall.admin.api.constant;
/**
* 资源类型
*/
public interface ResourceType {
/**
* 彩蛋
*/
Integer MENU = 1;
/**
* URL
*/
Integer URL = 2;
}

View File

@ -29,7 +29,7 @@ public class ResourceAddDTO {
@NotEmpty(message = "资源名字不能为空") @NotEmpty(message = "资源名字不能为空")
private String displayName; private String displayName;
/** /**
* 父资源比那好 * 父资源编号
*/ */
private Integer pid; private Integer pid;
/** /**

View File

@ -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;
}
}

View File

@ -1,6 +1,8 @@
package cn.iocoder.mall.admin.convert; package cn.iocoder.mall.admin.convert;
import cn.iocoder.mall.admin.api.bo.ResourceBO; 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 cn.iocoder.mall.admin.dataobject.ResourceDO;
import org.mapstruct.Mapper; import org.mapstruct.Mapper;
import org.mapstruct.Mappings; import org.mapstruct.Mappings;
@ -19,4 +21,10 @@ public interface ResourceConvert {
@Mappings({}) @Mappings({})
List<ResourceBO> convert(List<ResourceDO> resourceDOs); List<ResourceBO> convert(List<ResourceDO> resourceDOs);
@Mappings({})
ResourceDO convert(ResourceAddDTO resourceAddDTO);
@Mappings({})
ResourceDO convert(ResourceUpdateDTO resourceUpdateDTO);
} }

View File

@ -16,4 +16,13 @@ public interface ResourceMapper {
List<ResourceDO> selectListByTypeAndRoleIds(@Param("type") Integer type, List<ResourceDO> selectListByTypeAndRoleIds(@Param("type") Integer type,
@Param("roleIds") Set<Integer> roleIds); @Param("roleIds") Set<Integer> roleIds);
List<ResourceDO> 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);
} }

View File

@ -1,9 +1,15 @@
package cn.iocoder.mall.admin.service; 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.common.framework.vo.CommonResult;
import cn.iocoder.mall.admin.api.ResourceService; import cn.iocoder.mall.admin.api.ResourceService;
import cn.iocoder.mall.admin.api.bo.ResourceBO; 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.ResourceAddDTO;
import cn.iocoder.mall.admin.api.dto.ResourceUpdateDTO;
import cn.iocoder.mall.admin.convert.ResourceConvert; import cn.iocoder.mall.admin.convert.ResourceConvert;
import cn.iocoder.mall.admin.dao.ResourceMapper; import cn.iocoder.mall.admin.dao.ResourceMapper;
import cn.iocoder.mall.admin.dataobject.ResourceDO; import cn.iocoder.mall.admin.dataobject.ResourceDO;
@ -11,6 +17,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.Collections; import java.util.Collections;
import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@ -26,7 +33,7 @@ public class ResourceServiceImpl implements ResourceService {
} }
@Override @Override
public List<ResourceBO> getResourceByTypeAndRoleIds(Integer type, Set<Integer> roleIds) { public List<ResourceBO> getResourcesByTypeAndRoleIds(Integer type, Set<Integer> roleIds) {
if (roleIds == null || roleIds.isEmpty()) { if (roleIds == null || roleIds.isEmpty()) {
return Collections.emptyList(); return Collections.emptyList();
} }
@ -34,8 +41,100 @@ public class ResourceServiceImpl implements ResourceService {
} }
@Override @Override
public CommonResult<ResourceBO> addResource(ResourceAddDTO resourceAddDTO) { public List<ResourceBO> getResourcesByType(Integer type) {
return null; return ResourceConvert.INSTANCE.convert(resourceMapper.selectListByType (type));
}
@Override
@SuppressWarnings("Duplicates")
public CommonResult<ResourceBO> 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<Boolean> 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<Boolean> 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;
} }
} }

View File

@ -10,14 +10,27 @@
<!--)--> <!--)-->
<!--</insert>--> <!--</insert>-->
<select id="selectByTypeAndHandler" resultType="ResourceDO"> <sql id="FIELDS">
SELECT
id, name, type, sort, display_name, id, name, type, sort, display_name,
create_time, pid, handler create_time, pid, handler
</sql>
<select id="selectByTypeAndHandler" resultType="ResourceDO">
SELECT
<include refid="FIELDS"/>
FROM resource FROM resource
WHERE type = #{type} WHERE type = #{type}
AND handler = #{handler} AND handler = #{handler}
AND deleted = 0 AND deleted = 0
LIMIT 1
</select>
<select id="selectListByType" parameterType="Integer" resultType="ResourceDO">
SELECT
<include refid="FIELDS"/>
FROM resource
WHERE type = #{type}
AND deleted = 0
</select> </select>
<select id="selectListByTypeAndRoleIds" resultType="ResourceDO"> <select id="selectListByTypeAndRoleIds" resultType="ResourceDO">
@ -34,4 +47,55 @@
AND r.id = rr.resource_id AND r.id = rr.resource_id
</select> </select>
<select id="selectByName" parameterType="String" resultType="ResourceDO">
SELECT
<include refid="FIELDS"/>
FROM resource
WHERE name = #{name}
AND deleted = 0
LIMIT 1
</select>
<select id="selectById" resultType="ResourceDO">
SELECT
<include refid="FIELDS"/>
FROM resource
WHERE id = #{id}
AND deleted = 0
</select>
<insert id="insert" parameterType="ResourceDO" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
INSERT INTO resource (
name, type, sort, display_name, handler,
pid, create_time, deleted
) VALUES (
#{name}, #{type}, #{sort}, #{displayName}, #{handler},
#{pid}, #{createTime}, #{deleted}
)
</insert>
<update id="update" parameterType="ResourceDO">
UPDATE resource
<set>
<if test="name != null">
name = #{name},
</if>
<if test="sort != null">
sort = #{sort},
</if>
<if test="displayName != null">
display_name = #{displayName},
</if>
<if test="pid != null">
pid = #{pid},
</if>
<if test="handler != null">
handler = #{handler},
</if>
<if test="deleted != null">
deleted = #{deleted}
</if>
</set>
WHERE id = #{id}
</update>
</mapper> </mapper>

View File

@ -7,6 +7,15 @@ import java.util.Date;
*/ */
public class BaseDO { 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 Date updateTime;
private Boolean deleted; /**
* 是否删除
*/
private Integer deleted;
public Date getCreateTime() { public Date getCreateTime() {
return createTime; return createTime;
@ -35,11 +47,11 @@ public class BaseDO {
return this; return this;
} }
public Boolean getDeleted() { public Integer getDeleted() {
return deleted; return deleted;
} }
public BaseDO setDeleted(Boolean deleted) { public BaseDO setDeleted(Integer deleted) {
this.deleted = deleted; this.deleted = deleted;
return this; return this;
} }