diff --git a/common/service-utils/src/main/java/cn/bunny/common/service/exception/GlobalExceptionHandler.java b/common/service-utils/src/main/java/cn/bunny/common/service/exception/GlobalExceptionHandler.java index bd57e45..cc39b7b 100644 --- a/common/service-utils/src/main/java/cn/bunny/common/service/exception/GlobalExceptionHandler.java +++ b/common/service-utils/src/main/java/cn/bunny/common/service/exception/GlobalExceptionHandler.java @@ -52,7 +52,7 @@ public class GlobalExceptionHandler { String primaryKeyError = "Duplicate entry '(.*?)' for key .*"; Matcher primaryKeyErrorMatcher = Pattern.compile(primaryKeyError).matcher(message); if (primaryKeyErrorMatcher.find()) { - return Result.error(null, 500, "【" + primaryKeyErrorMatcher.group(1) + "】已存在"); + return Result.error(null, 500, "[" + primaryKeyErrorMatcher.group(1) + "]已存在"); } log.error("GlobalExceptionHandler===>运行时异常信息:{}", message); diff --git a/dao/src/main/java/cn/bunny/dao/pojo/result/ResultCodeEnum.java b/dao/src/main/java/cn/bunny/dao/pojo/result/ResultCodeEnum.java index 1154dd6..9c958bd 100644 --- a/dao/src/main/java/cn/bunny/dao/pojo/result/ResultCodeEnum.java +++ b/dao/src/main/java/cn/bunny/dao/pojo/result/ResultCodeEnum.java @@ -54,8 +54,7 @@ public enum ResultCodeEnum { AUTHENTICATION_EXPIRED(208, "身份验证过期"), SESSION_EXPIRATION(208, "会话过期"), - // 封禁 209 - FAIL_NO_ACCESS_DENIED_USER_LOCKED(209, "该账户已封禁"), + // 209 THE_SAME_USER_HAS_LOGGED_IN(209, "相同用户已登录"), // 提示错误 @@ -72,6 +71,7 @@ public enum ResultCodeEnum { FAIL_NO_ACCESS_DENIED_USER_OFFLINE(403, "用户强制下线"), LOGGED_IN_FROM_ANOTHER_DEVICE(403, "没有权限访问"), TOKEN_PARSING_FAILED(403, "token解析失败"), + FAIL_NO_ACCESS_DENIED_USER_LOCKED(403, "该账户已封禁"), // 系统错误 500 UNKNOWN_EXCEPTION(500, "服务异常"), diff --git a/service/src/main/java/cn/bunny/services/controller/UserController.java b/service/src/main/java/cn/bunny/services/controller/UserController.java index fcbfc26..8d569c2 100644 --- a/service/src/main/java/cn/bunny/services/controller/UserController.java +++ b/service/src/main/java/cn/bunny/services/controller/UserController.java @@ -121,7 +121,7 @@ public class UserController { } @Operation(summary = "刷新token", description = "刷新用户token") - @PostMapping("noAuth/refreshToken") + @PostMapping("noManage/refreshToken") public Result refreshToken(@Valid @RequestBody RefreshTokenDto dto) { RefreshTokenVo vo = userService.refreshToken(dto); return Result.success(vo); diff --git a/service/src/main/java/cn/bunny/services/factory/RoleFactory.java b/service/src/main/java/cn/bunny/services/factory/RoleFactory.java new file mode 100644 index 0000000..9ac4207 --- /dev/null +++ b/service/src/main/java/cn/bunny/services/factory/RoleFactory.java @@ -0,0 +1,44 @@ +package cn.bunny.services.factory; + +import cn.bunny.dao.entity.system.AdminUser; +import cn.bunny.dao.pojo.constant.RedisUserConstant; +import cn.bunny.services.mapper.UserMapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; + +import java.util.List; + +@Component +public class RoleFactory { + + @Autowired + private RedisTemplate redisTemplate; + + @Autowired + private UserMapper userMapper; + + @Autowired + private UserFactory userFactory; + + /** + * 批量更新Redis中用户信息 + * + * @param userIds 用户Id列表 + */ + public void updateUserRedisInfo(List userIds) { + // 根据Id查找所有用户 + List adminUsers = userMapper.selectList(Wrappers.lambdaQuery().in(AdminUser::getId, userIds)); + + // 用户为空时不更新Redis的key + if (adminUsers.isEmpty()) return; + + // 更新Redis中用户信息 + adminUsers.stream().filter(user -> { + String adminLoginInfoPrefix = RedisUserConstant.getAdminLoginInfoPrefix(user.getUsername()); + Object object = redisTemplate.opsForValue().get(adminLoginInfoPrefix); + return object != null; + }).forEach(user -> userFactory.buildUserVo(user, RedisUserConstant.REDIS_EXPIRATION_TIME)); + } +} diff --git a/service/src/main/java/cn/bunny/services/factory/UserFactory.java b/service/src/main/java/cn/bunny/services/factory/UserFactory.java index a17283e..0c8c467 100644 --- a/service/src/main/java/cn/bunny/services/factory/UserFactory.java +++ b/service/src/main/java/cn/bunny/services/factory/UserFactory.java @@ -117,9 +117,7 @@ public class UserFactory { Long userId = user.getId(); // 判断用户是否有头像,如果没有头像设置默认头像,并且用户头像不能和默认头像相同 - String avatar = user.getAvatar(); - String userAvatar = UserConstant.USER_AVATAR; - avatar = StringUtils.hasText(avatar) && !avatar.equals(userAvatar) ? minioUtil.getObjectNameFullPath(avatar) : userAvatar; + String avatar = checkGetUserAvatar(user.getAvatar()); // 查找用户橘色 List roles = new ArrayList<>(roleMapper.selectListByUserId(userId).stream().map(Role::getRoleCode).toList()); @@ -162,7 +160,7 @@ public class UserFactory { * @param avatar 头像字符串 * @return 整理好的头像内容 */ - public String checkUserAvatar(String avatar) { + public String checkPostUserAvatar(String avatar) { // 如果用户没有头像或者用户头像和默认头像相同,返回默认头像 String userAvatar = UserConstant.USER_AVATAR; if (!StringUtils.hasText(avatar) || avatar.equals(userAvatar)) return userAvatar; @@ -179,6 +177,30 @@ public class UserFactory { return "/" + matcher.group(1); } + /** + * 检查用户头像是否合规 + * + * @param avatar 头像字符串 + * @return 整理好的头像内容 + */ + public String checkGetUserAvatar(String avatar) { + // 如果用户没有头像或者用户头像和默认头像相同,返回默认头像 + String userAvatar = UserConstant.USER_AVATAR; + if (!StringUtils.hasText(avatar) || avatar.equals(userAvatar)) return userAvatar; + + // 替换前端发送的host前缀,将其删除,只保留路径名称 + String regex = "^https?://.*?/(.*)"; + Pattern pattern = Pattern.compile(regex); + Matcher matcher = pattern.matcher(avatar); + + // 如果没有匹配 + if (matcher.matches()) return avatar; + + // 匹配后返回内容 + return minioUtil.getObjectNameFullPath(avatar); + } + + /** * * 设置用户登录日志内容 */ diff --git a/service/src/main/java/cn/bunny/services/service/impl/RolePowerServiceImpl.java b/service/src/main/java/cn/bunny/services/service/impl/RolePowerServiceImpl.java index 9029082..f1425c7 100644 --- a/service/src/main/java/cn/bunny/services/service/impl/RolePowerServiceImpl.java +++ b/service/src/main/java/cn/bunny/services/service/impl/RolePowerServiceImpl.java @@ -1,10 +1,17 @@ package cn.bunny.services.service.impl; import cn.bunny.dao.dto.system.rolePower.AssignPowersToRoleDto; +import cn.bunny.dao.entity.system.AdminUser; import cn.bunny.dao.entity.system.RolePower; +import cn.bunny.dao.entity.system.UserRole; +import cn.bunny.services.factory.RoleFactory; import cn.bunny.services.mapper.RolePowerMapper; +import cn.bunny.services.mapper.UserMapper; +import cn.bunny.services.mapper.UserRoleMapper; import cn.bunny.services.service.RolePowerService; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -22,6 +29,14 @@ import java.util.List; @Transactional public class RolePowerServiceImpl extends ServiceImpl implements RolePowerService { + @Autowired + private UserMapper userMapper; + + @Autowired + private RoleFactory roleFactory; + @Autowired + private UserRoleMapper userRoleMapper; + /** * * 根据角色id获取权限内容 * @@ -54,7 +69,20 @@ public class RolePowerServiceImpl extends ServiceImpl roleIds = userRoleMapper.selectList(Wrappers.lambdaQuery().eq(UserRole::getRoleId, roleId)) + .stream().map(UserRole::getUserId).toList(); + + // 根据Id查找所有用户 + List adminUsers = userMapper.selectList(Wrappers.lambdaQuery().in(AdminUser::getId, roleIds)); + + // 用户为空时不更新Redis的key + if (adminUsers.isEmpty()) return; + + // 更新Redis中用户信息 + List userIds = adminUsers.stream().map(AdminUser::getId).toList(); + roleFactory.updateUserRedisInfo(userIds); } } diff --git a/service/src/main/java/cn/bunny/services/service/impl/RoleServiceImpl.java b/service/src/main/java/cn/bunny/services/service/impl/RoleServiceImpl.java index 48782eb..8b33bf1 100644 --- a/service/src/main/java/cn/bunny/services/service/impl/RoleServiceImpl.java +++ b/service/src/main/java/cn/bunny/services/service/impl/RoleServiceImpl.java @@ -4,15 +4,16 @@ import cn.bunny.common.service.exception.BunnyException; import cn.bunny.dao.dto.system.rolePower.role.RoleAddDto; import cn.bunny.dao.dto.system.rolePower.role.RoleDto; import cn.bunny.dao.dto.system.rolePower.role.RoleUpdateDto; -import cn.bunny.dao.entity.system.AdminUser; import cn.bunny.dao.entity.system.Role; import cn.bunny.dao.entity.system.UserRole; -import cn.bunny.dao.pojo.constant.RedisUserConstant; import cn.bunny.dao.pojo.result.PageResult; import cn.bunny.dao.pojo.result.ResultCodeEnum; import cn.bunny.dao.vo.system.rolePower.RoleVo; -import cn.bunny.services.factory.UserFactory; -import cn.bunny.services.mapper.*; +import cn.bunny.services.factory.RoleFactory; +import cn.bunny.services.mapper.RoleMapper; +import cn.bunny.services.mapper.RolePowerMapper; +import cn.bunny.services.mapper.RouterRoleMapper; +import cn.bunny.services.mapper.UserRoleMapper; import cn.bunny.services.service.RoleService; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.Wrappers; @@ -23,7 +24,6 @@ import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.Cacheable; -import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; import java.util.List; @@ -49,14 +49,7 @@ public class RoleServiceImpl extends ServiceImpl implements Ro private RouterRoleMapper routerRoleMapper; @Autowired - private UserMapper userMapper; - - @Autowired - private RedisTemplate redisTemplate; - - @Autowired - private UserFactory userFactory; - + private RoleFactory roleFactory; /** * * 角色 服务实现类 @@ -129,25 +122,13 @@ public class RoleServiceImpl extends ServiceImpl implements Ro BeanUtils.copyProperties(dto, role); updateById(role); - // 找到所有和当前更新角色相同的用户 + // 找到所有和当前更新角色相同的用户,并更新Redis中用户信息 List userIds = userRoleMapper.selectList(Wrappers.lambdaQuery().eq(UserRole::getRoleId, dto.getId())) .stream().map(UserRole::getUserId).toList(); - - // 根据Id查找所有用户 - List adminUsers = userMapper.selectList(Wrappers.lambdaQuery().in(AdminUser::getId, userIds)); - - // 用户为空时不更新Redis的key - if (adminUsers.isEmpty()) return; - - // 更新Redis中用户信息 - adminUsers.stream().filter(user -> { - String adminLoginInfoPrefix = RedisUserConstant.getAdminLoginInfoPrefix(user.getUsername()); - Object object = redisTemplate.opsForValue().get(adminLoginInfoPrefix); - return object != null; - }).forEach(user -> userFactory.buildUserVo(user, RedisUserConstant.REDIS_EXPIRATION_TIME)); - + roleFactory.updateUserRedisInfo(userIds); } + /** * 删除|批量删除角色 * diff --git a/service/src/main/java/cn/bunny/services/service/impl/UserServiceImpl.java b/service/src/main/java/cn/bunny/services/service/impl/UserServiceImpl.java index 5da4253..22013e5 100644 --- a/service/src/main/java/cn/bunny/services/service/impl/UserServiceImpl.java +++ b/service/src/main/java/cn/bunny/services/service/impl/UserServiceImpl.java @@ -4,7 +4,6 @@ import cn.bunny.common.service.context.BaseContext; import cn.bunny.common.service.exception.BunnyException; import cn.bunny.common.service.utils.JwtHelper; import cn.bunny.common.service.utils.ip.IpUtil; -import cn.bunny.common.service.utils.minio.MinioUtil; import cn.bunny.dao.dto.system.files.FileUploadDto; import cn.bunny.dao.dto.system.user.*; import cn.bunny.dao.entity.log.UserLoginLog; @@ -72,9 +71,6 @@ public class UserServiceImpl extends ServiceImpl implemen @Autowired private RedisTemplate redisTemplate; - @Autowired - private MinioUtil minioUtil; - @Autowired private FilesService filesService; @@ -190,7 +186,7 @@ public class UserServiceImpl extends ServiceImpl implemen UserVo userVo = new UserVo(); BeanUtils.copyProperties(user, userVo); - if (StringUtils.hasText(avatar)) userVo.setAvatar(minioUtil.getObjectNameFullPath(avatar)); + userVo.setAvatar(userFactory.checkGetUserAvatar(avatar)); return userVo; } @@ -215,14 +211,14 @@ public class UserServiceImpl extends ServiceImpl implemen if (adminUser.getPassword().equals(md5Password)) throw new BunnyException(ResultCodeEnum.UPDATE_NEW_PASSWORD_SAME_AS_OLD_PASSWORD); - // 删除Redis中登录用户信息 - redisTemplate.delete(RedisUserConstant.getAdminLoginInfoPrefix(adminUser.getUsername())); - // 更新用户密码 adminUser = new AdminUser(); adminUser.setPassword(md5Password); adminUser.setId(userId); updateById(adminUser); + + // 删除Redis中登录用户信息 + redisTemplate.delete(RedisUserConstant.getAdminLoginInfoPrefix(adminUser.getUsername())); } /** @@ -237,18 +233,22 @@ public class UserServiceImpl extends ServiceImpl implemen Long userId = dto.getUserId(); // 判断是否存在这个用户 - AdminUser adminUser = getOne(Wrappers.lambdaQuery().eq(AdminUser::getId, userId)); - if (adminUser == null) throw new BunnyException(ResultCodeEnum.USER_IS_EMPTY); + AdminUser user = getOne(Wrappers.lambdaQuery().eq(AdminUser::getId, userId)); + if (user == null) throw new BunnyException(ResultCodeEnum.USER_IS_EMPTY); // 上传头像 FileUploadDto uploadDto = FileUploadDto.builder().file(avatar).type(MinioConstant.avatar).build(); FileInfoVo fileInfoVo = filesService.upload(uploadDto); // 更新用户 - adminUser = new AdminUser(); + AdminUser adminUser = new AdminUser(); adminUser.setId(userId); adminUser.setAvatar(fileInfoVo.getFilepath()); updateById(adminUser); + + // 重新生成用户信息到Redis中 + user.setAvatar(adminUser.getAvatar()); + userFactory.buildUserVo(user, RedisUserConstant.REDIS_EXPIRATION_TIME); } /** @@ -302,11 +302,19 @@ public class UserServiceImpl extends ServiceImpl implemen */ @Override public void updateUserStatusByAdmin(AdminUserUpdateUserStatusDto dto) { - AdminUser adminUser = new AdminUser(); - adminUser.setId(dto.getUserId()); - adminUser.setStatus(dto.getStatus()); + Long userId = dto.getUserId(); + // 更新用户Id + AdminUser adminUser = new AdminUser(); + adminUser.setId(userId); + adminUser.setStatus(dto.getStatus()); updateById(adminUser); + + // 如果是锁定用户删除Redis中内容 + if (dto.getStatus()) { + adminUser = getOne(Wrappers.lambdaQuery().eq(AdminUser::getId, userId)); + redisTemplate.delete(RedisUserConstant.getAdminLoginInfoPrefix(adminUser.getUsername())); + } } /** @@ -333,7 +341,7 @@ public class UserServiceImpl extends ServiceImpl implemen if (user == null) throw new BunnyException(ResultCodeEnum.USER_IS_EMPTY); // 检查用户头像 - dto.setAvatar(userFactory.checkUserAvatar(dto.getAvatar())); + dto.setAvatar(userFactory.checkPostUserAvatar(dto.getAvatar())); // 更新用户 AdminUser adminUser = new AdminUser(); @@ -367,14 +375,14 @@ public class UserServiceImpl extends ServiceImpl implemen // 判断数据库中密码是否和更新用户密码相同 if (dbPassword.equals(password)) throw new BunnyException(ResultCodeEnum.NEW_PASSWORD_SAME_OLD_PASSWORD); - // 删除Redis中登录用户信息 - redisTemplate.delete(RedisUserConstant.getAdminLoginInfoPrefix(adminUser.getUsername())); - // 更新用户密码 adminUser = new AdminUser(); adminUser.setId(userId); adminUser.setPassword(password); updateById(adminUser); + + // 删除Redis中登录用户信息 + redisTemplate.delete(RedisUserConstant.getAdminLoginInfoPrefix(adminUser.getUsername())); } /** @@ -392,10 +400,7 @@ public class UserServiceImpl extends ServiceImpl implemen List voList = page.getRecords().stream() .map(adminUser -> { // 如果存在用户头像,则设置用户头像 - String avatar = adminUser.getAvatar(); - if (StringUtils.hasText(avatar)) { - avatar = minioUtil.getObjectNameFullPath(avatar); - } + String avatar = userFactory.checkGetUserAvatar(adminUser.getAvatar()); AdminUserVo adminUserVo = new AdminUserVo(); BeanUtils.copyProperties(adminUser, adminUserVo); @@ -444,33 +449,28 @@ public class UserServiceImpl extends ServiceImpl implemen /** * 更新用户信息 + * 如果更新了用户名需要用户重新登录,因为Redis中的key已经被删除 * * @param dto 用户信息更新 */ @Override public void updateAdminUser(AdminUserUpdateDto dto) { - List userList = list(Wrappers.lambdaQuery() - .ne(AdminUser::getId, dto.getId()) - .and(queryWrapper -> queryWrapper.eq(AdminUser::getEmail, dto.getEmail()) - .or() - .eq(AdminUser::getUsername, dto.getUsername())) - ); - - // 确保邮箱和用户名不能重复 - if (!userList.isEmpty()) { - throw new BunnyException(ResultCodeEnum.ALREADY_USER_EXCEPTION); - } - // 部门Id Long deptId = dto.getDeptId(); Long userId = dto.getId(); // 判断更新内容是否存在 - List adminUserList = list(Wrappers.lambdaQuery().eq(AdminUser::getId, userId)); - if (adminUserList.isEmpty()) throw new BunnyException(ResultCodeEnum.DATA_NOT_EXIST); + AdminUser adminUser = getOne(Wrappers.lambdaQuery().eq(AdminUser::getId, userId)); + if (adminUser == null) throw new BunnyException(ResultCodeEnum.DATA_NOT_EXIST); + + // 如果更新了用户名,删除之前的用户数据 + if (!dto.getUsername().equals(adminUser.getUsername())) { + String adminLoginInfoPrefix = RedisUserConstant.getAdminLoginInfoPrefix(adminUser.getUsername()); + redisTemplate.delete(adminLoginInfoPrefix); + } // 更新用户 - AdminUser adminUser = new AdminUser(); + adminUser = new AdminUser(); BeanUtils.copyProperties(dto, adminUser); updateById(adminUser);