- admin 模块重命名 system 模块

This commit is contained in:
sin
2019-05-03 17:20:18 +08:00
parent 2dff5d63a9
commit fb96022676
124 changed files with 25 additions and 26 deletions

View File

@@ -0,0 +1,14 @@
package cn.iocoder.mall.admin.config;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration
@MapperScan("cn.iocoder.mall.admin.dao") // 扫描对应的 Mapper 接口
@EnableTransactionManagement(proxyTargetClass = true) // 启动事务管理。为什么使用 proxyTargetClass 参数,参见 https://blog.csdn.net/huang_550/article/details/76492600
public class DatabaseConfiguration {
// 数据源,使用 HikariCP
}

View File

@@ -0,0 +1,26 @@
package cn.iocoder.mall.admin.config;
import cn.iocoder.common.framework.util.ServiceExceptionUtil;
import cn.iocoder.mall.admin.api.constant.AdminErrorCodeEnum;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.EventListener;
@Configuration
public class ServiceExceptionConfiguration {
@EventListener(ApplicationReadyEvent.class) // 可参考 https://www.cnblogs.com/ssslinppp/p/7607509.html
public void initMessages() {
// 从 service_exception_message.properties 加载错误码的方案
// Properties properties;
// try {
// properties = PropertiesLoaderUtils.loadAllProperties("classpath:service_exception_message.properties");
// } catch (IOException e) {
// throw new RuntimeException(e);
// }
for (AdminErrorCodeEnum item : AdminErrorCodeEnum.values()) {
ServiceExceptionUtil.put(item.getCode(), item.getMessage());
}
}
}

View File

@@ -0,0 +1,17 @@
package cn.iocoder.mall.admin.convert;
import cn.iocoder.mall.admin.api.dto.AdminAccessLogAddDTO;
import cn.iocoder.mall.admin.dataobject.AdminAccessLogDO;
import org.mapstruct.Mapper;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
@Mapper
public interface AdminAccessLogConvert {
AdminAccessLogConvert INSTANCE = Mappers.getMapper(AdminAccessLogConvert.class);
@Mappings({})
AdminAccessLogDO convert(AdminAccessLogAddDTO adminAccessLogAddDTO);
}

View File

@@ -0,0 +1,30 @@
package cn.iocoder.mall.admin.convert;
import cn.iocoder.mall.admin.api.bo.AdminBO;
import cn.iocoder.mall.admin.api.dto.AdminAddDTO;
import cn.iocoder.mall.admin.api.dto.AdminUpdateDTO;
import cn.iocoder.mall.admin.dataobject.AdminDO;
import org.mapstruct.Mapper;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
import java.util.List;
@Mapper
public interface AdminConvert {
AdminConvert INSTANCE = Mappers.getMapper(AdminConvert.class);
@Mappings({})
AdminBO convert(AdminDO adminDO);
@Mappings({})
AdminDO convert(AdminAddDTO adminAddDTO);
@Mappings({})
AdminDO convert(AdminUpdateDTO adminUpdateDTO);
@Mappings({})
List<AdminBO> convert(List<AdminDO> adminBOs);
}

View File

@@ -0,0 +1,25 @@
package cn.iocoder.mall.admin.convert;
import cn.iocoder.mall.admin.api.bo.DataDictBO;
import cn.iocoder.mall.admin.api.dto.DataDictAddDTO;
import cn.iocoder.mall.admin.api.dto.DataDictUpdateDTO;
import cn.iocoder.mall.admin.dataobject.DataDictDO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;
@Mapper
public interface DataDictConvert {
DataDictConvert INSTANCE = Mappers.getMapper(DataDictConvert.class);
DataDictDO convert(DataDictAddDTO dataDictAddDTO);
DataDictDO convert(DataDictUpdateDTO dataDictUpdateDTO);
DataDictBO convert(DataDictDO dataDictDO);
List<DataDictBO> convert(List<DataDictDO> dataDictDOs);
}

View File

@@ -0,0 +1,38 @@
package cn.iocoder.mall.admin.convert;
import cn.iocoder.mall.admin.api.bo.OAuth2AccessTokenBO;
import cn.iocoder.mall.admin.api.bo.OAuth2AuthenticationBO;
import cn.iocoder.mall.admin.dataobject.AdminRoleDO;
import cn.iocoder.mall.admin.dataobject.OAuth2AccessTokenDO;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
import java.util.List;
import java.util.stream.Collectors;
@Mapper
public interface OAuth2Convert {
OAuth2Convert INSTANCE = Mappers.getMapper(OAuth2Convert.class);
@Mappings({
@Mapping(source = "id", target = "accessToken")
})
OAuth2AccessTokenBO convertToAccessToken(OAuth2AccessTokenDO oauth2AccessTokenDO);
default OAuth2AccessTokenBO convertToAccessTokenWithExpiresIn(OAuth2AccessTokenDO oauth2AccessTokenDO) {
return this.convertToAccessToken(oauth2AccessTokenDO)
.setExpiresIn(Math.max((int) ((oauth2AccessTokenDO.getExpiresTime().getTime() - System.currentTimeMillis()) / 1000), 0));
}
@Mappings({})
OAuth2AuthenticationBO convertToAuthentication(OAuth2AccessTokenDO oauth2AccessTokenDO);
default OAuth2AuthenticationBO convertToAuthentication(OAuth2AccessTokenDO oauth2AccessTokenDO, List<AdminRoleDO> adminRoleDOs) {
return convertToAuthentication(oauth2AccessTokenDO)
.setRoleIds(adminRoleDOs.stream().map(AdminRoleDO::getRoleId).collect(Collectors.toSet()));
}
}

View File

