diff --git a/auh-api/Dockerfile b/auh-api/Dockerfile index 0039cda..3673ff8 100644 --- a/auh-api/Dockerfile +++ b/auh-api/Dockerfile @@ -26,6 +26,7 @@ ENTRYPOINT ["java","-jar","/home/server/app.jar"] #暴露 8000 端口 EXPOSE 8000 +EXPOSE 7070 # 生产环境 # mvn clean package -Pprod -DskipTests diff --git a/auh-api/src/main/java/cn/bunny/services/controller/configuration/EmailTemplateController.java b/auh-api/src/main/java/cn/bunny/services/controller/configuration/EmailTemplateController.java index 72e0c5e..bcbfa22 100644 --- a/auh-api/src/main/java/cn/bunny/services/controller/configuration/EmailTemplateController.java +++ b/auh-api/src/main/java/cn/bunny/services/controller/configuration/EmailTemplateController.java @@ -1,13 +1,13 @@ package cn.bunny.services.controller.configuration; +import cn.bunny.services.domain.common.enums.ResultCodeEnum; +import cn.bunny.services.domain.common.model.vo.result.PageResult; +import cn.bunny.services.domain.common.model.vo.result.Result; import cn.bunny.services.domain.system.email.dto.EmailTemplateAddDto; import cn.bunny.services.domain.system.email.dto.EmailTemplateDto; import cn.bunny.services.domain.system.email.dto.EmailTemplateUpdateDto; import cn.bunny.services.domain.system.email.entity.EmailTemplate; import cn.bunny.services.domain.system.email.vo.EmailTemplateVo; -import cn.bunny.services.domain.common.model.vo.result.PageResult; -import cn.bunny.services.domain.common.model.vo.result.Result; -import cn.bunny.services.domain.common.enums.ResultCodeEnum; import cn.bunny.services.service.configuration.EmailTemplateService; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import io.swagger.v3.oas.annotations.Operation; @@ -71,7 +71,7 @@ public class EmailTemplateController { } @Operation(summary = "全部邮件类型列表", description = "获取全部邮件类型列表", tags = "emailTemplate::query") - @GetMapping("public") + @GetMapping("private") public Result>> getEmailTypeList() { List> list = emailTemplateService.getEmailTypeList(); return Result.success(list); diff --git a/auh-api/src/main/resources/application.yml b/auh-api/src/main/resources/application.yml index eb9d205..d49babf 100644 --- a/auh-api/src/main/resources/application.yml +++ b/auh-api/src/main/resources/application.yml @@ -1,6 +1,8 @@ server: port: 8000 - + tomcat: + threads: + max: 1000 spring: profiles: active: @profiles.active@ diff --git a/service/src/main/java/cn/bunny/services/core/cache/UserAuthorizationCacheService.java b/service/src/main/java/cn/bunny/services/core/cache/UserAuthorizationCacheService.java index 3b19f6e..8c705e8 100644 --- a/service/src/main/java/cn/bunny/services/core/cache/UserAuthorizationCacheService.java +++ b/service/src/main/java/cn/bunny/services/core/cache/UserAuthorizationCacheService.java @@ -107,15 +107,4 @@ public class UserAuthorizationCacheService { return permissionList; } - - /** - * 清除缓存 - * 如有需要清除当前服务缓存 - */ - public void deleteRoleAndPermissionCache(String key) { - String permissionCodePrefix = RedisUserConstant.getUserPermissionCodePrefix(key); - String rolesCodePrefix = RedisUserConstant.getUserRolesCodePrefix(key); - redisTemplate.delete(permissionCodePrefix); - redisTemplate.delete(rolesCodePrefix); - } } diff --git a/service/src/main/java/cn/bunny/services/core/cache/UserCacheCleaner.java b/service/src/main/java/cn/bunny/services/core/cache/UserCacheCleaner.java new file mode 100644 index 0000000..e660828 --- /dev/null +++ b/service/src/main/java/cn/bunny/services/core/cache/UserCacheCleaner.java @@ -0,0 +1,33 @@ +package cn.bunny.services.core.cache; + +import cn.bunny.services.domain.common.constant.RedisUserConstant; +import jakarta.annotation.Resource; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; + +@Component +public class UserCacheCleaner { + @Resource + private RedisTemplate redisTemplate; + + public void cleanUserLoginCache(String username) { + String key = RedisUserConstant.getUserLoginInfoPrefix(username); + redisTemplate.delete(key); + } + + public void cleanUserRoleCache(String username) { + String key = RedisUserConstant.getUserRolesCodePrefix(username); + redisTemplate.delete(key); + } + + public void cleanUserPermissionCache(String username) { + String key = RedisUserConstant.getUserPermissionCodePrefix(username); + redisTemplate.delete(key); + } + + public void cleanAllUserCache(String username) { + cleanUserLoginCache(username); + cleanUserRoleCache(username); + cleanUserPermissionCache(username); + } +} \ No newline at end of file diff --git a/service/src/main/java/cn/bunny/services/core/cache/UserCacheService.java b/service/src/main/java/cn/bunny/services/core/cache/UserCacheService.java deleted file mode 100644 index 3122705..0000000 --- a/service/src/main/java/cn/bunny/services/core/cache/UserCacheService.java +++ /dev/null @@ -1,25 +0,0 @@ -package cn.bunny.services.core.cache; - -import cn.bunny.services.domain.common.constant.RedisUserConstant; -import cn.bunny.services.domain.common.model.vo.LoginVo; -import com.alibaba.fastjson2.JSON; -import jakarta.annotation.Resource; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.stereotype.Service; - -@Service -public class UserCacheService { - @Resource - private RedisTemplate redisTemplate; - - /** - * 根据用户名获取缓存中内容 - * - * @param username 用户名 - * @return LoginVo - */ - public LoginVo getLoginVoByUsername(String username) { - Object loginVoObject = redisTemplate.opsForValue().get(RedisUserConstant.getUserLoginInfoPrefix(username)); - return JSON.parseObject(JSON.toJSONString(loginVoObject), LoginVo.class); - } -} diff --git a/service/src/main/java/cn/bunny/services/core/event/event/ClearAllUserCacheEvent.java b/service/src/main/java/cn/bunny/services/core/event/event/ClearAllUserCacheEvent.java new file mode 100644 index 0000000..80d3352 --- /dev/null +++ b/service/src/main/java/cn/bunny/services/core/event/event/ClearAllUserCacheEvent.java @@ -0,0 +1,16 @@ +package cn.bunny.services.core.event.event; + +import lombok.Getter; +import lombok.Setter; +import org.springframework.context.ApplicationEvent; + +@Getter +@Setter +public class ClearAllUserCacheEvent extends ApplicationEvent { + private final String key; + + public ClearAllUserCacheEvent(Object source, String key) { + super(source); + this.key = key; + } +} \ No newline at end of file diff --git a/service/src/main/java/cn/bunny/services/core/event/event/UpdateUserinfoByPermissionIdsEvent.java b/service/src/main/java/cn/bunny/services/core/event/event/UpdateUserinfoByPermissionIdsEvent.java new file mode 100644 index 0000000..b6300f4 --- /dev/null +++ b/service/src/main/java/cn/bunny/services/core/event/event/UpdateUserinfoByPermissionIdsEvent.java @@ -0,0 +1,18 @@ +package cn.bunny.services.core.event.event; + +import lombok.Getter; +import lombok.Setter; +import org.springframework.context.ApplicationEvent; + +import java.util.List; + +@Getter +@Setter +public class UpdateUserinfoByPermissionIdsEvent extends ApplicationEvent { + private final List permissionIds; + + public UpdateUserinfoByPermissionIdsEvent(Object source, List permissionIds) { + super(source); + this.permissionIds = permissionIds; + } +} diff --git a/service/src/main/java/cn/bunny/services/core/event/event/UpdateUserinfoByRoleIdsEvent.java b/service/src/main/java/cn/bunny/services/core/event/event/UpdateUserinfoByRoleIdsEvent.java new file mode 100644 index 0000000..9bbdc00 --- /dev/null +++ b/service/src/main/java/cn/bunny/services/core/event/event/UpdateUserinfoByRoleIdsEvent.java @@ -0,0 +1,18 @@ +package cn.bunny.services.core.event.event; + +import lombok.Getter; +import lombok.Setter; +import org.springframework.context.ApplicationEvent; + +import java.util.List; + +@Getter +@Setter +public class UpdateUserinfoByRoleIdsEvent extends ApplicationEvent { + private final List roleIds; + + public UpdateUserinfoByRoleIdsEvent(Object source, List roleIds) { + super(source); + this.roleIds = roleIds; + } +} \ No newline at end of file diff --git a/service/src/main/java/cn/bunny/services/core/event/event/UpdateUserinfoByUserIdsEvent.java b/service/src/main/java/cn/bunny/services/core/event/event/UpdateUserinfoByUserIdsEvent.java new file mode 100644 index 0000000..b4c3b06 --- /dev/null +++ b/service/src/main/java/cn/bunny/services/core/event/event/UpdateUserinfoByUserIdsEvent.java @@ -0,0 +1,19 @@ +package cn.bunny.services.core.event.event; + +import lombok.Getter; +import lombok.Setter; +import org.springframework.context.ApplicationEvent; + +import java.util.List; + +@Getter +@Setter +public class UpdateUserinfoByUserIdsEvent extends ApplicationEvent { + private final List userIds; + + public UpdateUserinfoByUserIdsEvent(Object source, List userIds) { + super(source); + this.userIds = userIds; + } +} + diff --git a/service/src/main/java/cn/bunny/services/core/excel/I18nExcelListener.java b/service/src/main/java/cn/bunny/services/core/event/listener/excel/I18nExcelListener.java similarity index 97% rename from service/src/main/java/cn/bunny/services/core/excel/I18nExcelListener.java rename to service/src/main/java/cn/bunny/services/core/event/listener/excel/I18nExcelListener.java index 5d42d35..6017ff6 100644 --- a/service/src/main/java/cn/bunny/services/core/excel/I18nExcelListener.java +++ b/service/src/main/java/cn/bunny/services/core/event/listener/excel/I18nExcelListener.java @@ -1,4 +1,4 @@ -package cn.bunny.services.core.excel; +package cn.bunny.services.core.event.listener.excel; import cn.bunny.services.domain.common.model.dto.excel.I18nExcel; import cn.bunny.services.domain.system.i18n.entity.I18n; diff --git a/service/src/main/java/cn/bunny/services/core/excel/PermissionExcelListener.java b/service/src/main/java/cn/bunny/services/core/event/listener/excel/PermissionExcelListener.java similarity index 97% rename from service/src/main/java/cn/bunny/services/core/excel/PermissionExcelListener.java rename to service/src/main/java/cn/bunny/services/core/event/listener/excel/PermissionExcelListener.java index 6a92746..87014c8 100644 --- a/service/src/main/java/cn/bunny/services/core/excel/PermissionExcelListener.java +++ b/service/src/main/java/cn/bunny/services/core/event/listener/excel/PermissionExcelListener.java @@ -1,4 +1,4 @@ -package cn.bunny.services.core.excel; +package cn.bunny.services.core.event.listener.excel; import cn.bunny.services.domain.common.model.dto.excel.PermissionExcel; import cn.bunny.services.domain.system.system.entity.Permission; diff --git a/service/src/main/java/cn/bunny/services/core/excel/RoleExcelListener.java b/service/src/main/java/cn/bunny/services/core/event/listener/excel/RoleExcelListener.java similarity index 97% rename from service/src/main/java/cn/bunny/services/core/excel/RoleExcelListener.java rename to service/src/main/java/cn/bunny/services/core/event/listener/excel/RoleExcelListener.java index cc92624..39f5f85 100644 --- a/service/src/main/java/cn/bunny/services/core/excel/RoleExcelListener.java +++ b/service/src/main/java/cn/bunny/services/core/event/listener/excel/RoleExcelListener.java @@ -1,4 +1,4 @@ -package cn.bunny.services.core.excel; +package cn.bunny.services.core.event.listener.excel; import cn.bunny.services.domain.common.enums.ResultCodeEnum; import cn.bunny.services.domain.common.model.dto.excel.RoleExcel; diff --git a/service/src/main/java/cn/bunny/services/core/event/listener/user/AbstractUserInfoUpdateHandler.java b/service/src/main/java/cn/bunny/services/core/event/listener/user/AbstractUserInfoUpdateHandler.java new file mode 100644 index 0000000..638be36 --- /dev/null +++ b/service/src/main/java/cn/bunny/services/core/event/listener/user/AbstractUserInfoUpdateHandler.java @@ -0,0 +1,34 @@ +package cn.bunny.services.core.event.listener.user; + +import cn.bunny.services.core.cache.UserCacheCleaner; +import cn.bunny.services.domain.common.constant.RedisUserConstant; +import cn.bunny.services.domain.system.system.entity.AdminUser; +import cn.bunny.services.mapper.system.UserMapper; +import jakarta.annotation.Resource; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.function.Consumer; + +@Component("AbstractUserInfoUpdateHandler") +public abstract class AbstractUserInfoUpdateHandler { + + @Resource + protected UserMapper userMapper; + + @Resource + protected UserCacheCleaner userCacheCleaner; + + @Resource + private RedisTemplate redisTemplate; + + public void processUserUpdate(List userIds, Consumer postProcess) { + if (userIds.isEmpty()) return; + + List adminUsers = userMapper.selectBatchIds(userIds); + adminUsers.stream() + .filter(user -> redisTemplate.hasKey(RedisUserConstant.getUserLoginInfoPrefix(user.getUsername()))) + .forEach(postProcess); + } +} \ No newline at end of file diff --git a/service/src/main/java/cn/bunny/services/core/event/listener/user/UserinfoUpdateListener.java b/service/src/main/java/cn/bunny/services/core/event/listener/user/UserinfoUpdateListener.java new file mode 100644 index 0000000..77a45e6 --- /dev/null +++ b/service/src/main/java/cn/bunny/services/core/event/listener/user/UserinfoUpdateListener.java @@ -0,0 +1,68 @@ +package cn.bunny.services.core.event.listener.user; + +import cn.bunny.services.core.cache.UserLoginVoBuilderCacheService; +import cn.bunny.services.core.event.event.ClearAllUserCacheEvent; +import cn.bunny.services.core.event.event.UpdateUserinfoByPermissionIdsEvent; +import cn.bunny.services.core.event.event.UpdateUserinfoByRoleIdsEvent; +import cn.bunny.services.core.event.event.UpdateUserinfoByUserIdsEvent; +import cn.bunny.services.domain.common.constant.RedisUserConstant; +import cn.bunny.services.domain.system.system.entity.RolePermission; +import cn.bunny.services.domain.system.system.entity.UserRole; +import cn.bunny.services.mapper.system.RolePermissionMapper; +import cn.bunny.services.mapper.system.UserRoleMapper; +import jakarta.annotation.Resource; +import org.springframework.context.event.EventListener; +import org.springframework.stereotype.Component; + +import java.util.List; + +@Component("UserinfoUpdateListener") +public class UserinfoUpdateListener extends AbstractUserInfoUpdateHandler { + + @Resource + private UserLoginVoBuilderCacheService userLoginVoBuilderCacheService; + + @Resource + private UserRoleMapper userRoleMapper; + + @Resource + private RolePermissionMapper rolePermissionMapper; + + /* 根据用户id更新用户信息,重新生成LoginVo对象 */ + @EventListener + public void handlerUpdateUserinfoByUserIds(UpdateUserinfoByUserIdsEvent event) { + List userIds = event.getUserIds(); + processUserUpdate(userIds, user -> { + userCacheCleaner.cleanAllUserCache(user.getUsername()); + userLoginVoBuilderCacheService.buildLoginUserVo(user, RedisUserConstant.REDIS_EXPIRATION_TIME); + }); + } + + /* 根据角色id更新用户信息,重新生成LoginVo对象 */ + @EventListener + public void handlerUserinfoUpdateByRoleId(UpdateUserinfoByRoleIdsEvent event) { + List roleIds = event.getRoleIds(); + List userRoles = userRoleMapper.selectListByRoleIds(roleIds); + List userIds = userRoles.stream().map(UserRole::getUserId).toList(); + + UpdateUserinfoByUserIdsEvent userIdsEvent = new UpdateUserinfoByUserIdsEvent(event.getSource(), userIds); + handlerUpdateUserinfoByUserIds(userIdsEvent); + } + + /* 根据角色id更新用户信息,重新生成LoginVo对象 */ + @EventListener + public void handlerUserinfoUpdateByPermissionId(UpdateUserinfoByPermissionIdsEvent event) { + List permissionIds = event.getPermissionIds(); + List rolePermissions = rolePermissionMapper.selectRolePermissionListByPermissionIds(permissionIds); + List roleIds = rolePermissions.stream().map(RolePermission::getRoleId).toList(); + + UpdateUserinfoByRoleIdsEvent roleIdsEvent = new UpdateUserinfoByRoleIdsEvent(event.getSource(), roleIds); + handlerUserinfoUpdateByRoleId(roleIdsEvent); + } + + /* 清除用户登录、角色、权限所有缓存 */ + @EventListener + public void handlerDeleteAllUserCache(ClearAllUserCacheEvent event) { + userCacheCleaner.cleanAllUserCache(event.getKey()); + } +} diff --git a/service/src/main/java/cn/bunny/services/core/utils/UserServiceHelper.java b/service/src/main/java/cn/bunny/services/core/utils/UserServiceHelper.java deleted file mode 100644 index 2395f05..0000000 --- a/service/src/main/java/cn/bunny/services/core/utils/UserServiceHelper.java +++ /dev/null @@ -1,160 +0,0 @@ -package cn.bunny.services.core.utils; - -import cn.bunny.services.core.cache.UserAuthorizationCacheService; -import cn.bunny.services.core.cache.UserLoginVoBuilderCacheService; -import cn.bunny.services.domain.common.constant.RedisUserConstant; -import cn.bunny.services.domain.system.log.entity.UserLoginLog; -import cn.bunny.services.domain.system.system.entity.AdminUser; -import cn.bunny.services.domain.system.system.entity.RolePermission; -import cn.bunny.services.domain.system.system.entity.UserRole; -import cn.bunny.services.mapper.log.UserLoginLogMapper; -import cn.bunny.services.mapper.system.RolePermissionMapper; -import cn.bunny.services.mapper.system.UserMapper; -import cn.bunny.services.mapper.system.UserRoleMapper; -import jakarta.annotation.Resource; -import jakarta.servlet.http.HttpServletRequest; -import org.springframework.beans.BeanUtils; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.scheduling.annotation.Async; -import org.springframework.stereotype.Service; -import org.springframework.web.context.request.RequestContextHolder; -import org.springframework.web.context.request.ServletRequestAttributes; - -import java.util.List; - -@Service -public class UserServiceHelper { - - @Resource - private UserRoleMapper userRoleMapper; - - @Resource - private UserLoginVoBuilderCacheService userLoginVoBuilderCacheService; - - @Resource - private UserLoginLogMapper userLoginLogMapper; - - @Resource - private RolePermissionMapper rolePermissionMapper; - - @Resource - private RedisTemplate redisTemplate; - - @Resource - private UserMapper userMapper; - - @Resource - private UserAuthorizationCacheService userAuthorizationCacheService; - - /** - * 设置用户登录日志内容 - *

