Compare commits
3 Commits
1d3d09d112
...
3e66d8461b
| Author | SHA1 | Date | |
|---|---|---|---|
| 3e66d8461b | |||
| 5ed0e5aaf9 | |||
| ed980e953a |
@@ -21,6 +21,8 @@ public class RabbitMQConfig {
|
|||||||
private static final String QUEUE = "HOST_INFO_QUEUE";
|
private static final String QUEUE = "HOST_INFO_QUEUE";
|
||||||
|
|
||||||
public static final String EXCHANGE_NAME = "user.headers.exchange";
|
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";
|
||||||
|
|
||||||
//创建队列
|
//创建队列
|
||||||
//true:表示持久化
|
//true:表示持久化
|
||||||
@@ -46,6 +48,20 @@ public class RabbitMQConfig {
|
|||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public HeadersExchange aiChatHeadersExchange() {
|
||||||
|
return ExchangeBuilder.headersExchange(AI_CHAT_EXCHANGE_NAME)
|
||||||
|
.durable(true)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public HeadersExchange bigBrotherHeadersExchange() {
|
||||||
|
return ExchangeBuilder.headersExchange(BIG_BROTHER_EXCHANGE_NAME)
|
||||||
|
.durable(true)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public RabbitAdmin rabbitAdmin(ConnectionFactory cf) {
|
public RabbitAdmin rabbitAdmin(ConnectionFactory cf) {
|
||||||
return new RabbitAdmin(cf);
|
return new RabbitAdmin(cf);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package com.yupi.springbootinit.service.impl;
|
|||||||
import cn.dev33.satoken.stp.StpUtil;
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
import cn.hutool.core.bean.BeanUtil;
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
import cn.hutool.core.date.DateUtil;
|
import cn.hutool.core.date.DateUtil;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.yupi.springbootinit.common.ErrorCode;
|
import com.yupi.springbootinit.common.ErrorCode;
|
||||||
import com.yupi.springbootinit.exception.BusinessException;
|
import com.yupi.springbootinit.exception.BusinessException;
|
||||||
import com.yupi.springbootinit.mapper.SystemTenantMapper;
|
import com.yupi.springbootinit.mapper.SystemTenantMapper;
|
||||||
@@ -44,11 +45,11 @@ public class LoginService {
|
|||||||
@Resource
|
@Resource
|
||||||
private RedisTemplate<String, Boolean> redisTemplate;
|
private RedisTemplate<String, Boolean> redisTemplate;
|
||||||
|
|
||||||
/** 已创建过 RabbitMQ 队列的租户 ID 集合,防止重复创建 */
|
/** AI聊天使用的 HeadersExchange */
|
||||||
private final Set<String> created = ConcurrentHashMap.newKeySet();
|
private final HeadersExchange aiChatHeadersExchange;
|
||||||
|
|
||||||
/** 用户事件使用的 HeadersExchange */
|
/** 大哥使用的 HeadersExchange */
|
||||||
private final HeadersExchange userHeadersExchange;
|
private final HeadersExchange bigBrotherHeadersExchange;
|
||||||
|
|
||||||
/** RabbitMQ 管理组件 */
|
/** RabbitMQ 管理组件 */
|
||||||
@Resource
|
@Resource
|
||||||
@@ -74,26 +75,40 @@ public class LoginService {
|
|||||||
// 2. 按场景校验角色权限
|
// 2. 按场景校验角色权限
|
||||||
checkRole(scene, user.getId());
|
checkRole(scene, user.getId());
|
||||||
|
|
||||||
|
|
||||||
// 3. AI_CHAT 场景专属逻辑:缓存登录状态并动态创建 RabbitMQ 队列
|
// 3. AI_CHAT 场景专属逻辑:缓存登录状态并动态创建 RabbitMQ 队列
|
||||||
if (scene.equals(LoginSceneEnum.AI_CHAT)) {
|
if (scene.equals(LoginSceneEnum.AI_CHAT)) {
|
||||||
// 记录该用户已登录 AI_CHAT
|
// 记录该用户已登录 AI_CHAT
|
||||||
redisTemplate.opsForValue().set("ai_login:" + user.getTenantId() + ":" + user.getId(), true);
|
redisTemplate.opsForValue().set("ai_login:" + user.getTenantId() + ":" + user.getId(), true);
|
||||||
|
|
||||||
String queueName = "q.tenant." + user.getTenantId();
|
String queueName = "q.tenant." + user.getTenantId();
|
||||||
// 若该租户队列尚未创建,则创建队列并绑定到 HeadersExchange
|
// 若该租户队列尚未创建,则创建队列并绑定到 HeadersExchange
|
||||||
if (created.add(String.valueOf(user.getTenantId()))) {
|
|
||||||
Queue queue = QueueBuilder.durable(queueName).build();
|
Queue queue = QueueBuilder.durable(queueName).build();
|
||||||
rabbitAdmin.declareQueue(queue);
|
rabbitAdmin.declareQueue(queue);
|
||||||
|
|
||||||
Map<String, Object> headers = Map.of("tenantId", user.getTenantId(), "x-match", "all");
|
Map<String, Object> headers = Map.of("tenantId", user.getTenantId(), "x-match", "all");
|
||||||
Binding binding = BindingBuilder
|
Binding binding = BindingBuilder
|
||||||
.bind(queue)
|
.bind(queue)
|
||||||
.to(userHeadersExchange)
|
.to(aiChatHeadersExchange) // 使用AI聊天专用交换机
|
||||||
.whereAll(headers)
|
.whereAll(headers)
|
||||||
.match();
|
.match();
|
||||||
rabbitAdmin.declareBinding(binding);
|
rabbitAdmin.declareBinding(binding);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// 3. 大哥场景专属逻辑:缓存登录状态并动态创建 RabbitMQ 队列
|
||||||
|
if (scene.equals(LoginSceneEnum.BIG_BROTHER)) {
|
||||||
|
// 记录该用户已登录 BIG_BROTHER
|
||||||
|
redisTemplate.opsForValue().set("bigbrother_login:" + user.getTenantId() + ":" + user.getId(), true);
|
||||||
|
String queueName = "b.tenant." + user.getTenantId();
|
||||||
|
// 若该租户队列尚未创建,则创建队列并绑定到 HeadersExchange
|
||||||
|
Queue queue = QueueBuilder.durable(queueName).build();
|
||||||
|
rabbitAdmin.declareQueue(queue);
|
||||||
|
Map<String, Object> headers = Map.of("tenantId", user.getTenantId(), "x-match", "all");
|
||||||
|
Binding binding = BindingBuilder
|
||||||
|
.bind(queue)
|
||||||
|
.to(bigBrotherHeadersExchange) // 使用大哥专用交换机
|
||||||
|
.whereAll(headers)
|
||||||
|
.match();
|
||||||
|
rabbitAdmin.declareBinding(binding);
|
||||||
|
}
|
||||||
|
|
||||||
SystemTenant systemTenant = tenantMapper.selectById(user.getTenantId());
|
SystemTenant systemTenant = tenantMapper.selectById(user.getTenantId());
|
||||||
// 封装返回数据
|
// 封装返回数据
|
||||||
SystemUsersVO vo = new SystemUsersVO();
|
SystemUsersVO vo = new SystemUsersVO();
|
||||||
@@ -189,7 +204,6 @@ public class LoginService {
|
|||||||
|
|
||||||
// 3. 若该租户下已无 AI_CHAT 在线用户,则删除队列
|
// 3. 若该租户下已无 AI_CHAT 在线用户,则删除队列
|
||||||
if (!redisUtils.hasKeyByPrefix("ai_login:" + usersDTO.getTenantId())) {
|
if (!redisUtils.hasKeyByPrefix("ai_login:" + usersDTO.getTenantId())) {
|
||||||
created.remove(String.valueOf(usersDTO.getTenantId()));
|
|
||||||
boolean b = rabbitAdmin.deleteQueue("q.tenant." + usersDTO.getTenantId());
|
boolean b = rabbitAdmin.deleteQueue("q.tenant." + usersDTO.getTenantId());
|
||||||
log.info("删除租户:{} 队列删除状态:{}", usersDTO.getTenantId(), b);
|
log.info("删除租户:{} 队列删除状态:{}", usersDTO.getTenantId(), b);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -93,9 +93,7 @@ sa-token:
|
|||||||
# token 名称(同时也是 cookie 名称)
|
# token 名称(同时也是 cookie 名称)
|
||||||
token-name: vvtoken
|
token-name: vvtoken
|
||||||
# token 有效期(单位:秒) 默认30天,-1 代表永久有效
|
# token 有效期(单位:秒) 默认30天,-1 代表永久有效
|
||||||
timeout: 604800
|
timeout: 172800
|
||||||
# token 最低活跃频率(单位:秒),如果 token 超过此时间没有访问系统就会被冻结,默认-1 代表不限制,永不冻结
|
|
||||||
active-timeout: -1
|
|
||||||
# 是否允许同一账号多地同时登录 (为 true 时允许一起登录, 为 false 时新登录挤掉旧登录)
|
# 是否允许同一账号多地同时登录 (为 true 时允许一起登录, 为 false 时新登录挤掉旧登录)
|
||||||
is-concurrent: false
|
is-concurrent: false
|
||||||
# 在多人登录同一账号时,是否共用一个 token (为 true 时所有登录共用一个 token, 为 false 时每次登录新建一个 token)
|
# 在多人登录同一账号时,是否共用一个 token (为 true 时所有登录共用一个 token, 为 false 时每次登录新建一个 token)
|
||||||
|
|||||||
Reference in New Issue
Block a user