@@ -0,0 +1,30 @@
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;
import org.mapstruct.factory.Mappers;
import java.util.List;
@Mapper
public interface ResourceConvert {
ResourceConvert INSTANCE = Mappers.getMapper(ResourceConvert.class);
@Mappings({})
ResourceBO convert(ResourceDO resourceDO);
@Mappings({})
List<ResourceBO> convert(List<ResourceDO> resourceDOs);
@Mappings({})
ResourceDO convert(ResourceAddDTO resourceAddDTO);
@Mappings({})
ResourceDO convert(ResourceUpdateDTO resourceUpdateDTO);
}

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

@@ -0,0 +1,11 @@
package cn.iocoder.mall.admin.dao;
import cn.iocoder.mall.admin.dataobject.AdminAccessLogDO;
import org.springframework.stereotype.Repository;
@Repository
public interface AdminAccessLogMapper {
void insert(AdminAccessLogDO entity);
}

View File

@@ -0,0 +1,26 @@
package cn.iocoder.mall.admin.dao;
import cn.iocoder.mall.admin.dataobject.AdminDO;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface AdminMapper {
AdminDO selectById(@Param("id") Integer id);
AdminDO selectByUsername(@Param("username") String username);
List<AdminDO> selectListByNicknameLike(@Param("nickname") String nickname,
@Param("offset") Integer offset,
@Param("limit") Integer limit);
Integer selectCountByNicknameLike(@Param("nickname") String nickname);
void insert(AdminDO admin);
int update(AdminDO admin);
}

View File

@@ -0,0 +1,20 @@
package cn.iocoder.mall.admin.dao;
import cn.iocoder.mall.admin.dataobject.AdminRoleDO;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface AdminRoleMapper {
List<AdminRoleDO> selectByAdminId(@Param("adminId") Integer adminId);
int updateToDeletedByAdminId(@Param("adminId") Integer adminId);
int updateToDeletedByRoleId(@Param("roleId") Integer roleId);
void insertList(@Param("adminRoleDOs") List<AdminRoleDO> adminRoleDOs);
}

View File

@@ -0,0 +1,35 @@
package cn.iocoder.mall.admin.dao;
import cn.iocoder.mall.admin.dataobject.DataDictDO;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
import java.util.Collection;
import java.util.List;
@Repository
public interface DataDictMapper {
DataDictDO selectById(@Param("id") Integer id);
DataDictDO selectByEnumValueAndValue(
@Param("enumValue") String enumValue,
@Param("value") String value
);
List<DataDictDO> selectByEnumValueAndValues(
@Param("enumValue") String enumValue,
@Param("values") Collection<String> values
);
List<DataDictDO> selectByEnumValue(
@Param("enumValue") String enumValue
);
List<DataDictDO> selectList();
void insert(DataDictDO dataDict);
int update(DataDictDO dataDict);
}

View File

@@ -0,0 +1,16 @@
package cn.iocoder.mall.admin.dao;
import cn.iocoder.mall.admin.dataobject.OAuth2AccessTokenDO;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
@Repository
public interface OAuth2AccessTokenMapper {
void insert(OAuth2AccessTokenDO entity);
OAuth2AccessTokenDO selectByTokenId(@Param("id") String id);
int updateToInvalidByAdminId(@Param("adminId") Integer adminId);
}

View File

@@ -0,0 +1,14 @@
package cn.iocoder.mall.admin.dao;
import cn.iocoder.mall.admin.dataobject.OAuth2RefreshTokenDO;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
@Repository
public interface OAuth2RefreshTokenMapper {
void insert(OAuth2RefreshTokenDO entity);
int updateToInvalidByAdminId(@Param("adminId") Integer adminId);
}

View File

@@ -0,0 +1,33 @@
package cn.iocoder.mall.admin.dao;
import cn.iocoder.mall.admin.dataobject.ResourceDO;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Set;
@Repository
public interface ResourceMapper {
ResourceDO selectByTypeAndHandler(@Param("type") Integer type,
@Param("handler") String handler);
List<ResourceDO> selectListByTypeAndRoleIds(@Param("type") Integer type,
@Param("roleIds") Set<Integer> roleIds);
List<ResourceDO> selectListByType(@Param("type") Integer type);
ResourceDO selectByName(@Param("name") String name);
ResourceDO selectById(@Param("id") Integer id);
List<ResourceDO> selectListByIds(@Param("ids") Set<Integer> ids);
void insert(ResourceDO resource);
int update(ResourceDO resource);
int selectCountByPid(@Param("pid") Integer pid);
}

View File

@@ -0,0 +1,29 @@
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;
import java.util.Set;
@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);
List<RoleDO> selectListByIds(@Param("ids") Set<Integer> ids);
List<RoleDO> selectList();
}

View File

@@ -0,0 +1,22 @@
package cn.iocoder.mall.admin.dao;
import cn.iocoder.mall.admin.dataobject.RoleResourceDO;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface RoleResourceMapper {
int insertList(@Param("roleResources") List<RoleResourceDO> resourceDOs);
List<RoleResourceDO> selectByResourceHandler(@Param("resourceHandler") String resourceHandler);
List<RoleResourceDO> selectByResourceId(@Param("resourceId") Integer resourceId);
int updateToDeletedByResourceId(@Param("resourceId") Integer resourceId);
int updateToDeletedByRoleId(@Param("roleId") Integer roleId);
}

View File

@@ -0,0 +1,55 @@
package cn.iocoder.mall.admin.dataobject;
import cn.iocoder.common.framework.dataobject.DeletableDO;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.Date;
/**
* 管理员访问日志 DO
*/
@Data
@Accessors(chain = true)
public class AdminAccessLogDO extends DeletableDO {
/**
* 编号
*/
private Integer id;
/**
* 管理员编号.
*
* 当管理员为空时该值为0
*/
private Integer adminId;
/**
* 访问地址
*/
private String uri;
/**
* 参数
*/
private String queryString;
/**
* http 方法
*/
private String method;
/**
* userAgent
*/
private String userAgent;
/**
* ip
*/
private String ip;
/**
* 请求时间
*/
private Date startTime;
/**
* 响应时长 -- 毫秒级
*/
private Integer responseTime;
}

