Merge remote-tracking branch 'origin/master'

This commit is contained in:
sin
2019-05-16 21:51:11 +08:00
64 changed files with 795 additions and 739 deletions

View File

@@ -1,6 +1,7 @@
package cn.iocoder.mall.admin.convert;
import cn.iocoder.common.framework.vo.PageResult;
import cn.iocoder.mall.admin.api.bo.admin.AdminAuthenticationBO;
import cn.iocoder.mall.admin.api.bo.admin.AdminBO;
import cn.iocoder.mall.admin.api.dto.admin.AdminAddDTO;
import cn.iocoder.mall.admin.api.dto.admin.AdminUpdateDTO;
@@ -21,6 +22,9 @@ public interface AdminConvert {
@Mappings({})
AdminBO convert(AdminDO adminDO);
@Mappings({})
AdminAuthenticationBO convert2(AdminDO admin);
@Mappings({})
AdminDO convert(AdminAddDTO adminAddDTO);

View File

@@ -2,6 +2,7 @@ package cn.iocoder.mall.admin.convert;
import cn.iocoder.mall.admin.api.bo.oauth2.OAuth2AccessTokenBO;
import cn.iocoder.mall.admin.api.bo.oauth2.OAuth2AuthenticationBO;
import cn.iocoder.mall.admin.api.bo.oauth2.OAuth2AuthenticationOldBO;
import cn.iocoder.mall.admin.dataobject.AdminRoleDO;
import cn.iocoder.mall.admin.dataobject.OAuth2AccessTokenDO;
import org.mapstruct.Mapper;
@@ -27,11 +28,14 @@ public interface OAuth2Convert {
.setExpiresIn(Math.max((int) ((oauth2AccessTokenDO.getExpiresTime().getTime() - System.currentTimeMillis()) / 1000), 0));
}
@Mappings({})
OAuth2AuthenticationOldBO convertToAuthenticationOld(OAuth2AccessTokenDO oauth2AccessTokenDO);
@Mappings({})
OAuth2AuthenticationBO convertToAuthentication(OAuth2AccessTokenDO oauth2AccessTokenDO);
default OAuth2AuthenticationBO convertToAuthentication(OAuth2AccessTokenDO oauth2AccessTokenDO, List<AdminRoleDO> adminRoleDOs) {
return convertToAuthentication(oauth2AccessTokenDO)
default OAuth2AuthenticationOldBO convertToAuthenticationOld(OAuth2AccessTokenDO oauth2AccessTokenDO, List<AdminRoleDO> adminRoleDOs) {
return convertToAuthenticationOld(oauth2AccessTokenDO)
.setRoleIds(adminRoleDOs.stream().map(AdminRoleDO::getRoleId).collect(Collectors.toSet()));
}

View File

@@ -12,16 +12,27 @@ import java.util.List;
@Repository
public interface AdminRoleMapper extends BaseMapper<AdminRoleDO> {
List<AdminRoleDO> selectByAdminId(@Param("adminId") Integer adminId);
default List<AdminRoleDO> selectByAdminId( Integer adminId) {
return selectList(new QueryWrapper<AdminRoleDO>().eq("admin_id", adminId));
}
default List<AdminRoleDO> selectListByAdminIds(Collection<Integer> adminIds) {
return selectList(new QueryWrapper<AdminRoleDO>().in("admin_id", adminIds));
}
int updateToDeletedByAdminId(@Param("adminId") Integer adminId);
default int deleteByAdminId(Integer adminId) {
return delete(new QueryWrapper<AdminRoleDO>().eq("admin_id", adminId));
}
int updateToDeletedByRoleId(@Param("roleId") Integer roleId);
default int deleteByRoleId(Integer roleId) {
return delete(new QueryWrapper<AdminRoleDO>().eq("role_id", roleId));
}
void insertList(@Param("adminRoleDOs") List<AdminRoleDO> adminRoleDOs);
/**
* 批量插入。因为 MyBaits Plus 的批量插入是基于 Service 实现,所以只好写 XML
*
* @param adminRoleDOs 数组
*/
int insertList(@Param("adminRoleDOs") List<AdminRoleDO> adminRoleDOs);
}

View File

@@ -1,6 +1,8 @@
package cn.iocoder.mall.admin.dao;
import cn.iocoder.mall.admin.dataobject.DataDictDO;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
@@ -8,9 +10,7 @@ import java.util.Collection;
import java.util.List;
@Repository
public interface DataDictMapper {
DataDictDO selectById(@Param("id") Integer id);
public interface DataDictMapper extends BaseMapper<DataDictDO> {
DataDictDO selectByEnumValueAndValue(
@Param("enumValue") String enumValue,
@@ -26,10 +26,9 @@ public interface DataDictMapper {
@Param("enumValue") String enumValue
);
List<DataDictDO> selectList();
default List<DataDictDO> selectList() {
return selectList(new QueryWrapper<>());
}
void insert(DataDictDO dataDict);
int update(DataDictDO dataDict);
}

View File

@@ -1,16 +1,17 @@
package cn.iocoder.mall.admin.dao;
import cn.iocoder.mall.admin.dataobject.OAuth2AccessTokenDO;
import org.apache.ibatis.annotations.Param;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.springframework.stereotype.Repository;
@Repository
public interface OAuth2AccessTokenMapper {
public interface OAuth2AccessTokenMapper extends BaseMapper<OAuth2AccessTokenDO> {
void insert(OAuth2AccessTokenDO entity);
default int updateToInvalidByAdminId(Integer adminId) {
QueryWrapper<OAuth2AccessTokenDO> query = new QueryWrapper<OAuth2AccessTokenDO>()
.eq("admin_id", adminId).eq("valid", true);
return update(new OAuth2AccessTokenDO().setValid(false), query);
}
OAuth2AccessTokenDO selectByTokenId(@Param("id") String id);
int updateToInvalidByAdminId(@Param("adminId") Integer adminId);
}
}

View File

@@ -1,14 +1,17 @@
package cn.iocoder.mall.admin.dao;
import cn.iocoder.mall.admin.dataobject.OAuth2RefreshTokenDO;
import org.apache.ibatis.annotations.Param;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.springframework.stereotype.Repository;
@Repository
public interface OAuth2RefreshTokenMapper {
public interface OAuth2RefreshTokenMapper extends BaseMapper<OAuth2RefreshTokenDO> {
void insert(OAuth2RefreshTokenDO entity);
default int updateToInvalidByAdminId(Integer adminId) {
QueryWrapper<OAuth2RefreshTokenDO> query = new QueryWrapper<OAuth2RefreshTokenDO>()
.eq("admin_id", adminId).eq("valid", true);
return update(new OAuth2RefreshTokenDO().setValid(false), query);
}
int updateToInvalidByAdminId(@Param("adminId") Integer adminId);
}
}

View File

@@ -1,6 +1,8 @@
package cn.iocoder.mall.admin.dao;
import cn.iocoder.common.framework.mybatis.QueryWrapperX;
import cn.iocoder.mall.admin.dataobject.ResourceDO;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
@@ -11,16 +13,24 @@ import java.util.Set;
@Repository
public interface ResourceMapper extends BaseMapper<ResourceDO> {
ResourceDO selectByTypeAndHandler(@Param("type") Integer type,
@Param("handler") String handler);
// TODO 芋艿,后续改造。
List<ResourceDO> selectListByTypeAndRoleIds(@Param("type") Integer type,
@Param("roleIds") Set<Integer> roleIds);
List<ResourceDO> selectListByType(@Param("type") Integer type);
default List<ResourceDO> selectListByPermission(String permission) {
return selectList(new QueryWrapperX<ResourceDO>().like("permissions", permission));
}
List<ResourceDO> selectListByIds(@Param("ids") Set<Integer> ids);
default List<ResourceDO> selectListByType(Integer type) {
return selectList(new QueryWrapperX<ResourceDO>().eqIfPresent("type", type));
}
int selectCountByPid(@Param("pid") Integer pid);
default List<ResourceDO> selectListByIds(Set<Integer> ids) {
return selectList(new QueryWrapper<ResourceDO>().in("id", ids));
}
default int selectCountByPid(Integer pid) {
return selectCount(new QueryWrapper<ResourceDO>().eq("pid", pid));
}
}

View File

@@ -9,16 +9,11 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.stereotype.Repository;
import java.util.Collection;
import java.util.List;
@Repository
public interface RoleMapper extends BaseMapper<RoleDO> {
default List<RoleDO> selectListByIds(Collection<Integer> ids) {
return selectList(new QueryWrapper<RoleDO>().in("id", ids));
}
default List<RoleDO> selectList() {
return selectList(new QueryWrapper<>());
}

View File

@@ -1,22 +1,38 @@
package cn.iocoder.mall.admin.dao;
import cn.iocoder.mall.admin.dataobject.RoleResourceDO;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
import java.util.Collection;
import java.util.List;
@Repository
public interface RoleResourceMapper {
public interface RoleResourceMapper extends BaseMapper<RoleResourceDO> {
int insertList(@Param("roleResources") List<RoleResourceDO> resourceDOs);
/**
* 批量插入。因为 MyBaits Plus 的批量插入是基于 Service 实现,所以只好写 XML
*
* @param roleResources 数组
*/
int insertList(@Param("roleResources") List<RoleResourceDO> roleResources);
List<RoleResourceDO> selectByResourceHandler(@Param("resourceHandler") String resourceHandler);
default List<RoleResourceDO> selectListByResourceId(Integer resourceId) {
return selectList(new QueryWrapper<RoleResourceDO>().eq("resource_id", resourceId));
}
List<RoleResourceDO> selectByResourceId(@Param("resourceId") Integer resourceId);
default List<RoleResourceDO> selectListByResourceId(Collection<Integer> resourceIds) {
return selectList(new QueryWrapper<RoleResourceDO>().in("resource_id", resourceIds));
}
int updateToDeletedByResourceId(@Param("resourceId") Integer resourceId);
default int deleteByResourceId(Integer resourceId) {
return delete(new QueryWrapper<RoleResourceDO>().eq("resource_id", resourceId));
}
int updateToDeletedByRoleId(@Param("roleId") Integer roleId);
default int deleteByRoleId(Integer roleId) {
return delete(new QueryWrapper<RoleResourceDO>().eq("role_id", roleId));
}
}
}

View File

@@ -1,6 +1,7 @@
package cn.iocoder.mall.admin.dataobject;
import cn.iocoder.common.framework.dataobject.DeletableDO;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.experimental.Accessors;
@@ -13,6 +14,7 @@ import lombok.experimental.Accessors;
* value1 男
* value2 女
*/
@TableName("data_dict")
@Data
@Accessors(chain = true)
public class DataDictDO extends DeletableDO {

View File

@@ -1,5 +1,9 @@
package cn.iocoder.mall.admin.dataobject;
import cn.iocoder.common.framework.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.experimental.Accessors;
@@ -8,22 +12,28 @@ import java.util.Date;
/**
* OAUTH2 AccessToken
*/
@TableName("oauth2_access_token")
@Data
@Accessors(chain = true)
public class OAuth2AccessTokenDO {
public class OAuth2AccessTokenDO extends BaseDO {
/**
* 访问令牌
*/
@TableId(type = IdType.INPUT)
private String id;
/**
* 刷新令牌
*/
private String refreshToken;
/**
* 管理员比那好
* 用户编号
*/
private Integer adminId;
private Integer userId;
/**
* 用户类型
*/
private Integer userType;
/**
* 过期时间
*/
@@ -32,63 +42,5 @@ public class OAuth2AccessTokenDO {
* 是否有效
*/
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

@@ -1,5 +1,9 @@
package cn.iocoder.mall.admin.dataobject;
import cn.iocoder.common.framework.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.experimental.Accessors;
@@ -10,18 +14,24 @@ import java.util.Date;
*
* idx_uid
*/
@TableName("oauth2_refresh_token")
@Data
@Accessors(chain = true)
public class OAuth2RefreshTokenDO {
public class OAuth2RefreshTokenDO extends BaseDO {
/**
* 刷新令牌
*/
@TableId(type = IdType.INPUT)
private String id;
/**
* 用户编号
*/
private Integer adminId;
private Integer userId;
/**
* 用户类型
*/
private Integer userType;
/**
* 是否有效
*/
@@ -30,9 +40,5 @@ public class OAuth2RefreshTokenDO {
* 过期时间
*/
private Date expiresTime;
/**
* 创建时间
*/
private Date createTime;
}

View File

@@ -1,12 +1,14 @@
package cn.iocoder.mall.admin.dataobject;
import cn.iocoder.common.framework.dataobject.DeletableDO;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* {@link RoleDO} 和 {@link ResourceDO} 的关联表
*/
@TableName("role_resource")
@Data
@Accessors(chain = true)
public class RoleResourceDO extends DeletableDO {

View File

@@ -2,16 +2,20 @@ 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.constant.UserTypeEnum;
import cn.iocoder.common.framework.util.CollectionUtil;
import cn.iocoder.common.framework.util.ServiceExceptionUtil;
import cn.iocoder.common.framework.vo.CommonResult;
import cn.iocoder.common.framework.vo.PageResult;
import cn.iocoder.mall.admin.api.AdminService;
import cn.iocoder.mall.admin.api.bo.role.RoleBO;
import cn.iocoder.mall.admin.api.bo.admin.AdminAuthenticationBO;
import cn.iocoder.mall.admin.api.bo.admin.AdminAuthorizationBO;
import cn.iocoder.mall.admin.api.bo.admin.AdminBO;
import cn.iocoder.mall.admin.api.bo.oauth2.OAuth2AccessTokenBO;
import cn.iocoder.mall.admin.api.bo.role.RoleBO;
import cn.iocoder.mall.admin.api.constant.AdminConstants;
import cn.iocoder.mall.admin.api.constant.AdminErrorCodeEnum;
import cn.iocoder.mall.admin.api.dto.admin.*;
import cn.iocoder.mall.admin.api.dto.oauth2.OAuth2CreateTokenDTO;
import cn.iocoder.mall.admin.convert.AdminConvert;
import cn.iocoder.mall.admin.dao.AdminMapper;
import cn.iocoder.mall.admin.dao.AdminRoleMapper;
@@ -39,32 +43,30 @@ public class AdminServiceImpl implements AdminService {
private AdminRoleMapper adminRoleMapper;
@Autowired
private OAuth2ServiceImpl oAuth2Service;
private OAuth2ServiceImpl oauth2Service;
@Autowired
private RoleServiceImpl roleService;
public CommonResult<AdminDO> validAdmin(String username, String password) {
AdminDO admin = adminMapper.selectByUsername(username);
@Override
public AdminAuthenticationBO authentication(AdminAuthenticationDTO adminAuthenticationDTO) {
AdminDO admin = adminMapper.selectByUsername(adminAuthenticationDTO.getUsername());
// 账号不存在
if (admin == null) {
return ServiceExceptionUtil.error(AdminErrorCodeEnum.ADMIN_USERNAME_NOT_REGISTERED.getCode());
throw ServiceExceptionUtil.exception(AdminErrorCodeEnum.ADMIN_USERNAME_NOT_REGISTERED.getCode());
}
// 密码不正确
if (encodePassword(password).equals(admin.getPassword())) {
return ServiceExceptionUtil.error(AdminErrorCodeEnum.ADMIN_PASSWORD_ERROR.getCode());
if (encodePassword(adminAuthenticationDTO.getPassword()).equals(admin.getPassword())) {
throw ServiceExceptionUtil.exception(AdminErrorCodeEnum.ADMIN_PASSWORD_ERROR.getCode());
}
// 账号被禁用
if (CommonStatusEnum.DISABLE.getValue().equals(admin.getStatus())) {
return ServiceExceptionUtil.error(AdminErrorCodeEnum.ADMIN_IS_DISABLE.getCode());
throw ServiceExceptionUtil.exception(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);
// 创建 accessToken
OAuth2AccessTokenBO accessTokenBO = oauth2Service.createToken(new OAuth2CreateTokenDTO().setUserId(admin.getId())
.setUserType(UserTypeEnum.ADMIN.getValue()));
// 转换返回
return AdminConvert.INSTANCE.convert2(admin).setToken(accessTokenBO);
}
@Override
@@ -130,7 +132,7 @@ public class AdminServiceImpl implements AdminService {
adminMapper.updateById(updateAdmin);
// 如果是关闭管理员,则标记 token 失效。否则,管理员还可以继续蹦跶
if (CommonStatusEnum.DISABLE.getValue().equals(adminUpdateStatusDTO.getStatus())) {
oAuth2Service.removeToken(adminUpdateStatusDTO.getId());
oauth2Service.removeToken(adminUpdateStatusDTO.getId());
}
// TODO 插入操作日志
// 返回成功
@@ -152,7 +154,7 @@ public class AdminServiceImpl implements AdminService {
// 标记删除 AdminDO
adminMapper.deleteById(updateAdminId); // 标记删除
// 标记删除 AdminRole
adminRoleMapper.updateToDeletedByAdminId(updateAdminId);
adminRoleMapper.deleteByAdminId(updateAdminId);
// TODO 插入操作日志
// 返回成功
return true;
@@ -202,7 +204,7 @@ public class AdminServiceImpl implements AdminService {
}
// TODO 芋艿,这里先简单实现。即方式是,删除老的分配的角色关系,然后添加新的分配的角色关系
// 标记管理员角色源关系都为删除
adminRoleMapper.updateToDeletedByAdminId(adminAssignRoleDTO.getId());
adminRoleMapper.deleteByAdminId(adminAssignRoleDTO.getId());
// 创建 RoleResourceDO 数组,并插入到数据库
if (!CollectionUtil.isEmpty(adminAssignRoleDTO.getRoleIds())) {
List<AdminRoleDO> adminRoleDOs = adminAssignRoleDTO.getRoleIds().stream().map(roleId -> {
@@ -218,6 +220,24 @@ public class AdminServiceImpl implements AdminService {
return true;
}
@Override
public AdminAuthorizationBO checkPermissions(Integer adminId, List<String> permissions) {
// 查询管理员拥有的角色关联数据
List<AdminRoleDO> adminRoleList = adminRoleMapper.selectByAdminId(adminId);
Set<Integer> adminRoleIds = CollectionUtil.convertSet(adminRoleList, AdminRoleDO::getRoleId);
// 授权校验
if (!CollectionUtil.isEmpty(permissions)) {
Map<String, List<Integer>> permissionRoleMap = roleService.getPermissionRoleMap(permissions);
for (Map.Entry<String, List<Integer>> entry : permissionRoleMap.entrySet()) {
if (!CollectionUtil.containsAny(entry.getValue(), adminRoleIds)) { // 所以有任一不满足,就验证失败,抛出异常
throw ServiceExceptionUtil.exception(AdminErrorCodeEnum.ADMIN_INVALID_PERMISSION.getCode());
}
}
}
// 返回成功
return new AdminAuthorizationBO().setId(adminId).setRoleIds(adminRoleIds);
}
private String encodePassword(String password) {
return DigestUtils.md5DigestAsHex(password.getBytes());
}

View File

@@ -31,16 +31,16 @@ public class DataDictServiceImpl implements DataDictService {
private DataDictMapper dataDictMapper;
@Override
public CommonResult<List<DataDictBO>> selectDataDictList() {
public List<DataDictBO> selectDataDictList() {
List<DataDictDO> dataDicts = dataDictMapper.selectList();
return CommonResult.success(DataDictConvert.INSTANCE.convert(dataDicts));
return DataDictConvert.INSTANCE.convert(dataDicts);
}
@Override
public CommonResult<DataDictBO> addDataDict(Integer adminId, DataDictAddDTO dataDictAddDTO) {
public DataDictBO addDataDict(Integer adminId, DataDictAddDTO dataDictAddDTO) {
// 校验数据字典重复
if (dataDictMapper.selectByEnumValueAndValue(dataDictAddDTO.getEnumValue(), dataDictAddDTO.getValue()) != null) {
return ServiceExceptionUtil.error(AdminErrorCodeEnum.DATA_DICT_EXISTS.getCode());
throw ServiceExceptionUtil.exception(AdminErrorCodeEnum.DATA_DICT_EXISTS.getCode());
}
// 保存到数据库
DataDictDO dataDict = DataDictConvert.INSTANCE.convert(dataDictAddDTO);
@@ -49,45 +49,43 @@ public class DataDictServiceImpl implements DataDictService {
dataDictMapper.insert(dataDict);
// TODO 插入操作日志
// 返回成功
return CommonResult.success(DataDictConvert.INSTANCE.convert(dataDict));
return DataDictConvert.INSTANCE.convert(dataDict);
}
@Override
public CommonResult<Boolean> updateDataDict(Integer adminId, DataDictUpdateDTO dataDictUpdateDTO) {
public Boolean updateDataDict(Integer adminId, DataDictUpdateDTO dataDictUpdateDTO) {
// 校验数据字典不存在
DataDictDO existsDataDict = dataDictMapper.selectById(dataDictUpdateDTO.getId());
if (existsDataDict == null) {
return ServiceExceptionUtil.error(AdminErrorCodeEnum.DATA_DICT_NOT_EXISTS.getCode());
throw ServiceExceptionUtil.exception(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());
throw ServiceExceptionUtil.exception(AdminErrorCodeEnum.DATA_DICT_EXISTS.getCode());
}
// 更新到数据库
DataDictDO updateDataDict = DataDictConvert.INSTANCE.convert(dataDictUpdateDTO);
dataDictMapper.update(updateDataDict);
dataDictMapper.updateById(updateDataDict);
// TODO 插入操作日志
// 返回成功
return CommonResult.success(true);
return true;
}
// 一般情况下,不要删除数据字典。
// 因为,业务数据正在使用该数据字典,删除后,可能有不可预知的问题。
@Override
public CommonResult<Boolean> deleteDataDict(Integer adminId, Integer dataDictId) {
public Boolean deleteDataDict(Integer adminId, Integer dataDictId) {
// 校验数据字典不存在
DataDictDO existsDataDict = dataDictMapper.selectById(dataDictId);
if (existsDataDict == null) {
return ServiceExceptionUtil.error(AdminErrorCodeEnum.DATA_DICT_NOT_EXISTS.getCode());
throw ServiceExceptionUtil.exception(AdminErrorCodeEnum.DATA_DICT_NOT_EXISTS.getCode());
}
// 更新到数据库
DataDictDO updateDataDict = new DataDictDO().setId(dataDictId);
updateDataDict.setDeleted(DeletedStatusEnum.DELETED_YES.getValue());
dataDictMapper.update(updateDataDict);
// 标记删除
dataDictMapper.deleteById(dataDictId);
// TODO 插入操作日志
// 返回成功
return CommonResult.success(true);
return true;
}
@Override
@@ -106,7 +104,7 @@ public class DataDictServiceImpl implements DataDictService {
@Override
public CommonResult<List<DataDictBO>> getDataDictList(String dictKey, Collection<?> dictValueList) {
Set<String> convertDictValueList = dictValueList.stream().map(o -> String.valueOf(o)).collect(Collectors.toSet());
Set<String> convertDictValueList = dictValueList.stream().map(String::valueOf).collect(Collectors.toSet());
List<DataDictDO> dataDictDOList = dataDictMapper.selectByEnumValueAndValues(dictKey, convertDictValueList);
List<DataDictBO> dataDictBOList = DataDictConvert.INSTANCE.convert(dataDictDOList);
return CommonResult.success(dataDictBOList);

View File

@@ -1,24 +1,23 @@
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.oauth2.OAuth2AccessTokenBO;
import cn.iocoder.mall.admin.api.bo.oauth2.OAuth2AuthenticationBO;
import cn.iocoder.mall.admin.api.constant.AdminErrorCodeEnum;
import cn.iocoder.mall.admin.api.constant.ResourceConstants;
import cn.iocoder.mall.admin.api.dto.oauth2.OAuth2CreateTokenDTO;
import cn.iocoder.mall.admin.api.dto.oauth2.OAuth2GetTokenDTO;
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 cn.iocoder.mall.admin.dataobject.OAuth2AccessTokenDO;
import cn.iocoder.mall.admin.dataobject.OAuth2RefreshTokenDO;
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
@@ -49,36 +48,15 @@ public class OAuth2ServiceImpl implements OAuth2Service {
@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();
public OAuth2AccessTokenBO createToken(OAuth2CreateTokenDTO oauth2CreateTokenDTO) {
Integer userId = oauth2CreateTokenDTO.getUserId();
Integer userType = oauth2CreateTokenDTO.getUserType();
// 创建刷新令牌
OAuth2RefreshTokenDO oauth2RefreshTokenDO = createOAuth2RefreshToken(admin.getId());
OAuth2RefreshTokenDO oauth2RefreshTokenDO = createOAuth2RefreshToken(userId, userType);
// 创建访问令牌
OAuth2AccessTokenDO oauth2AccessTokenDO = createOAuth2AccessToken(admin.getId(), oauth2RefreshTokenDO.getId());
OAuth2AccessTokenDO oauth2AccessTokenDO = createOAuth2AccessToken(userId, userType, 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));
return OAuth2Convert.INSTANCE.convertToAccessTokenWithExpiresIn(oauth2AccessTokenDO);
}
/**
@@ -95,40 +73,37 @@ public class OAuth2ServiceImpl implements OAuth2Service {
}
@Override
public CommonResult<Boolean> checkPermission(Integer adminId, Set<Integer> roleIds, String url) {
// 如果未配置该资源,说明无需权限控制。
ResourceDO resource = resourceService.getResourceByTypeAndHandler(ResourceConstants.TYPE_BUTTON, url);
if (resource == null) {
return CommonResult.success(true);
public OAuth2AuthenticationBO getAuthentication(OAuth2GetTokenDTO oauth2GetTokenDTO) {
OAuth2AccessTokenDO accessTokenDO = oauth2AccessTokenMapper.selectById(oauth2GetTokenDTO.getAccessToken());
if (accessTokenDO == null) { // 不存在
throw ServiceExceptionUtil.exception(AdminErrorCodeEnum.OAUTH2_INVALID_TOKEN_NOT_FOUND.getCode());
}
// 资源存在,结果无角色,说明没有权限。
if (roleIds == null || roleIds.isEmpty()) {
return ServiceExceptionUtil.error(AdminErrorCodeEnum.OAUTH_INVALID_PERMISSION.getCode());
if (accessTokenDO.getExpiresTime().getTime() < System.currentTimeMillis()) { // 已过期
throw ServiceExceptionUtil.exception(AdminErrorCodeEnum.OAUTH2_INVALID_TOKEN_EXPIRED.getCode());
}
// 校验是否有资源对应的角色,即 RBAC 。
List<RoleResourceDO> roleResourceDOs = roleService.getRoleByResourceId(resource.getId());
for (RoleResourceDO roleResourceDO : roleResourceDOs) {
if (roleIds.contains(roleResourceDO.getRoleId())) {
return CommonResult.success(true);
}
if (!accessTokenDO.getValid()) { // 无效
throw ServiceExceptionUtil.exception(AdminErrorCodeEnum.OAUTH2_INVALID_TOKEN_INVALID.getCode());
}
// 没有权限,返回错误
return ServiceExceptionUtil.error(AdminErrorCodeEnum.OAUTH_INVALID_PERMISSION.getCode());
if (!oauth2GetTokenDTO.getUserType().equals(accessTokenDO.getUserType())) {
throw ServiceExceptionUtil.exception(AdminErrorCodeEnum.OAUTH2_INVALID_TOKEN_INVALID.getCode());
}
// 转换返回
return OAuth2Convert.INSTANCE.convertToAuthentication(accessTokenDO);
}
private OAuth2AccessTokenDO createOAuth2AccessToken(Integer adminId, String refreshToken) {
private OAuth2AccessTokenDO createOAuth2AccessToken(Integer userId, Integer userType, String refreshToken) {
OAuth2AccessTokenDO accessToken = new OAuth2AccessTokenDO().setId(generateAccessToken())
.setRefreshToken(refreshToken)
.setAdminId(adminId)
.setUserId(userId).setUserType(userType)
.setExpiresTime(new Date(System.currentTimeMillis() + accessTokenExpireTimeMillis))
.setValid(true);
oauth2AccessTokenMapper.insert(accessToken);
return accessToken;
}
private OAuth2RefreshTokenDO createOAuth2RefreshToken(Integer adminId) {
private OAuth2RefreshTokenDO createOAuth2RefreshToken(Integer userId, Integer userType) {
OAuth2RefreshTokenDO refreshToken = new OAuth2RefreshTokenDO().setId(generateRefreshToken())
.setAdminId(adminId)
.setUserId(userId).setUserType(userType)
.setExpiresTime(new Date(System.currentTimeMillis() + refreshTokenExpireTimeMillis))
.setValid(true);
oauth2RefreshTokenMapper.insert(refreshToken);

View File

@@ -1,8 +1,8 @@
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.util.StringUtil;
import cn.iocoder.mall.admin.api.ResourceService;
import cn.iocoder.mall.admin.api.bo.resource.ResourceBO;
import cn.iocoder.mall.admin.api.constant.AdminErrorCodeEnum;
@@ -31,8 +31,14 @@ public class ResourceServiceImpl implements ResourceService {
@Autowired
private RoleResourceMapper roleResourceMapper;
public ResourceDO getResourceByTypeAndHandler(Integer type, String handler) {
return resourceMapper.selectByTypeAndHandler(type, handler);
public List<ResourceDO> getResourceListByPermission(String permission) {
List<ResourceDO> resources = resourceMapper.selectListByPermission(permission);
if (resources.isEmpty()) {
return Collections.emptyList();
}
// 因为 ResourceDO 存储的 permissions 是字符串,使用逗号分隔,需要进一步判断
resources.removeIf(resourceDO -> !StringUtil.split(resourceDO.getPermissions(), ",").contains(permission));
return resources;
}
@Override
@@ -49,12 +55,7 @@ public class ResourceServiceImpl implements ResourceService {
}
@Override
@SuppressWarnings("Duplicates")
public ResourceBO addResource(Integer adminId, ResourceAddDTO resourceAddDTO) {
// 补充未在 Validation 中校验的参数校验
if (!isValidResourceType(resourceAddDTO.getType())) {
throw ServiceExceptionUtil.exception(SysErrorCodeEnum.VALIDATION_REQUEST_PARAM_ERROR.getCode(), "资源类型必须是菜单或 Url"); // TODO 有点搓
}
// 校验父资源存在
checkParentResource(resourceAddDTO.getPid(), null);
// 存储到数据库
@@ -69,7 +70,6 @@ public class ResourceServiceImpl implements ResourceService {
}
@Override
@SuppressWarnings("Duplicates")
public Boolean updateResource(Integer adminId, ResourceUpdateDTO resourceUpdateDTO) {
// 校验更新的资源是否存在
if (resourceMapper.selectById(resourceUpdateDTO.getId()) == null) {
@@ -100,7 +100,7 @@ public class ResourceServiceImpl implements ResourceService {
// 更新到数据库
resourceMapper.deleteById(resourceId);
// 删除资源关联表
roleResourceMapper.updateToDeletedByResourceId(resourceId);
roleResourceMapper.deleteByResourceId(resourceId);
// 返回成功
return true;
}
@@ -112,18 +112,6 @@ public class ResourceServiceImpl implements ResourceService {
return resourceMapper.selectListByIds(resourceIds);
}
private boolean isValidResourceType(Integer type) {
return ResourceConstants.TYPE_MENU.equals(type)
|| ResourceConstants.TYPE_BUTTON.equals(type);
}
private boolean checkParentExists(Integer pid) {
if (!ResourceConstants.PID_ROOT.equals(pid)) {
return resourceMapper.selectById(pid) == null;
}
return false;
}
private void checkParentResource(Integer pid, Integer childId) {
if (pid == null || ResourceConstants.PID_ROOT.equals(pid)) {
return;

View File

@@ -19,6 +19,7 @@ import cn.iocoder.mall.admin.dataobject.ResourceDO;
import cn.iocoder.mall.admin.dataobject.RoleDO;
import cn.iocoder.mall.admin.dataobject.RoleResourceDO;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.google.common.collect.Maps;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -40,12 +41,8 @@ public class RoleServiceImpl implements RoleService {
@Autowired
private ResourceServiceImpl resourceService;
public List<RoleResourceDO> getRoleByResourceHandler(String resourceHandler) {
return roleResourceMapper.selectByResourceHandler(resourceHandler);
}
public List<RoleResourceDO> getRoleByResourceId(Integer resourceId) {
return roleResourceMapper.selectByResourceId(resourceId);
return roleResourceMapper.selectListByResourceId(resourceId);
}
@Override
@@ -62,7 +59,7 @@ public class RoleServiceImpl implements RoleService {
@Override
public List<RoleBO> getRoleList(Collection<Integer> ids) {
List<RoleDO> roles = roleMapper.selectListByIds(ids);
List<RoleDO> roles = roleMapper.selectBatchIds(ids);
return RoleConvert.INSTANCE.convert(roles);
}
@@ -104,9 +101,9 @@ public class RoleServiceImpl implements RoleService {
// 更新到数据库,标记删除
roleMapper.deleteById(roleId);
// 标记删除 RoleResource
roleResourceMapper.updateToDeletedByRoleId(roleId);
roleResourceMapper.deleteByRoleId(roleId);
// 标记删除 AdminRole
adminRoleMapper.updateToDeletedByRoleId(roleId);
adminRoleMapper.deleteByRoleId(roleId);
// TODO 插入操作日志
// 返回成功
return true;
@@ -130,7 +127,7 @@ public class RoleServiceImpl implements RoleService {
}
// TODO 芋艿,这里先简单实现。即方式是,删除老的分配的资源关系,然后添加新的分配的资源关系
// 标记角色原资源关系都为删除
roleResourceMapper.updateToDeletedByRoleId(roleId);
roleResourceMapper.deleteByRoleId(roleId);
// 创建 RoleResourceDO 数组,并插入到数据库
if (!CollectionUtil.isEmpty(resourceIds)) {
List<RoleResourceDO> roleResources = resourceIds.stream().map(resourceId -> {
@@ -150,7 +147,37 @@ public class RoleServiceImpl implements RoleService {
if (CollectionUtil.isEmpty(roleIds)) {
return Collections.emptyList();
}
return roleMapper.selectListByIds(roleIds);
return roleMapper.selectBatchIds(roleIds);
}
/**
* 获得权限与角色的映射关系。
*
* TODO 芋艿,等以后有 redis ,优化成从缓存读取。每个 permission ,哪些角色可以访问
*
* @param permissions 权限标识数组
* @return 映射关系。KEY权限标识VALUE角色编号数组
*/
public Map<String, List<Integer>> getPermissionRoleMap(List<String> permissions) {
if (CollectionUtil.isEmpty(permissions)) {
return Collections.emptyMap();
}
Map<String, List<Integer>> result = Maps.newHashMapWithExpectedSize(permissions.size());
for (String permission : permissions) {
List<ResourceDO> resources = resourceService.getResourceListByPermission(permission);
if (resources.isEmpty()) { // 无需授权
result.put(permission, Collections.emptyList());
} else {
List<RoleResourceDO> roleResources = roleResourceMapper.selectListByResourceId(
CollectionUtil.convertSet(resources, ResourceDO::getId));
if (roleResources.isEmpty()) {
result.put(permission, Collections.emptyList());
} else {
result.put(permission, CollectionUtil.convertList(roleResources, RoleResourceDO::getRoleId));
}
}
}
return result;
}
}

View File

@@ -2,37 +2,6 @@
<!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.AdminRoleMapper">
<!--<insert id="insert" parameterType="UserDO" useGeneratedKeys="true" keyProperty="id">-->
<!--INSERT INTO users (-->
<!--id, mobile, create_time-->
<!--) VALUES (-->
<!--#{id}, #{mobile}, #{createTime}-->
<!--)-->
<!--</insert>-->
<select id="selectByAdminId" parameterType="Integer" resultType="AdminRoleDO">
SELECT
ar.id, ar.admin_id, ar.role_id
FROM admin a, admin_role ar
WHERE a.id = #{adminId}
AND a.id = ar.admin_id
AND ar.deleted = 0
</select>
<update id="updateToDeletedByAdminId" parameterType="Integer">
UPDATE admin_role
SET deleted = 1
WHERE admin_id = #{adminId}
AND deleted = 0
</update>
<update id="updateToDeletedByRoleId" parameterType="Integer">
UPDATE admin_role
SET deleted = 1
WHERE role_id = #{roleId}
AND deleted = 0
</update>
<insert id="insertList">
INSERT INTO admin_role (
admin_id, role_id, create_time, deleted
@@ -42,4 +11,4 @@
</foreach>
</insert>
</mapper>
</mapper>

View File

@@ -29,21 +29,6 @@
</foreach>
</select>
<select id="selectById" resultType="DataDictDO">
SELECT
<include refid="FIELDS"/>
FROM data_dict
WHERE id = #{id}
AND deleted = 0
</select>
<select id="selectList" resultType="DataDictDO">
SELECT
<include refid="FIELDS"/>
FROM data_dict
WHERE deleted = 0
</select>
<select id="selectByEnumValue" resultType="cn.iocoder.mall.admin.dataobject.DataDictDO">
SELECT
<include refid="FIELDS"/>
@@ -52,39 +37,4 @@
AND enum_value = #{enumValue}
</select>
<insert id="insert" parameterType="DataDictDO" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
INSERT INTO data_dict (
id, enum_value, value, display_name, sort,
memo, create_time, deleted
) VALUES (
#{id}, #{enumValue}, #{value}, #{displayName}, #{sort},
#{memo}, #{createTime}, #{deleted}
)
</insert>
<update id="update" parameterType="DataDictDO">
UPDATE data_dict
<set>
<if test="enumValue != null">
enum_value = #{enumValue},
</if>
<if test="value != null">
value = #{value},
</if>
<if test="displayName != null">
display_name = #{displayName},
</if>
<if test="sort != null">
sort = #{sort},
</if>
<if test="memo != null">
memo = #{memo},
</if>
<if test="deleted != null">
deleted = #{deleted}
</if>
</set>
WHERE id = #{id}
</update>
</mapper>
</mapper>

View File

@@ -1,29 +0,0 @@
<?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.OAuth2AccessTokenMapper">
<insert id="insert" parameterType="OAuth2AccessTokenDO">
INSERT INTO oauth2_access_token (
id, refresh_token, admin_id, valid, expires_time,
create_time
) VALUES (
#{id}, #{refreshToken}, #{adminId}, #{valid}, #{expiresTime},
#{createTime}
)
</insert>
<select id="selectByTokenId" parameterType="String" resultType="OAuth2AccessTokenDO">
SELECT
id, admin_id, valid, expires_time
FROM oauth2_access_token
WHERE id = #{id}
</select>
<update id="updateToInvalidByAdminId" parameterType="Integer">
UPDATE oauth2_access_token
SET valid = 0
WHERE admin_id = #{adminId}
AND valid = 1
</update>
</mapper>

View File

@@ -1,20 +0,0 @@
<?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.OAuth2RefreshTokenMapper">
<insert id="insert" parameterType="OAuth2RefreshTokenDO">
INSERT INTO oauth2_refresh_token (
id, admin_id, valid, expires_time, create_time
) VALUES (
#{id}, #{adminId}, #{valid}, #{expiresTime}, #{createTime}
)
</insert>
<update id="updateToInvalidByAdminId" parameterType="Integer">
UPDATE oauth2_refresh_token
SET valid = 0
WHERE admin_id = #{adminId}
AND valid = 1
</update>
</mapper>

View File

@@ -7,31 +7,9 @@
create_time, pid, handler
</sql>
<select id="selectByTypeAndHandler" resultType="ResourceDO">
SELECT
<include refid="FIELDS"/>
FROM resource
WHERE type = #{type}
AND handler = #{handler}
AND deleted = 0
LIMIT 1
</select>
<select id="selectListByType" parameterType="Integer" resultType="ResourceDO">
SELECT
<include refid="FIELDS"/>
FROM resource
<where>
<if test="type != null">
type = #{type}
</if>
AND deleted = 0
</where>
</select>
<select id="selectListByTypeAndRoleIds" resultType="ResourceDO">
SELECT
r.id, r.name, r.type, r.sort, r.display_name,
r.id, r.type, r.sort, r.display_name,
r.create_time, r.pid, r.handler
FROM resource r, role_resource rr
WHERE r.deleted = 0
@@ -46,23 +24,4 @@
AND r.id = rr.resource_id
</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
COUNT(1)
FROM resource
WHERE pid = #{pid}
AND deleted = 0
</select>
</mapper>

View File

@@ -2,45 +2,6 @@
<!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.RoleResourceMapper">
<!--<insert id="insert" parameterType="UserDO" useGeneratedKeys="true" keyProperty="id">-->
<!--INSERT INTO users (-->
<!--id, mobile, create_time-->
<!--) VALUES (-->
<!--#{id}, #{mobile}, #{createTime}-->
<!--)-->
<!--</insert>-->
<select id="selectByResourceHandler" parameterType="String" resultType="RoleResourceDO">
SELECT
rr.id, rr.role_id, rr.resource_id
FROM resource r, role_resource rr
WHERE r.handler = #{resourceHandler}
AND r.id = rr.resource_id
AND rr.deleted = 0;
</select>
<select id="selectByResourceId" parameterType="Integer" resultType="RoleResourceDO">
SELECT
id, role_id, resource_id
FROM role_resource
WHERE resource_id = #{resourceId}
AND deleted = 0
</select>
<update id="updateToDeletedByResourceId" parameterType="Integer">
UPDATE role_resource
SET deleted = 1
WHERE resource_id = #{resourceId}
AND deleted = 0
</update>
<update id="updateToDeletedByRoleId" parameterType="Integer">
UPDATE role_resource
SET deleted = 1
WHERE role_id = #{roleId}
AND deleted = 0
</update>
<insert id="insertList">
INSERT INTO role_resource (
resource_id, role_id, create_time, deleted
@@ -50,4 +11,4 @@
</foreach>
</insert>
</mapper>
</mapper>