From e2eb5f9ad07c620c8ec7dcd386c408b58980ae91 Mon Sep 17 00:00:00 2001 From: ziin Date: Fri, 5 Dec 2025 13:57:16 +0800 Subject: [PATCH] =?UTF-8?q?feat(login):=20=E6=96=B0=E5=A2=9E=E7=BD=91?= =?UTF-8?q?=E9=A1=B5AI=E7=99=BB=E5=BD=95=E5=9C=BA=E6=99=AFWEB=5FAI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在LoginSceneEnum中增加WEB_AI枚举,绑定路径webAi-doLogin - LoginService扩展WEB_AI登录逻辑:缓存登录态、创建w.tenant.{tenantId}队列并绑定webAiHeadersExchange - 新增webAiHeadersExchange Bean,交换机名web.ai.headers.exchange - 用户实体与Service增加web_ai字段及checkWebAILoginRole权限校验 - 提供/webAi-doLogin接口,支持网页端AI独立登录与Token管理 --- .../springbootinit/config/RabbitMQConfig.java | 9 ++++ .../config/SaTokenConfigure.java | 1 + .../controller/UserController.java | 5 +++ .../model/entity/SystemUsers.java | 7 ++++ .../model/enums/LoginSceneEnum.java | 3 +- .../service/SystemUsersService.java | 2 + .../service/impl/LoginService.java | 42 +++++++++++++++++-- .../service/impl/SystemUsersServiceImpl.java | 7 ++++ 8 files changed, 72 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/yupi/springbootinit/config/RabbitMQConfig.java b/src/main/java/com/yupi/springbootinit/config/RabbitMQConfig.java index 4ad6dca..611021b 100644 --- a/src/main/java/com/yupi/springbootinit/config/RabbitMQConfig.java +++ b/src/main/java/com/yupi/springbootinit/config/RabbitMQConfig.java @@ -23,6 +23,7 @@ public class RabbitMQConfig { public static final String EXCHANGE_NAME = "user.headers.exchange"; public static final String AI_CHAT_EXCHANGE_NAME = "ai.chat.headers.exchange"; public static final String BIG_BROTHER_EXCHANGE_NAME = "big.brother.headers.exchange"; + public static final String WEB_AI_EXCHANGE_NAME = "web.ai.headers.exchange"; //创建队列 //true:表示持久化 @@ -55,12 +56,20 @@ public class RabbitMQConfig { .build(); } + @Bean public HeadersExchange bigBrotherHeadersExchange() { return ExchangeBuilder.headersExchange(BIG_BROTHER_EXCHANGE_NAME) .durable(true) .build(); } + /** 网页AI使用的 HeadersExchange */ + @Bean + public HeadersExchange webAiHeadersExchange() { + return ExchangeBuilder.headersExchange(WEB_AI_EXCHANGE_NAME) + .durable(true) + .build(); + } @Bean public RabbitAdmin rabbitAdmin(ConnectionFactory cf) { diff --git a/src/main/java/com/yupi/springbootinit/config/SaTokenConfigure.java b/src/main/java/com/yupi/springbootinit/config/SaTokenConfigure.java index 87208bb..19acb90 100644 --- a/src/main/java/com/yupi/springbootinit/config/SaTokenConfigure.java +++ b/src/main/java/com/yupi/springbootinit/config/SaTokenConfigure.java @@ -50,6 +50,7 @@ public class SaTokenConfigure implements WebMvcConfigurer { "/user/bigbrother-doLogin", "/user/aiChat-doLogin", "/user/aiChat-logout", + "/user/webAi-doLogin", "/error", }; } diff --git a/src/main/java/com/yupi/springbootinit/controller/UserController.java b/src/main/java/com/yupi/springbootinit/controller/UserController.java index b26fcff..f3148d4 100644 --- a/src/main/java/com/yupi/springbootinit/controller/UserController.java +++ b/src/main/java/com/yupi/springbootinit/controller/UserController.java @@ -58,6 +58,11 @@ public class UserController { return ResultUtils.success(loginService.aiChatLogout(usersDTO)); } + @PostMapping("webAi-doLogin") + public BaseResponse webAiDoLogin(@RequestBody SystemUsersDTO usersDTO) { + return ResultUtils.success(loginService.login(LoginSceneEnum.WEB_AI, usersDTO)); + } + @GetMapping("/logout") public BaseResponse logout(){ return ResultUtils.success(loginService.logout()); diff --git a/src/main/java/com/yupi/springbootinit/model/entity/SystemUsers.java b/src/main/java/com/yupi/springbootinit/model/entity/SystemUsers.java index 6adeceb..4433bee 100644 --- a/src/main/java/com/yupi/springbootinit/model/entity/SystemUsers.java +++ b/src/main/java/com/yupi/springbootinit/model/entity/SystemUsers.java @@ -188,4 +188,11 @@ public class SystemUsers { @TableField(value = "ai_replay") @ApiModelProperty(value = "是否开启智能回复") private Byte aiReplay; + + /** + * 能否登录智能回复客户端 + */ + @TableField(value = "web_ai") + @ApiModelProperty(value = "能否登录智能回复客户端") + private Byte webAi; } \ No newline at end of file diff --git a/src/main/java/com/yupi/springbootinit/model/enums/LoginSceneEnum.java b/src/main/java/com/yupi/springbootinit/model/enums/LoginSceneEnum.java index fda1b2d..4d7de11 100644 --- a/src/main/java/com/yupi/springbootinit/model/enums/LoginSceneEnum.java +++ b/src/main/java/com/yupi/springbootinit/model/enums/LoginSceneEnum.java @@ -8,7 +8,8 @@ import lombok.Getter; public enum LoginSceneEnum { HOST("doLogin", "host", "checkCrawlRole"), BIG_BROTHER("bigbrother-doLogin", "bigbrother", "checkBigBrotherRole"), - AI_CHAT("aiChat-doLogin", "aiChat", "checkAiChatLoginRole"); + AI_CHAT("aiChat-doLogin", "aiChat", "checkAiChatLoginRole"), + WEB_AI("webAiChat-doLogin", "webAiChat", "checkWebAiChatLoginRole"); private final String path; // 对应 @PostMapping private final String saMode; // Sa-Token 登录模式 diff --git a/src/main/java/com/yupi/springbootinit/service/SystemUsersService.java b/src/main/java/com/yupi/springbootinit/service/SystemUsersService.java index 85e27ee..f76437a 100644 --- a/src/main/java/com/yupi/springbootinit/service/SystemUsersService.java +++ b/src/main/java/com/yupi/springbootinit/service/SystemUsersService.java @@ -24,4 +24,6 @@ public interface SystemUsersService extends IService { boolean checkbigBrotherlRole(Long userId); boolean checkAiCHatLoginRole(Long userId); + + boolean checkWebAILoginRole(Long userId); } diff --git a/src/main/java/com/yupi/springbootinit/service/impl/LoginService.java b/src/main/java/com/yupi/springbootinit/service/impl/LoginService.java index 28b84ea..032bcfe 100644 --- a/src/main/java/com/yupi/springbootinit/service/impl/LoginService.java +++ b/src/main/java/com/yupi/springbootinit/service/impl/LoginService.java @@ -51,6 +51,9 @@ public class LoginService { /** 大哥使用的 HeadersExchange */ private final HeadersExchange bigBrotherHeadersExchange; + /** 网页AI使用的 HeadersExchange */ + private final HeadersExchange webAiHeadersExchange; + /** RabbitMQ 管理组件 */ @Resource private RabbitAdmin rabbitAdmin; @@ -108,6 +111,20 @@ public class LoginService { .match(); rabbitAdmin.declareBinding(binding); } + if (scene.equals(LoginSceneEnum.WEB_AI)) { + redisTemplate.opsForValue().set("webAI_login:" + user.getTenantId() + ":" + user.getId(), true); + String queueName = "w.tenant." + user.getTenantId(); + // 若该租户队列尚未创建,则创建队列并绑定到 HeadersExchange + Queue queue = QueueBuilder.durable(queueName).build(); + rabbitAdmin.declareQueue(queue); + Map headers = Map.of("tenantId", user.getTenantId(), "x-match", "all"); + Binding binding = BindingBuilder + .bind(queue) + .to(webAiHeadersExchange) // 使用webAi专用交换机 + .whereAll(headers) + .match(); + rabbitAdmin.declareBinding(binding); + } SystemTenant systemTenant = tenantMapper.selectById(user.getTenantId()); // 封装返回数据 @@ -120,6 +137,7 @@ public class LoginService { StpUtil.login(user.getId(), scene.getSaMode()); switch (scene) { case AI_CHAT: + StpUtil.logout(user.getId(), LoginSceneEnum.WEB_AI.getSaMode()); StpUtil.renewTimeout(DateUtils.dateBetween(systemTenant.getAiExpireTime(),DateUtil.date())); BeanUtil.copyProperties(user, vo); vo.setTokenName(StpUtil.getTokenName()); @@ -140,6 +158,14 @@ public class LoginService { vo.setTokenValue(StpUtil.getTokenValue()); vo.setBrotherExpireTime(systemTenant.getBrotherExpireTime()); return vo; + case WEB_AI: + StpUtil.logout(user.getId(), LoginSceneEnum.AI_CHAT.getSaMode()); + StpUtil.renewTimeout(DateUtils.dateBetween(systemTenant.getAiExpireTime(),DateUtil.date())); + BeanUtil.copyProperties(user, vo); + vo.setTokenName(StpUtil.getTokenName()); + vo.setTokenValue(StpUtil.getTokenValue()); + vo.setAiExpireTime(systemTenant.getAiExpireTime()); + return vo; } return null; } @@ -180,6 +206,7 @@ public class LoginService { case HOST -> usersService.checkCrawlRole(userId); case BIG_BROTHER -> usersService.checkbigBrotherlRole(userId); case AI_CHAT -> usersService.checkAiCHatLoginRole(userId); + case WEB_AI -> usersService.checkWebAILoginRole(userId); }; if (!pass) { throw new BusinessException(ErrorCode.LOGIN_NOT_ALLOWED); @@ -194,19 +221,28 @@ public class LoginService { */ public Boolean aiChatLogout(SystemUsersDTO usersDTO) { // 1. 删除 Redis 中该用户的 AI_CHAT 登录标记 - Boolean delete = redisTemplate.delete("ai_login:" + usersDTO.getTenantId() + ":" + usersDTO.getUserId()); + Boolean ai_login = redisTemplate.delete("ai_login:" + usersDTO.getTenantId() + ":" + usersDTO.getUserId()); + Boolean webAi_login = redisTemplate.delete("webAI_login:" + usersDTO.getTenantId() + ":" + usersDTO.getUserId()); + // 2. 使当前 Token 失效 String tokenValue = StpUtil.getTokenValue(); StpUtil.logoutByTokenValue(tokenValue); - log.info("删除租户:{} 登录状态:{}", usersDTO.getTenantId(), delete); + log.info("删除租户:{} 登录状态:{}", usersDTO.getTenantId(), ai_login); + log.info("删除租户:{} 登录状态:{}", usersDTO.getTenantId(), webAi_login); // 3. 若该租户下已无 AI_CHAT 在线用户,则删除队列 if (!redisUtils.hasKeyByPrefix("ai_login:" + usersDTO.getTenantId())) { boolean b = rabbitAdmin.deleteQueue("q.tenant." + usersDTO.getTenantId()); - log.info("删除租户:{} 队列删除状态:{}", usersDTO.getTenantId(), b); + log.info("删除Ai_CHAT租户:{} 队列删除状态:{}", usersDTO.getTenantId(), b); } + + if (!redisUtils.hasKeyByPrefix("webAI_login:" + usersDTO.getTenantId())) { + boolean b = rabbitAdmin.deleteQueue("w.tenant." + usersDTO.getTenantId()); + log.info("删除Web_AI租户:{} 队列删除状态:{}", usersDTO.getTenantId(), b); + } + return true; } diff --git a/src/main/java/com/yupi/springbootinit/service/impl/SystemUsersServiceImpl.java b/src/main/java/com/yupi/springbootinit/service/impl/SystemUsersServiceImpl.java index 0b05f87..856baa3 100644 --- a/src/main/java/com/yupi/springbootinit/service/impl/SystemUsersServiceImpl.java +++ b/src/main/java/com/yupi/springbootinit/service/impl/SystemUsersServiceImpl.java @@ -83,5 +83,12 @@ public class SystemUsersServiceImpl extends ServiceImpl