View File

@@ -0,0 +1,37 @@
package cn.iocoder.mall.admin.dataobject;
import cn.iocoder.common.framework.dataobject.DeletableDO;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 管理员实体
*/
@Data
@Accessors(chain = true)
public class AdminDO extends DeletableDO {
/**
* 管理员编号
*/
private Integer id;
/**
* 登陆账号
*/
private String username;
/**
* 昵称
*/
private String nickname;
/**
* 密码
*
* TODO 芋艿 暂时最简单的 MD5
*/
private String password;
/**
* 账号状态
*/
private Integer status;
}

View File

@@ -0,0 +1,27 @@
package cn.iocoder.mall.admin.dataobject;
import cn.iocoder.common.framework.dataobject.DeletableDO;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* {@link AdminDO} 和 {@link RoleDO} 的关联表
*/
@Data
@Accessors(chain = true)
public class AdminRoleDO extends DeletableDO {
/**
* 编号
*/
private Integer id;
/**
* 管理员编号(外键:{@link AdminDO}
*/
private Integer adminId;
/**
* 角色编号(外键:{@link RoleDO}
*/
private Integer roleId;
}

View File

@@ -0,0 +1,45 @@
package cn.iocoder.mall.admin.dataobject;
import cn.iocoder.common.framework.dataobject.DeletableDO;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 数据字典
*
* 使用 {@link #enumValue} 作为聚合。例如说:
*
* enumValue gender 性别
* value1 男
* value2 女
*/
@Data
@Accessors(chain = true)
public class DataDictDO extends DeletableDO {
/**
* 编号
*/
private Integer id;
/**
* 大类枚举值
*/
private String enumValue;
/**
* 小类数值
*/
private String value;
/**
* 展示名
*/
private String displayName;
/**
* 排序值
*/
private Integer sort;
/**
* 备注
*/
private String memo;
}

View File

@@ -0,0 +1,94 @@
package cn.iocoder.mall.admin.dataobject;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.Date;
/**
* OAUTH2 AccessToken
*/
@Data
@Accessors(chain = true)
public class OAuth2AccessTokenDO {
/**
* 访问令牌
*/
private String id;
/**
* 刷新令牌
*/
private String refreshToken;
/**
* 管理员比那好
*/
private Integer adminId;
/**
* 过期时间
*/
private Date expiresTime;
/**
* 是否有效
*/
private Boolean valid;
/**
* 创建时间
*/
private Date createTime;
public String getId() {
return id;
}
public OAuth2AccessTokenDO setId(String id) {
this.id = id;
return this;
}
public String getRefreshToken() {
return refreshToken;
}
public OAuth2AccessTokenDO setRefreshToken(String refreshToken) {
this.refreshToken = refreshToken;
return this;
}
public Integer getAdminId() {
return adminId;
}
public OAuth2AccessTokenDO setAdminId(Integer adminId) {
this.adminId = adminId;
return this;
}
public Date getExpiresTime() {
return expiresTime;
}
public OAuth2AccessTokenDO setExpiresTime(Date expiresTime) {
this.expiresTime = expiresTime;
return this;
}
public Boolean getValid() {
return valid;
}
public OAuth2AccessTokenDO setValid(Boolean valid) {
this.valid = valid;
return this;
}
public Date getCreateTime() {
return createTime;
}
public OAuth2AccessTokenDO setCreateTime(Date createTime) {
this.createTime = createTime;
return this;
}
}

View File

@@ -0,0 +1,38 @@
package cn.iocoder.mall.admin.dataobject;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.Date;
/**
* 刷新令牌
*
* idx_uid
*/
@Data
@Accessors(chain = true)
public class OAuth2RefreshTokenDO {
/**
* 刷新令牌
*/
private String id;
/**
* 用户编号
*/
private Integer adminId;
/**
* 是否有效
*/
private Boolean valid;
/**
* 过期时间
*/
private Date expiresTime;
/**
* 创建时间
*/
private Date createTime;
}

View File

@@ -0,0 +1,65 @@
package cn.iocoder.mall.admin.dataobject;
import cn.iocoder.common.framework.dataobject.DeletableDO;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.Date;
/**
* 资源实体
*/
@Data
@Accessors(chain = true)
public class ResourceDO extends DeletableDO {
/**
* 资源类型 - 菜单
*/
@Deprecated
public static final Integer TYPE_MENU = 1;
/**
* 资源类型 - 操作
*
* 例如,按钮。
*/
@Deprecated
public static final Integer TYPE_OPERATION = 2;
/**
* 资源编号
*/
private Integer id;
/**
* 资源名字(标识)
*/
private String name;
/**
* 资源类型
*/
private Integer type;
/**
* 排序
*/
private Integer sort;
/**
* 展示名
*/
private String displayName;
/**
* 添加时间
*/
private Date createTime;
/**
* 父级资源编号(外键:{@link ResourceDO#id})
*/
private Integer pid;
/**
* 操作
*
* 当资源类型为【菜单】时handler 配置为界面 URL ,或者前端组件名
* 当资源类型为【URL】时handler 配置为后端 URL 。举个例子,如果有一个「创建管理员」的表单,那么前端界面上的按钮可以根据这个 url 判断是否展示,后端接收到该 url 的请求时会判断是否有权限。
*/
private String handler;
}

View File

@@ -0,0 +1,23 @@
package cn.iocoder.mall.admin.dataobject;
import cn.iocoder.common.framework.dataobject.DeletableDO;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 角色实体
*/
@Data
@Accessors(chain = true)
public class RoleDO extends DeletableDO {
/**
* 角色编号
*/
private Integer id;
/**
* 角色名
*/
private String name;
}

View File

@@ -0,0 +1,27 @@
package cn.iocoder.mall.admin.dataobject;
import cn.iocoder.common.framework.dataobject.DeletableDO;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* {@link RoleDO} 和 {@link ResourceDO} 的关联表
*/
@Data
@Accessors(chain = true)
public class RoleResourceDO extends DeletableDO {
/**
* 编号
*/
private Integer id;
/**
* 角色编号(外键:{@link RoleDO}
*/
private Integer roleId;
/**
* 资源编号(外键:{@link ResourceDO}
*/
private Integer resourceId;
}

View File

@@ -0,0 +1,56 @@
package cn.iocoder.mall.admin.service;
import cn.iocoder.common.framework.util.StringUtil;
import cn.iocoder.common.framework.vo.CommonResult;
import cn.iocoder.mall.admin.api.AdminAccessLogService;
import cn.iocoder.mall.admin.api.dto.AdminAccessLogAddDTO;
import cn.iocoder.mall.admin.convert.AdminAccessLogConvert;
import cn.iocoder.mall.admin.dao.AdminAccessLogMapper;
import cn.iocoder.mall.admin.dataobject.AdminAccessLogDO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Date;
@Service
@org.apache.dubbo.config.annotation.Service(validation = "true")
public class AdminAccessLogServiceImpl implements AdminAccessLogService {
/**
* 请求参数最大长度。
*/
private static final Integer QUERY_STRING_MAX_LENGTH = 4096;
/**
* 请求地址最大长度。
*/
private static final Integer URI_MAX_LENGTH = 4096;
/**
* User-Agent 最大长度。
*/
private static final Integer USER_AGENT_MAX_LENGTH = 1024;
@Autowired
private AdminAccessLogMapper adminAccessLogMapper;
@Override
public CommonResult<Boolean> addAdminAccessLog(AdminAccessLogAddDTO adminAccessLogAddDTO) {
// 创建 AdminAccessLogDO
AdminAccessLogDO accessLog = AdminAccessLogConvert.INSTANCE.convert(adminAccessLogAddDTO);
accessLog.setCreateTime(new Date());
// 截取最大长度
if (accessLog.getUri().length() > URI_MAX_LENGTH) {
accessLog.setUri(StringUtil.substring(accessLog.getUri(), URI_MAX_LENGTH));
}
if (accessLog.getQueryString().length() > QUERY_STRING_MAX_LENGTH) {
accessLog.setQueryString(StringUtil.substring(accessLog.getQueryString(), QUERY_STRING_MAX_LENGTH));
}
if (accessLog.getUserAgent().length() > USER_AGENT_MAX_LENGTH) {
accessLog.setUserAgent(StringUtil.substring(accessLog.getUserAgent(), USER_AGENT_MAX_LENGTH));
}
// 插入
adminAccessLogMapper.insert(accessLog);
// 返回成功
return CommonResult.success(true);
}
}

View File

@@ -0,0 +1,203 @@
package cn.iocoder.mall.admin.service;
import cn.iocoder.common.framework.constant.CommonStatusEnum;
import cn.iocoder.common.framework.constant.DeletedStatusEnum;
import cn.iocoder.common.framework.util.ServiceExceptionUtil;
import cn.iocoder.common.framework.vo.CommonResult;
import cn.iocoder.mall.admin.api.AdminService;
import cn.iocoder.mall.admin.api.bo.AdminBO;
import cn.iocoder.mall.admin.api.bo.AdminPageBO;
import cn.iocoder.mall.admin.api.constant.AdminConstants;
import cn.iocoder.mall.admin.api.constant.AdminErrorCodeEnum;
import cn.iocoder.mall.admin.api.dto.AdminAddDTO;
import cn.iocoder.mall.admin.api.dto.AdminPageDTO;
import cn.iocoder.mall.admin.api.dto.AdminUpdateDTO;
import cn.iocoder.mall.admin.convert.AdminConvert;
import cn.iocoder.mall.admin.dao.AdminMapper;
import cn.iocoder.mall.admin.dao.AdminRoleMapper;
import cn.iocoder.mall.admin.dataobject.AdminDO;
import cn.iocoder.mall.admin.dataobject.AdminRoleDO;
import cn.iocoder.mall.admin.dataobject.RoleDO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
@Service
@org.apache.dubbo.config.annotation.Service(validation = "true")
public class AdminServiceImpl implements AdminService {
@Autowired
private AdminMapper adminMapper;
@Autowired
private AdminRoleMapper adminRoleMapper;
@Autowired
private OAuth2ServiceImpl oAuth2Service;
@Autowired
private RoleServiceImpl roleService;
public CommonResult<AdminDO> validAdmin(String username, String password) {
AdminDO admin = adminMapper.selectByUsername(username);
// 账号不存在
if (admin == null) {
return ServiceExceptionUtil.error(AdminErrorCodeEnum.ADMIN_USERNAME_NOT_REGISTERED.getCode());
}
// 密码不正确
if (encodePassword(password).equals(admin.getPassword())) {
return ServiceExceptionUtil.error(AdminErrorCodeEnum.ADMIN_PASSWORD_ERROR.getCode());
}
// 账号被禁用
if (CommonStatusEnum.DISABLE.getValue().equals(admin.getStatus())) {
return ServiceExceptionUtil.error(AdminErrorCodeEnum.ADMIN_IS_DISABLE.getCode());
}
// 校验成功,返回管理员。并且,去掉一些非关键字段,考虑安全性。
admin.setPassword(null);
admin.setStatus(null);
return CommonResult.success(admin);
}
public List<AdminRoleDO> getAdminRoles(Integer adminId) {
return adminRoleMapper.selectByAdminId(adminId);
}
@Override
public CommonResult<AdminPageBO> getAdminPage(AdminPageDTO adminPageDTO) {
AdminPageBO adminPage = new AdminPageBO();
// 查询分页数据
int offset = (adminPageDTO.getPageNo() - 1) * adminPageDTO.getPageSize();
adminPage.setList(AdminConvert.INSTANCE.convert(adminMapper.selectListByNicknameLike(adminPageDTO.getNickname(),
offset, adminPageDTO.getPageSize())));
// 查询分页总数
adminPage.setTotal(adminMapper.selectCountByNicknameLike(adminPageDTO.getNickname()));
return CommonResult.success(adminPage);
}
@Override
public CommonResult<AdminBO> addAdmin(Integer adminId, AdminAddDTO adminAddDTO) {
// 校验账号唯一
if (adminMapper.selectByUsername(adminAddDTO.getUsername()) != null) {
return ServiceExceptionUtil.error(AdminErrorCodeEnum.ADMIN_USERNAME_EXISTS.getCode());
}
// 保存到数据库
AdminDO admin = AdminConvert.INSTANCE.convert(adminAddDTO)
.setPassword(encodePassword(adminAddDTO.getPassword())) // 加密密码
.setStatus(CommonStatusEnum.ENABLE.getValue());
admin.setCreateTime(new Date());
admin.setDeleted(DeletedStatusEnum.DELETED_NO.getValue());
adminMapper.insert(admin);
// TODO 插入操作日志
// 返回成功
return CommonResult.success(AdminConvert.INSTANCE.convert(admin));
}
@Override
public CommonResult<Boolean> updateAdmin(Integer adminId, AdminUpdateDTO adminUpdateDTO) {
// 校验账号存在
if (adminMapper.selectById(adminUpdateDTO.getId()) == null) {
return ServiceExceptionUtil.error(AdminErrorCodeEnum.ADMIN_USERNAME_NOT_REGISTERED.getCode());
}
// 校验账号唯一
AdminDO usernameAdmin = adminMapper.selectByUsername(adminUpdateDTO.getUsername());
if (usernameAdmin != null && !usernameAdmin.getId().equals(adminUpdateDTO.getId())) {
return ServiceExceptionUtil.error(AdminErrorCodeEnum.ADMIN_USERNAME_EXISTS.getCode());
}
// 更新到数据库
AdminDO updateAdmin = AdminConvert.INSTANCE.convert(adminUpdateDTO);
adminMapper.update(updateAdmin);
// TODO 插入操作日志
// 返回成功
return CommonResult.success(true);
}
@Override
@Transactional
public CommonResult<Boolean> updateAdminStatus(Integer adminId, Integer updateAdminId, Integer status) {
// 校验账号存在
AdminDO admin = adminMapper.selectById(updateAdminId);
if (admin == null) {
return ServiceExceptionUtil.error(AdminErrorCodeEnum.ADMIN_USERNAME_NOT_REGISTERED.getCode());
}
if (AdminConstants.USERNAME_ADMIN.equals(admin.getUsername())) {
return ServiceExceptionUtil.error(AdminErrorCodeEnum.ADMIN_ADMIN_STATUS_CAN_NOT_UPDATE.getCode());
}
// 如果状态相同,则返回错误
if (status.equals(admin.getStatus())) {
return ServiceExceptionUtil.error(AdminErrorCodeEnum.ADMIN_STATUS_EQUALS.getCode());
}
// 更新管理员状态
AdminDO updateAdmin = new AdminDO().setId(updateAdminId).setStatus(status);
adminMapper.update(updateAdmin);
// 如果是关闭管理员,则标记 token 失效。否则,管理员还可以继续蹦跶
if (CommonStatusEnum.DISABLE.getValue().equals(status)) {
oAuth2Service.removeToken(updateAdminId);
}
// TODO 插入操作日志
// 返回成功
return CommonResult.success(true);
}
@Override
@Transactional
public CommonResult<Boolean> deleteAdmin(Integer adminId, Integer updateAdminId) {
// 校验账号存在
AdminDO admin = adminMapper.selectById(updateAdminId);
if (admin == null) {
return ServiceExceptionUtil.error(AdminErrorCodeEnum.ADMIN_USERNAME_NOT_REGISTERED.getCode());
}
// 只有禁用的账号才可以删除
if (CommonStatusEnum.ENABLE.getValue().equals(admin.getStatus())) {
return ServiceExceptionUtil.error(AdminErrorCodeEnum.ADMIN_DELETE_ONLY_DISABLE.getCode());
}
// 标记删除 AdminDO
AdminDO updateAdmin = new AdminDO().setId(updateAdminId);
updateAdmin.setDeleted(DeletedStatusEnum.DELETED_YES.getValue());
adminMapper.update(updateAdmin);
// 标记删除 AdminRole
adminRoleMapper.updateToDeletedByAdminId(updateAdminId);
// TODO 插入操作日志
// 返回成功
return CommonResult.success(true);
}
@Override
@Transactional
public CommonResult<Boolean> assignRole(Integer adminId, Integer updateAdminId, Set<Integer> roleIds) {
// 校验账号存在
AdminDO admin = adminMapper.selectById(updateAdminId);
if (admin == null) {
return ServiceExceptionUtil.error(AdminErrorCodeEnum.ADMIN_USERNAME_NOT_REGISTERED.getCode());
}
// 校验是否有不存在的角色
List<RoleDO> roles = roleService.getRoles(roleIds);
if (roles.size() != roleIds.size()) {
return ServiceExceptionUtil.error(AdminErrorCodeEnum.ROLE_ASSIGN_RESOURCE_NOT_EXISTS.getCode());
}
// TODO 芋艿,这里先简单实现。即方式是,删除老的分配的角色关系,然后添加新的分配的角色关系
// 标记管理员角色源关系都为删除
adminRoleMapper.updateToDeletedByAdminId(updateAdminId);
// 创建 RoleResourceDO 数组,并插入到数据库
if (!roleIds.isEmpty()) {
List<AdminRoleDO> adminRoleDOs = roleIds.stream().map(roleId -> {
AdminRoleDO roleResource = new AdminRoleDO().setAdminId(updateAdminId).setRoleId(roleId);
roleResource.setCreateTime(new Date());
roleResource.setDeleted(DeletedStatusEnum.DELETED_NO.getValue());
return roleResource;
}).collect(Collectors.toList());
adminRoleMapper.insertList(adminRoleDOs);
}
// TODO 插入操作日志
// 返回成功
return CommonResult.success(true);
}
private String encodePassword(String password) {
return DigestUtils.md5DigestAsHex(password.getBytes());
}
}

View File

@@ -0,0 +1,114 @@
package cn.iocoder.mall.admin.service;
import cn.iocoder.common.framework.constant.DeletedStatusEnum;
import cn.iocoder.common.framework.util.ServiceExceptionUtil;
import cn.iocoder.common.framework.vo.CommonResult;
import cn.iocoder.mall.admin.api.DataDictService;
import cn.iocoder.mall.admin.api.bo.DataDictBO;
import cn.iocoder.mall.admin.api.constant.AdminErrorCodeEnum;
import cn.iocoder.mall.admin.api.dto.DataDictAddDTO;
import cn.iocoder.mall.admin.api.dto.DataDictUpdateDTO;
import cn.iocoder.mall.admin.convert.DataDictConvert;
import cn.iocoder.mall.admin.dao.DataDictMapper;
import cn.iocoder.mall.admin.dataobject.DataDictDO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* 数据字典 Service
*/
@Service
@org.apache.dubbo.config.annotation.Service(validation = "true")
public class DataDictServiceImpl implements DataDictService {
@Autowired
private DataDictMapper dataDictMapper;
@Override
public CommonResult<List<DataDictBO>> selectDataDictList() {
List<DataDictDO> dataDicts = dataDictMapper.selectList();
return CommonResult.success(DataDictConvert.INSTANCE.convert(dataDicts));
}
@Override
public CommonResult<DataDictBO> addDataDict(Integer adminId, DataDictAddDTO dataDictAddDTO) {
// 校验数据字典重复
if (dataDictMapper.selectByEnumValueAndValue(dataDictAddDTO.getEnumValue(), dataDictAddDTO.getValue()) != null) {
return ServiceExceptionUtil.error(AdminErrorCodeEnum.DATA_DICT_EXISTS.getCode());
}
// 保存到数据库
DataDictDO dataDict = DataDictConvert.INSTANCE.convert(dataDictAddDTO);
dataDict.setCreateTime(new Date());
dataDict.setDeleted(DeletedStatusEnum.DELETED_NO.getValue());
dataDictMapper.insert(dataDict);
// TODO 插入操作日志
// 返回成功
return CommonResult.success(DataDictConvert.INSTANCE.convert(dataDict));
}
@Override
public CommonResult<Boolean> updateDataDict(Integer adminId, DataDictUpdateDTO dataDictUpdateDTO) {
// 校验数据字典不存在
DataDictDO existsDataDict = dataDictMapper.selectById(dataDictUpdateDTO.getId());
if (existsDataDict == null) {
return ServiceExceptionUtil.error(AdminErrorCodeEnum.DATA_DICT_NOT_EXISTS.getCode());
}
// 校验数据字典重复
DataDictDO duplicateDataDict = dataDictMapper.selectByEnumValueAndValue(existsDataDict.getEnumValue(), dataDictUpdateDTO.getValue());
if (duplicateDataDict != null && !duplicateDataDict.getId().equals(dataDictUpdateDTO.getId())) {
return ServiceExceptionUtil.error(AdminErrorCodeEnum.DATA_DICT_EXISTS.getCode());
}
// 更新到数据库
DataDictDO updateDataDict = DataDictConvert.INSTANCE.convert(dataDictUpdateDTO);
dataDictMapper.update(updateDataDict);
// TODO 插入操作日志
// 返回成功
return CommonResult.success(true);
}
// 一般情况下,不要删除数据字典。
// 因为,业务数据正在使用该数据字典,删除后,可能有不可预知的问题。
@Override
public CommonResult<Boolean> deleteDataDict(Integer adminId, Integer dataDictId) {
// 校验数据字典不存在
DataDictDO existsDataDict = dataDictMapper.selectById(dataDictId);
if (existsDataDict == null) {
return ServiceExceptionUtil.error(AdminErrorCodeEnum.DATA_DICT_NOT_EXISTS.getCode());
}
// 更新到数据库
DataDictDO updateDataDict = new DataDictDO().setId(dataDictId);
updateDataDict.setDeleted(DeletedStatusEnum.DELETED_YES.getValue());
dataDictMapper.update(updateDataDict);
// TODO 插入操作日志
// 返回成功
return CommonResult.success(true);
}
@Override
public CommonResult<DataDictBO> getDataDict(String dictKey, Object dictValue) {
DataDictDO dataDictDO = dataDictMapper.selectByEnumValueAndValue(dictKey, String.valueOf(dictValue));
DataDictBO dataDictBO = DataDictConvert.INSTANCE.convert(dataDictDO);
return CommonResult.success(dataDictBO);
}
@Override
public CommonResult<List<DataDictBO>> getDataDict(String dictKey) {
List<DataDictDO> dataDictDOList = dataDictMapper.selectByEnumValue(dictKey);
List<DataDictBO> dataDictBOList = DataDictConvert.INSTANCE.convert(dataDictDOList);
return CommonResult.success(dataDictBOList);
}
@Override
public CommonResult<List<DataDictBO>> getDataDictList(String dictKey, Collection<?> dictValueList) {
Set<String> convertDictValueList = dictValueList.stream().map(o -> String.valueOf(o)).collect(Collectors.toSet());
List<DataDictDO> dataDictDOList = dataDictMapper.selectByEnumValueAndValues(dictKey, convertDictValueList);
List<DataDictBO> dataDictBOList = DataDictConvert.INSTANCE.convert(dataDictDOList);
return CommonResult.success(dataDictBOList);
}
}

View File

@@ -0,0 +1,145 @@
package cn.iocoder.mall.admin.service;
import cn.iocoder.common.framework.util.ServiceExceptionUtil;
import cn.iocoder.common.framework.vo.CommonResult;
import cn.iocoder.mall.admin.api.OAuth2Service;
import cn.iocoder.mall.admin.api.bo.OAuth2AccessTokenBO;
import cn.iocoder.mall.admin.api.bo.OAuth2AuthenticationBO;
import cn.iocoder.mall.admin.api.constant.AdminErrorCodeEnum;
import cn.iocoder.mall.admin.convert.OAuth2Convert;
import cn.iocoder.mall.admin.dao.OAuth2AccessTokenMapper;
import cn.iocoder.mall.admin.dao.OAuth2RefreshTokenMapper;
import cn.iocoder.mall.admin.dataobject.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.UUID;
@Service
@org.apache.dubbo.config.annotation.Service(validation = "true")
public class OAuth2ServiceImpl implements OAuth2Service {
/**
* 访问令牌过期时间,单位:毫秒
*/
@Value("${modules.oauth2-code-service.access-token-expire-time-millis}")
private int accessTokenExpireTimeMillis;
/**
* 刷新令牌过期时间,单位:毫秒
*/
@Value("${modules.oauth2-code-service.refresh-token-expire-time-millis}")
private int refreshTokenExpireTimeMillis;
@Autowired
private AdminServiceImpl adminService;
@Autowired
private OAuth2AccessTokenMapper oauth2AccessTokenMapper;
@Autowired
private OAuth2RefreshTokenMapper oauth2RefreshTokenMapper;
@Autowired
private RoleServiceImpl roleService;
@Autowired
private ResourceServiceImpl resourceService;
@Override
@Transactional
public CommonResult<OAuth2AccessTokenBO> getAccessToken(String username, String password) {
CommonResult<AdminDO> adminResult = adminService.validAdmin(username, password);
// 校验失败,返回错误结果
if (adminResult.isError()) {
return CommonResult.error(adminResult);
}
AdminDO admin = adminResult.getData();
// 创建刷新令牌
OAuth2RefreshTokenDO oauth2RefreshTokenDO = createOAuth2RefreshToken(admin.getId());
// 创建访问令牌
OAuth2AccessTokenDO oauth2AccessTokenDO = createOAuth2AccessToken(admin.getId(), oauth2RefreshTokenDO.getId());
// 转换返回
return CommonResult.success(OAuth2Convert.INSTANCE.convertToAccessTokenWithExpiresIn(oauth2AccessTokenDO));
}
@Override
public CommonResult<OAuth2AuthenticationBO> checkToken(String accessToken) {
OAuth2AccessTokenDO accessTokenDO = oauth2AccessTokenMapper.selectByTokenId(accessToken);
if (accessTokenDO == null) { // 不存在
return ServiceExceptionUtil.error(AdminErrorCodeEnum.OAUTH_INVALID_TOKEN_NOT_FOUND.getCode());
}
if (accessTokenDO.getExpiresTime().getTime() < System.currentTimeMillis()) { // 已过期
return ServiceExceptionUtil.error(AdminErrorCodeEnum.OAUTH_INVALID_TOKEN_EXPIRED.getCode());
}
if (!accessTokenDO.getValid()) { // 无效
return ServiceExceptionUtil.error(AdminErrorCodeEnum.OAUTH_INVALID_TOKEN_INVALID.getCode());
}
// 获得管理员拥有的角色
List<AdminRoleDO> adminRoleDOs = adminService.getAdminRoles(accessTokenDO.getAdminId());
return CommonResult.success(OAuth2Convert.INSTANCE.convertToAuthentication(accessTokenDO, adminRoleDOs));
}
/**
* 移除管理员对应的 Token
*
* @param adminId 管理员编号
*/
@Transactional
public void removeToken(Integer adminId) {
// 设置 access token 失效
oauth2AccessTokenMapper.updateToInvalidByAdminId(adminId);
// 设置 refresh token 失效
oauth2RefreshTokenMapper.updateToInvalidByAdminId(adminId);
}
@Override
public CommonResult<Boolean> checkPermission(Integer adminId, Set<Integer> roleIds, String url) {
// 如果未配置该资源,说明无需权限控制。
ResourceDO resource = resourceService.getResourceByTypeAndHandler(ResourceDO.TYPE_OPERATION, url);
if (resource == null) {
return CommonResult.success(true);
}
// 资源存在,结果无角色,说明没有权限。
if (roleIds == null || roleIds.isEmpty()) {
return ServiceExceptionUtil.error(AdminErrorCodeEnum.OAUTH_INVALID_PERMISSION.getCode());
}
// 校验是否有资源对应的角色,即 RBAC 。
List<RoleResourceDO> roleResourceDOs = roleService.getRoleByResourceId(resource.getId());
for (RoleResourceDO roleResourceDO : roleResourceDOs) {
if (roleIds.contains(roleResourceDO.getRoleId())) {
return CommonResult.success(true);
}
}
// 没有权限,返回错误
return ServiceExceptionUtil.error(AdminErrorCodeEnum.OAUTH_INVALID_PERMISSION.getCode());
}
private OAuth2AccessTokenDO createOAuth2AccessToken(Integer adminId, String refreshToken) {
OAuth2AccessTokenDO accessToken = new OAuth2AccessTokenDO().setId(generateAccessToken())
.setRefreshToken(refreshToken)
.setAdminId(adminId)
.setExpiresTime(new Date(System.currentTimeMillis() + accessTokenExpireTimeMillis))
.setValid(true);
oauth2AccessTokenMapper.insert(accessToken);
return accessToken;
}
private OAuth2RefreshTokenDO createOAuth2RefreshToken(Integer adminId) {
OAuth2RefreshTokenDO refreshToken = new OAuth2RefreshTokenDO().setId(generateRefreshToken())
.setAdminId(adminId)
.setExpiresTime(new Date(System.currentTimeMillis() + refreshTokenExpireTimeMillis))
.setValid(true);
oauth2RefreshTokenMapper.insert(refreshToken);
return refreshToken;
}
private String generateAccessToken() {
return UUID.randomUUID().toString().replaceAll("-", "");
}
private String generateRefreshToken() {
return UUID.randomUUID().toString().replaceAll("-", "");
}
}

View File

@@ -0,0 +1,159 @@
package cn.iocoder.mall.admin.service;
import cn.iocoder.common.framework.constant.DeletedStatusEnum;
import cn.iocoder.common.framework.constant.SysErrorCodeEnum;
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.dao.RoleResourceMapper;
import cn.iocoder.mall.admin.dataobject.ResourceDO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Set;
@Service
@org.apache.dubbo.config.annotation.Service(validation = "true")
public class ResourceServiceImpl implements ResourceService {
@Autowired
private ResourceMapper resourceMapper;
@Autowired
private RoleResourceMapper roleResourceMapper;
public ResourceDO getResourceByTypeAndHandler(Integer type, String handler) {
return resourceMapper.selectByTypeAndHandler(type, handler);
}
@Override
public List<ResourceBO> getResourcesByTypeAndRoleIds(Integer type, Set<Integer> roleIds) {
if (roleIds == null || roleIds.isEmpty()) {
return Collections.emptyList();
}
return ResourceConvert.INSTANCE.convert(resourceMapper.selectListByTypeAndRoleIds(type, roleIds));
}
@Override
public List<ResourceBO> getResourcesByType(Integer type) {
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);
} else if (!resource.getHandler().startsWith("/")) {
resource.setHandler("/" + resource.getHandler());
}
resource.setCreateTime(new Date());
resource.setDeleted(DeletedStatusEnum.DELETED_NO.getValue());
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
@Transactional
public CommonResult<Boolean> deleteResource(Integer adminId, Integer resourceId) {
// 校验更新的资源是否存在
if (resourceMapper.selectById(resourceId) == null) {
return ServiceExceptionUtil.error(AdminErrorCodeEnum.RESOURCE_NOT_EXISTS.getCode());
}
// 校验是否还有子资源
if (resourceMapper.selectCountByPid(resourceId) > 0) {
return ServiceExceptionUtil.error(AdminErrorCodeEnum.RESOURCE_EXISTS_CHILDREN.getCode());
}
// 更新到数据库
ResourceDO resource = new ResourceDO().setId(resourceId);
resource.setDeleted(DeletedStatusEnum.DELETED_YES.getValue());
resourceMapper.update(resource);
// 删除资源关联表
roleResourceMapper.updateToDeletedByResourceId(resourceId);
// 返回成功
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) {
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

@@ -0,0 +1,163 @@
package cn.iocoder.mall.admin.service;
import cn.iocoder.common.framework.constant.DeletedStatusEnum;
import cn.iocoder.common.framework.util.CollectionUtil;
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.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.AdminRoleMapper;
import cn.iocoder.mall.admin.dao.RoleMapper;
import cn.iocoder.mall.admin.dao.RoleResourceMapper;
import cn.iocoder.mall.admin.dataobject.AdminRoleDO;
import cn.iocoder.mall.admin.dataobject.ResourceDO;
import cn.iocoder.mall.admin.dataobject.RoleDO;
import cn.iocoder.mall.admin.dataobject.RoleResourceDO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
@Service
@org.apache.dubbo.config.annotation.Service(validation = "true")
public class RoleServiceImpl implements RoleService {
@Autowired
private RoleResourceMapper roleResourceMapper;
@Autowired
private AdminRoleMapper adminRoleMapper;
@Autowired
private RoleMapper roleMapper;
@Autowired
private ResourceServiceImpl resourceService;
public List<RoleResourceDO> getRoleByResourceHandler(String resourceHandler) {
return roleResourceMapper.selectByResourceHandler(resourceHandler);
}
public List<RoleResourceDO> getRoleByResourceId(Integer 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<Set<Integer>> getRoleList(Integer adminId) {
List<AdminRoleDO> adminRoleDOs = adminRoleMapper.selectByAdminId(adminId);
return CommonResult.success(adminRoleDOs.stream().map(AdminRoleDO::getRoleId).collect(Collectors.toSet()));
}
@Override
public CommonResult<List<RoleBO>> getRoleList() {
List<RoleDO> roleList = roleMapper.selectList();
return CommonResult.success(RoleConvert.INSTANCE.convert(roleList));
}
@Override
public CommonResult<RoleBO> addRole(Integer adminId, RoleAddDTO roleAddDTO) {
// TODO 芋艿,角色名是否要唯一呢?貌似一般系统都是允许的。
// 保存到数据库
RoleDO role = RoleConvert.INSTANCE.convert(roleAddDTO);
role.setCreateTime(new Date());
role.setDeleted(DeletedStatusEnum.DELETED_NO.getValue());
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
@Transactional
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(DeletedStatusEnum.DELETED_YES.getValue());
roleMapper.update(roleDO);
// 标记删除 RoleResource
roleResourceMapper.updateToDeletedByRoleId(roleId);
// 标记删除 AdminRole
adminRoleMapper.updateToDeletedByRoleId(roleId);
// TODO 插入操作日志
// 返回成功
return CommonResult.success(true);
}
@Override
@Transactional
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());
roleResource.setDeleted(DeletedStatusEnum.DELETED_NO.getValue());
return roleResource;
}).collect(Collectors.toList());
roleResourceMapper.insertList(roleResources);
}
// TODO 插入操作日志
// 返回成功
return CommonResult.success(true);
}
public List<RoleDO> getRoles(Set<Integer> roleIds) {
if (CollectionUtil.isEmpty(roleIds)) {
return Collections.emptyList();
}
return roleMapper.selectListByIds(roleIds);
}
}