- * 该方法用于将管理员用户信息复制到用户登录日志对象中,同时处理特殊字段映射关系。 - *

- * 实现说明: - * 1. 使用BeanUtils.copyProperties()复制属性时,会自动将AdminUser.id复制到UserLoginLog.id - * 2. 由于UserLoginLog实际需要的是userId字段而非id字段,需要特殊处理: - * - 先进行属性复制 - * - 然后将UserLoginLog.userId设置为AdminUser.id - * - 最后将UserLoginLog.id显式设为null(避免自动生成的id被覆盖) - * - * @param user 管理员用户实体对象,包含用户基本信息 - * @param token 本次登录/退出的认证令牌 - * @param type 操作类型(LOGIN-登录/LOGOUT-退出) - */ - public void setUserLoginLog(AdminUser user, String token, String type) { - UserLoginLog userLoginLog = new UserLoginLog(); - BeanUtils.copyProperties(user, userLoginLog); - userLoginLog.setUserId(user.getId()); - userLoginLog.setId(null); - userLoginLog.setToken(token); - userLoginLog.setType(type); - - // 当前请求request - ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); - if (requestAttributes != null) { - HttpServletRequest request = requestAttributes.getRequest(); - - // 获取User-Agent - String userAgent = request.getHeader("User-Agent"); - userLoginLog.setUserAgent(userAgent); - - // 获取X-Requested-With - String xRequestedWith = request.getHeader("X-Requested-With"); - userLoginLog.setXRequestedWith(xRequestedWith); - } - - userLoginLogMapper.insert(userLoginLog); - } - - /** - * 批量更新Redis中用户权限信息,设计用户和角色就用这个 - * - * @param userIds 需要更新的用户ID集合 - * (仅处理集合中存在的有效用户) - * @see RedisUserConstant Redis键前缀常量 - */ - public void updateUserRedisInfo(List userIds) { - if (userIds.isEmpty()) return; - - // 批量查询用户 - List adminUsers = userMapper.selectBatchIds(userIds); - // 并行处理用户更新 - adminUsers.stream() - .filter(user -> redisTemplate.hasKey(RedisUserConstant.getUserLoginInfoPrefix(user.getUsername()))) - .forEach(user -> { - // 更新时清除缓存中的角色和权限 - String username = user.getUsername(); - userAuthorizationCacheService.deleteRoleAndPermissionCache(username); - - // 更新用户权限信息 - userLoginVoBuilderCacheService.buildLoginUserVo(user, RedisUserConstant.REDIS_EXPIRATION_TIME); - }); - } - - /** - * 处理角色更新事件 - * - * @param roleIds 角色ID - */ - @Async - public void updateBatchUserRedisInfoByRoleId(List roleIds) { - // 批量查询关联用户ID - List userRoles = userRoleMapper.selectListByRoleIds(roleIds); - List userIds = userRoles.stream().map(UserRole::getUserId).toList(); - updateUserRedisInfo(userIds); - } - - /** - * 处理权限更新事件 - * - * @param permissionIds 权限ID - */ - @Async - public void updateBatchUserRedisInfoByPermissionId(List permissionIds) { - // 批量查询关联用户ID - List rolePermissions = rolePermissionMapper.selectRolePermissionListByPermissionIds(permissionIds); - List roleIds = rolePermissions.stream().map(RolePermission::getRoleId).toList(); - updateBatchUserRedisInfoByRoleId(roleIds); - } - - /** - * 清除用户登录时的缓存 - * - * @param username 用户名 - */ - public void deleteLoginUserCache(String username) { - String userRolesCodePrefix = RedisUserConstant.getUserRolesCodePrefix(username); - redisTemplate.delete(userRolesCodePrefix); - } - - /** - * 清除用户登录时的缓存 - * - * @param username 用户名 - */ - public void deleteUserCache(String username) { - userAuthorizationCacheService.deleteRoleAndPermissionCache(username); - deleteLoginUserCache(username); - } -} diff --git a/service/src/main/java/cn/bunny/services/security/service/TokenValidationService.java b/service/src/main/java/cn/bunny/services/security/service/TokenValidationService.java index e8740a5..6554cf8 100644 --- a/service/src/main/java/cn/bunny/services/security/service/TokenValidationService.java +++ b/service/src/main/java/cn/bunny/services/security/service/TokenValidationService.java @@ -1,13 +1,15 @@ package cn.bunny.services.security.service; -import cn.bunny.services.core.cache.UserCacheService; +import cn.bunny.services.domain.common.constant.RedisUserConstant; import cn.bunny.services.domain.common.enums.ResultCodeEnum; import cn.bunny.services.domain.common.model.dto.security.TokenInfo; import cn.bunny.services.domain.common.model.vo.LoginVo; import cn.bunny.services.security.exception.CustomAuthenticationException; import cn.bunny.services.utils.JwtTokenUtil; +import com.alibaba.fastjson2.JSON; import jakarta.annotation.Resource; import jakarta.servlet.http.HttpServletRequest; +import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; /** @@ -17,7 +19,7 @@ import org.springframework.stereotype.Service; public class TokenValidationService { @Resource - private UserCacheService userCacheService; + private RedisTemplate redisTemplate; public TokenInfo validateToken(HttpServletRequest request) { // 判断是否有 token @@ -37,7 +39,8 @@ public class TokenValidationService { Long userId = JwtTokenUtil.getUserId(token); // 查找 Redis - LoginVo loginVo = userCacheService.getLoginVoByUsername(username); + Object loginVoObject = redisTemplate.opsForValue().get(RedisUserConstant.getUserLoginInfoPrefix(username)); + LoginVo loginVo = JSON.parseObject(JSON.toJSONString(loginVoObject), LoginVo.class); return TokenInfo.builder().userId(userId).username(username).token(token).loginVo(loginVo).build(); } diff --git a/service/src/main/java/cn/bunny/services/service/configuration/impl/I18nServiceImpl.java b/service/src/main/java/cn/bunny/services/service/configuration/impl/I18nServiceImpl.java index a516725..994b247 100644 --- a/service/src/main/java/cn/bunny/services/service/configuration/impl/I18nServiceImpl.java +++ b/service/src/main/java/cn/bunny/services/service/configuration/impl/I18nServiceImpl.java @@ -1,6 +1,6 @@ package cn.bunny.services.service.configuration.impl; -import cn.bunny.services.core.excel.I18nExcelListener; +import cn.bunny.services.core.event.listener.excel.I18nExcelListener; import cn.bunny.services.core.strategy.export.ExcelExportStrategy; import cn.bunny.services.core.strategy.export.JsonExportStrategy; import cn.bunny.services.domain.common.constant.FileType; diff --git a/service/src/main/java/cn/bunny/services/service/system/impl/PermissionServiceImpl.java b/service/src/main/java/cn/bunny/services/service/system/impl/PermissionServiceImpl.java index 8d9c752..bd7fb4f 100644 --- a/service/src/main/java/cn/bunny/services/service/system/impl/PermissionServiceImpl.java +++ b/service/src/main/java/cn/bunny/services/service/system/impl/PermissionServiceImpl.java @@ -1,10 +1,10 @@ package cn.bunny.services.service.system.impl; -import cn.bunny.services.core.excel.PermissionExcelListener; +import cn.bunny.services.core.event.event.UpdateUserinfoByPermissionIdsEvent; +import cn.bunny.services.core.event.listener.excel.PermissionExcelListener; import cn.bunny.services.core.strategy.export.ExcelExportStrategy; import cn.bunny.services.core.strategy.export.JsonExportStrategy; import cn.bunny.services.core.template.PermissionTreeProcessor; -import cn.bunny.services.core.utils.UserServiceHelper; import cn.bunny.services.domain.common.constant.FileType; import cn.bunny.services.domain.common.enums.ResultCodeEnum; import cn.bunny.services.domain.common.model.dto.excel.PermissionExcel; @@ -32,6 +32,7 @@ import org.springframework.beans.BeanUtils; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.Cacheable; import org.springframework.cache.annotation.Caching; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -63,7 +64,7 @@ public class PermissionServiceImpl extends ServiceImpl ids = List.of(dto.getId()); + applicationEventPublisher.publishEvent(new UpdateUserinfoByPermissionIdsEvent(this, ids)); } /** @@ -174,7 +176,7 @@ public class PermissionServiceImpl extends ServiceImpl permissionList = dto.getIds().stream().map(id -> { + List ids = dto.getIds(); + List permissionList = ids.stream().map(id -> { Permission permission = new Permission(); permission.setId(id); permission.setParentId(dto.getParentId()); @@ -198,7 +201,7 @@ public class PermissionServiceImpl extends ServiceImpl ids = list.stream().map(PermissionUpdateDto::getId).toList(); - userServiceHelper.updateBatchUserRedisInfoByPermissionId(ids); + applicationEventPublisher.publishEvent(new UpdateUserinfoByPermissionIdsEvent(this, ids)); } } diff --git a/service/src/main/java/cn/bunny/services/service/system/impl/RolePermissionServiceImpl.java b/service/src/main/java/cn/bunny/services/service/system/impl/RolePermissionServiceImpl.java index 7ffe2c8..561c089 100644 --- a/service/src/main/java/cn/bunny/services/service/system/impl/RolePermissionServiceImpl.java +++ b/service/src/main/java/cn/bunny/services/service/system/impl/RolePermissionServiceImpl.java @@ -1,6 +1,6 @@ package cn.bunny.services.service.system.impl; -import cn.bunny.services.core.utils.UserServiceHelper; +import cn.bunny.services.core.event.event.UpdateUserinfoByRoleIdsEvent; import cn.bunny.services.domain.system.system.dto.AssignPowersToRoleDto; import cn.bunny.services.domain.system.system.entity.AdminUser; import cn.bunny.services.domain.system.system.entity.RolePermission; @@ -12,6 +12,7 @@ import cn.bunny.services.service.system.RolePermissionService; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import jakarta.annotation.Resource; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -36,7 +37,7 @@ public class RolePermissionServiceImpl extends ServiceImpl ids = List.of(roleId); + baseMapper.deleteBatchRoleIds(ids); // 保存分配数据 List rolePermissionList = powerIds.stream().map(powerId -> { @@ -85,6 +87,6 @@ public class RolePermissionServiceImpl extends ServiceImpl implements Ro private static final String CACHE_NAMES = "role"; @Resource - private UserRoleMapper userRoleMapper; - - @Resource - private RolePermissionMapper rolePermissionMapper; - - @Resource - private RouterRoleMapper routerRoleMapper; - - @Resource - private UserServiceHelper userServiceHelper; + private ApplicationEventPublisher applicationEventPublisher; /** * 角色 服务实现类 @@ -231,7 +220,8 @@ public class RoleServiceImpl extends ServiceImpl implements Ro updateById(role); // 发布角色更新事件 - userServiceHelper.updateBatchUserRedisInfoByRoleId(List.of(roleId)); + List ids = List.of(roleId); + applicationEventPublisher.publishEvent(new UpdateUserinfoByRoleIdsEvent(this, ids)); } /** @@ -249,7 +239,7 @@ public class RoleServiceImpl extends ServiceImpl implements Ro if (ids.isEmpty()) throw new AuthCustomerException(ResultCodeEnum.REQUEST_IS_EMPTY); // 重新构建角色和用户缓存 - userServiceHelper.updateBatchUserRedisInfoByRoleId(ids); + applicationEventPublisher.publishEvent(new UpdateUserinfoByRoleIdsEvent(this, ids)); // 删除角色 removeByIds(ids); diff --git a/service/src/main/java/cn/bunny/services/service/system/impl/UserLoginServiceImpl.java b/service/src/main/java/cn/bunny/services/service/system/impl/UserLoginServiceImpl.java index 3ebe811..4b8bea3 100644 --- a/service/src/main/java/cn/bunny/services/service/system/impl/UserLoginServiceImpl.java +++ b/service/src/main/java/cn/bunny/services/service/system/impl/UserLoginServiceImpl.java @@ -3,12 +3,12 @@ package cn.bunny.services.service.system.impl; import cn.bunny.services.context.BaseContext; import cn.bunny.services.core.cache.EmailCacheService; import cn.bunny.services.core.cache.UserLoginVoBuilderCacheService; +import cn.bunny.services.core.event.event.ClearAllUserCacheEvent; import cn.bunny.services.core.strategy.login.DefaultLoginStrategy; import cn.bunny.services.core.strategy.login.EmailLoginStrategy; import cn.bunny.services.core.strategy.login.LoginContext; import cn.bunny.services.core.strategy.login.LoginStrategy; import cn.bunny.services.core.template.email.ConcreteSenderEmailTemplate; -import cn.bunny.services.core.utils.UserServiceHelper; import cn.bunny.services.domain.common.constant.RedisUserConstant; import cn.bunny.services.domain.common.constant.UserConstant; import cn.bunny.services.domain.common.enums.EmailTemplateEnums; @@ -16,6 +16,7 @@ import cn.bunny.services.domain.common.enums.LoginEnums; import cn.bunny.services.domain.common.enums.ResultCodeEnum; import cn.bunny.services.domain.common.model.vo.LoginVo; import cn.bunny.services.domain.system.email.entity.EmailTemplate; +import cn.bunny.services.domain.system.log.entity.UserLoginLog; import cn.bunny.services.domain.system.system.dto.user.AdminUserUpdateByLocalUserDto; import cn.bunny.services.domain.system.system.dto.user.LoginDto; import cn.bunny.services.domain.system.system.dto.user.RefreshTokenDto; @@ -23,6 +24,7 @@ import cn.bunny.services.domain.system.system.entity.AdminUser; import cn.bunny.services.domain.system.system.vo.user.RefreshTokenVo; import cn.bunny.services.exception.AuthCustomerException; import cn.bunny.services.mapper.configuration.EmailTemplateMapper; +import cn.bunny.services.mapper.log.UserLoginLogMapper; import cn.bunny.services.mapper.system.UserMapper; import cn.bunny.services.minio.MinioHelper; import cn.bunny.services.service.system.UserLoginService; @@ -34,20 +36,21 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; import org.jetbrains.annotations.NotNull; import org.springframework.beans.BeanUtils; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; import java.util.HashMap; @Service public class UserLoginServiceImpl extends ServiceImpl implements UserLoginService { - @Resource - private UserServiceHelper userServiceHelper; - @Resource private PasswordEncoder passwordEncoder; @@ -57,6 +60,9 @@ public class UserLoginServiceImpl extends ServiceImpl imp @Resource private EmailTemplateMapper emailTemplateMapper; + @Resource + private UserLoginLogMapper userLoginLogMapper; + @Resource private ConcreteSenderEmailTemplate concreteSenderEmailTemplate; @@ -70,7 +76,7 @@ public class UserLoginServiceImpl extends ServiceImpl imp private EmailCacheService emailCacheService; @Resource - private UserServiceHelper serviceHelper; + private ApplicationEventPublisher applicationEventPublisher; /** * 前台用户登录接口 @@ -131,7 +137,7 @@ public class UserLoginServiceImpl extends ServiceImpl imp LoginVo loginVo = userLoginVoBuilderCacheService.buildLoginUserVo(user, readMeDay); // 将用户登录保存在用户登录日志表中 - userServiceHelper.setUserLoginLog(user, loginVo.getToken(), UserConstant.LOGIN); + setUserLoginLog(user, loginVo.getToken(), UserConstant.LOGIN); return loginVo; } @@ -225,12 +231,11 @@ public class UserLoginServiceImpl extends ServiceImpl imp AdminUser adminUser = getOne(Wrappers.lambdaQuery().eq(AdminUser::getId, userId)); adminUser.setIpAddress(ipAddr); adminUser.setIpRegion(ipRegion); - userServiceHelper.setUserLoginLog(adminUser, token, UserConstant.LOGOUT); + setUserLoginLog(adminUser, token, UserConstant.LOGOUT); // 删除Redis中用户信息 String username = adminUser.getUsername(); - - serviceHelper.deleteUserCache(username); + applicationEventPublisher.publishEvent(new ClearAllUserCacheEvent(this, username)); } @@ -289,6 +294,48 @@ public class UserLoginServiceImpl extends ServiceImpl imp updateById(adminUser); // 删除Redis中登录用户信息、角色、权限信息 - serviceHelper.deleteUserCache(adminUser.getUsername()); + String username = adminUser.getUsername(); + applicationEventPublisher.publishEvent(new ClearAllUserCacheEvent(this, username)); + } + + /** + * 设置用户登录日志内容 + *

+ * 该方法用于将管理员用户信息复制到用户登录日志对象中,同时处理特殊字段映射关系。 + *

+ * 实现说明: + * 1. 使用BeanUtils.copyProperties()复制属性时,会自动将AdminUser.id复制到UserLoginLog.id + * 2. 由于UserLoginLog实际需要的是userId字段而非id字段,需要特殊处理: + * - 先进行属性复制 + * - 然后将UserLoginLog.userId设置为AdminUser.id + * - 最后将UserLoginLog.id显式设为null(避免自动生成的id被覆盖) + * + * @param user 管理员用户实体对象,包含用户基本信息 + * @param token 本次登录/退出的认证令牌 + * @param type 操作类型(LOGIN-登录/LOGOUT-退出) + */ + public void setUserLoginLog(AdminUser user, String token, String type) { + UserLoginLog userLoginLog = new UserLoginLog(); + BeanUtils.copyProperties(user, userLoginLog); + userLoginLog.setUserId(user.getId()); + userLoginLog.setId(null); + userLoginLog.setToken(token); + userLoginLog.setType(type); + + // 当前请求request + ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); + if (requestAttributes != null) { + HttpServletRequest request = requestAttributes.getRequest(); + + // 获取User-Agent + String userAgent = request.getHeader("User-Agent"); + userLoginLog.setUserAgent(userAgent); + + // 获取X-Requested-With + String xRequestedWith = request.getHeader("X-Requested-With"); + userLoginLog.setXRequestedWith(xRequestedWith); + } + + userLoginLogMapper.insert(userLoginLog); } } diff --git a/service/src/main/java/cn/bunny/services/service/system/impl/UserRoleServiceImpl.java b/service/src/main/java/cn/bunny/services/service/system/impl/UserRoleServiceImpl.java index 4b63af0..6931ece 100644 --- a/service/src/main/java/cn/bunny/services/service/system/impl/UserRoleServiceImpl.java +++ b/service/src/main/java/cn/bunny/services/service/system/impl/UserRoleServiceImpl.java @@ -1,6 +1,6 @@ package cn.bunny.services.service.system.impl; -import cn.bunny.services.core.utils.UserServiceHelper; +import cn.bunny.services.core.event.event.UpdateUserinfoByUserIdsEvent; import cn.bunny.services.domain.common.enums.ResultCodeEnum; import cn.bunny.services.domain.system.system.dto.user.AssignRolesToUsersDto; import cn.bunny.services.domain.system.system.entity.AdminUser; @@ -12,6 +12,7 @@ import cn.bunny.services.service.system.UserRoleService; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import jakarta.annotation.Resource; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -36,7 +37,7 @@ public class UserRoleServiceImpl extends ServiceImpl i private UserMapper userMapper; @Resource - private UserServiceHelper serviceHelper; + private ApplicationEventPublisher applicationEventPublisher; /** * * 根据用户id获取角色列表 @@ -69,7 +70,8 @@ public class UserRoleServiceImpl extends ServiceImpl i } // 删除这个用户下所有已经分配好的角色内容 - baseMapper.deleteBatchIdsByUserIds(List.of(userId)); + List ids = List.of(userId); + baseMapper.deleteBatchIdsByUserIds(ids); // 保存分配好的角色信息 List roleList = roleIds.stream().map(roleId -> { @@ -81,6 +83,6 @@ public class UserRoleServiceImpl extends ServiceImpl i saveBatch(roleList); // 重新设置Redis中的用户存储信息vo对象 - serviceHelper.updateUserRedisInfo(List.of(userId)); + applicationEventPublisher.publishEvent(new UpdateUserinfoByUserIdsEvent(this, ids)); } } diff --git a/service/src/main/java/cn/bunny/services/service/system/impl/UserServiceImpl.java b/service/src/main/java/cn/bunny/services/service/system/impl/UserServiceImpl.java index ee8e2c0..867ca1b 100644 --- a/service/src/main/java/cn/bunny/services/service/system/impl/UserServiceImpl.java +++ b/service/src/main/java/cn/bunny/services/service/system/impl/UserServiceImpl.java @@ -1,9 +1,10 @@ package cn.bunny.services.service.system.impl; import cn.bunny.services.core.cache.RedisService; -import cn.bunny.services.core.cache.UserCacheService; -import cn.bunny.services.core.utils.UserServiceHelper; +import cn.bunny.services.core.event.event.ClearAllUserCacheEvent; +import cn.bunny.services.core.event.event.UpdateUserinfoByUserIdsEvent; import cn.bunny.services.domain.common.constant.MinioConstant; +import cn.bunny.services.domain.common.constant.RedisUserConstant; import cn.bunny.services.domain.common.constant.UserConstant; import cn.bunny.services.domain.common.enums.ResultCodeEnum; import cn.bunny.services.domain.common.model.vo.LoginVo; @@ -29,6 +30,7 @@ import cn.bunny.services.mapper.system.UserRoleMapper; import cn.bunny.services.minio.MinioHelper; import cn.bunny.services.service.system.FilesService; import cn.bunny.services.service.system.UserService; +import com.alibaba.fastjson2.JSON; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.Wrappers; @@ -37,6 +39,8 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import jakarta.annotation.Resource; import jakarta.validation.Valid; import org.springframework.beans.BeanUtils; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.data.redis.core.RedisTemplate; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -81,10 +85,10 @@ public class UserServiceImpl extends ServiceImpl implemen private RedisService redisService; @Resource - private UserCacheService userCacheService; + private RedisTemplate redisTemplate; @Resource - private UserServiceHelper userServiceHelper; + private ApplicationEventPublisher applicationEventPublisher; /** * 获取用户信息 @@ -144,7 +148,7 @@ public class UserServiceImpl extends ServiceImpl implemen // 删除Redis中用户信息 String username = adminUser.getUsername(); - userServiceHelper.deleteUserCache(username); + applicationEventPublisher.publishEvent(new ClearAllUserCacheEvent(this, username)); } /** @@ -189,7 +193,8 @@ public class UserServiceImpl extends ServiceImpl implemen List keys = redisService.scannerRedisKeyByPage(pageNum, pageSize); List list = keys.stream().map(key -> { - LoginVo loginVo = userCacheService.getLoginVoByUsername(key); + Object loginVoObject = redisTemplate.opsForValue().get(RedisUserConstant.getUserLoginInfoPrefix(key)); + LoginVo loginVo = JSON.parseObject(JSON.toJSONString(loginVoObject), LoginVo.class); UserVo userVo = new UserVo(); BeanUtils.copyProperties(loginVo, userVo); @@ -305,7 +310,8 @@ public class UserServiceImpl extends ServiceImpl implemen updateById(adminUser); // 同步到 Redis - userServiceHelper.updateUserRedisInfo(List.of(adminUser.getId())); + List ids = List.of(adminUser.getId()); + applicationEventPublisher.publishEvent(new UpdateUserinfoByUserIdsEvent(this, ids)); } /** @@ -324,11 +330,7 @@ public class UserServiceImpl extends ServiceImpl implemen if (!roleList.isEmpty()) throw new AuthCustomerException(ResultCodeEnum.ADMIN_ROLE_CAN_NOT_DELETED); // 清除Redis中数据 - List adminUserList = list(Wrappers.lambdaQuery().eq(AdminUser::getId, ids)); - adminUserList.parallelStream().forEach(adminUser -> { - String username = adminUser.getUsername(); - userServiceHelper.deleteLoginUserCache(username); - }); + applicationEventPublisher.publishEvent(new UpdateUserinfoByUserIdsEvent(this, ids)); // 删除部门相关 userDeptMapper.deleteBatchIdsByUserIds(ids);