Compare commits
9 Commits
1d3d09d112
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 49a0022ee8 | |||
| e2eb5f9ad0 | |||
| cd7aba7aaa | |||
| b69e36391e | |||
| a9ea0d1ebf | |||
| a2cdb813c7 | |||
| 3e66d8461b | |||
| 5ed0e5aaf9 | |||
| ed980e953a |
6
pom.xml
6
pom.xml
@@ -70,12 +70,6 @@
|
||||
<groupId>org.springframework.session</groupId>
|
||||
<artifactId>spring-session-data-redis</artifactId>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/com.github.binarywang/wx-java-mp-spring-boot-starter -->
|
||||
<dependency>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<artifactId>wx-java-mp-spring-boot-starter</artifactId>
|
||||
<version>4.4.0</version>
|
||||
</dependency>
|
||||
<!-- https://doc.xiaominfo.com/docs/quick-start#openapi2 -->
|
||||
<dependency>
|
||||
<groupId>com.github.xiaoymin</groupId>
|
||||
|
||||
@@ -21,6 +21,9 @@ public class RabbitMQConfig {
|
||||
private static final String QUEUE = "HOST_INFO_QUEUE";
|
||||
|
||||
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:表示持久化
|
||||
@@ -46,6 +49,28 @@ public class RabbitMQConfig {
|
||||
.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();
|
||||
}
|
||||
/** 网页AI使用的 HeadersExchange */
|
||||
@Bean
|
||||
public HeadersExchange webAiHeadersExchange() {
|
||||
return ExchangeBuilder.headersExchange(WEB_AI_EXCHANGE_NAME)
|
||||
.durable(true)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RabbitAdmin rabbitAdmin(ConnectionFactory cf) {
|
||||
return new RabbitAdmin(cf);
|
||||
|
||||
@@ -50,6 +50,7 @@ public class SaTokenConfigure implements WebMvcConfigurer {
|
||||
"/user/bigbrother-doLogin",
|
||||
"/user/aiChat-doLogin",
|
||||
"/user/aiChat-logout",
|
||||
"/user/webAi-doLogin",
|
||||
"/error",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -58,6 +58,11 @@ public class UserController {
|
||||
return ResultUtils.success(loginService.aiChatLogout(usersDTO));
|
||||
}
|
||||
|
||||
@PostMapping("webAi-doLogin")
|
||||
public BaseResponse<SystemUsersVO> webAiDoLogin(@RequestBody SystemUsersDTO usersDTO) {
|
||||
return ResultUtils.success(loginService.login(LoginSceneEnum.WEB_AI, usersDTO));
|
||||
}
|
||||
|
||||
@GetMapping("/logout")
|
||||
public BaseResponse<Boolean> logout(){
|
||||
return ResultUtils.success(loginService.logout());
|
||||
|
||||
@@ -15,7 +15,4 @@ public interface CountryInfoMapper extends BaseMapper<CountryInfo> {
|
||||
|
||||
List<CountryInfoVO> selectByCountryGroupName();
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -150,4 +150,7 @@ public class ServerBigBrother {
|
||||
@TableField(value = "tenant_id")
|
||||
@ApiModelProperty(value="租户 Id")
|
||||
private Long tenantId;
|
||||
|
||||
@TableField(value = "sec_uid")
|
||||
private String secUid;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 登录模式
|
||||
|
||||
@@ -112,4 +112,7 @@ public class ServerBigBrotherVO {
|
||||
@TableField(value = "fans_level")
|
||||
@ApiModelProperty(value = "大哥粉丝团等级")
|
||||
private Integer fansLevel;
|
||||
|
||||
@TableField(value = "sec_uid")
|
||||
private String secUid;
|
||||
}
|
||||
@@ -64,4 +64,11 @@ public class CountryInfoVO {
|
||||
@ApiModelProperty(value = "语言中文")
|
||||
private String languageName;
|
||||
|
||||
|
||||
/**
|
||||
* 国家名称英文
|
||||
*/
|
||||
@TableField(value = "country_name_english")
|
||||
@ApiModelProperty(value = "国家名称英文")
|
||||
private String countryNameEnglish;
|
||||
}
|
||||
@@ -24,4 +24,6 @@ public interface SystemUsersService extends IService<SystemUsers> {
|
||||
boolean checkbigBrotherlRole(Long userId);
|
||||
|
||||
boolean checkAiCHatLoginRole(Long userId);
|
||||
|
||||
boolean checkWebAILoginRole(Long userId);
|
||||
}
|
||||
|
||||
@@ -1,30 +1,17 @@
|
||||
package com.yupi.springbootinit.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.yupi.springbootinit.common.BaseResponse;
|
||||
import com.yupi.springbootinit.common.ResultUtils;
|
||||
import com.yupi.springbootinit.mapper.NewHostsMapper;
|
||||
import com.yupi.springbootinit.model.dto.host.HistoryDataDTO;
|
||||
import com.yupi.springbootinit.model.dto.host.HostInfoDTO;
|
||||
import com.yupi.springbootinit.model.entity.NewHosts;
|
||||
import com.yupi.springbootinit.model.vo.hosts.NewHostsVO;
|
||||
import com.yupi.springbootinit.model.vo.hosts.SevenDaysData;
|
||||
import com.yupi.springbootinit.service.HostInfoService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.StopWatch;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
/*
|
||||
* @author: ziin
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.yupi.springbootinit.service.impl;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.yupi.springbootinit.common.ErrorCode;
|
||||
import com.yupi.springbootinit.exception.BusinessException;
|
||||
import com.yupi.springbootinit.mapper.SystemTenantMapper;
|
||||
@@ -44,11 +45,14 @@ public class LoginService {
|
||||
@Resource
|
||||
private RedisTemplate<String, Boolean> redisTemplate;
|
||||
|
||||
/** 已创建过 RabbitMQ 队列的租户 ID 集合,防止重复创建 */
|
||||
private final Set<String> created = ConcurrentHashMap.newKeySet();
|
||||
/** AI聊天使用的 HeadersExchange */
|
||||
private final HeadersExchange aiChatHeadersExchange;
|
||||
|
||||
/** 用户事件使用的 HeadersExchange */
|
||||
private final HeadersExchange userHeadersExchange;
|
||||
/** 大哥使用的 HeadersExchange */
|
||||
private final HeadersExchange bigBrotherHeadersExchange;
|
||||
|
||||
/** 网页AI使用的 HeadersExchange */
|
||||
private final HeadersExchange webAiHeadersExchange;
|
||||
|
||||
/** RabbitMQ 管理组件 */
|
||||
@Resource
|
||||
@@ -74,26 +78,54 @@ public class LoginService {
|
||||
// 2. 按场景校验角色权限
|
||||
checkRole(scene, user.getId());
|
||||
|
||||
|
||||
// 3. AI_CHAT 场景专属逻辑:缓存登录状态并动态创建 RabbitMQ 队列
|
||||
if (scene.equals(LoginSceneEnum.AI_CHAT)) {
|
||||
// 记录该用户已登录 AI_CHAT
|
||||
redisTemplate.opsForValue().set("ai_login:" + user.getTenantId() + ":" + user.getId(), true);
|
||||
|
||||
String queueName = "q.tenant." + user.getTenantId();
|
||||
// 若该租户队列尚未创建,则创建队列并绑定到 HeadersExchange
|
||||
if (created.add(String.valueOf(user.getTenantId()))) {
|
||||
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(userHeadersExchange)
|
||||
.to(aiChatHeadersExchange) // 使用AI聊天专用交换机
|
||||
.whereAll(headers)
|
||||
.match();
|
||||
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);
|
||||
}
|
||||
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<String, Object> 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());
|
||||
// 封装返回数据
|
||||
SystemUsersVO vo = new SystemUsersVO();
|
||||
@@ -105,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());
|
||||
@@ -125,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;
|
||||
}
|
||||
@@ -165,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);
|
||||
@@ -179,20 +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())) {
|
||||
created.remove(String.valueOf(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;
|
||||
}
|
||||
|
||||
|
||||
@@ -83,5 +83,12 @@ public class SystemUsersServiceImpl extends ServiceImpl<SystemUsersMapper,System
|
||||
return systemUsers.getAiChat() == 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkWebAILoginRole(Long userId) {
|
||||
SystemUsers systemUsers = baseMapper.selectById(userId);
|
||||
return systemUsers.getWebAi() == 1;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -93,9 +93,7 @@ sa-token:
|
||||
# token 名称(同时也是 cookie 名称)
|
||||
token-name: vvtoken
|
||||
# token 有效期(单位:秒) 默认30天,-1 代表永久有效
|
||||
timeout: 604800
|
||||
# token 最低活跃频率(单位:秒),如果 token 超过此时间没有访问系统就会被冻结,默认-1 代表不限制,永不冻结
|
||||
active-timeout: -1
|
||||
timeout: 172800
|
||||
# 是否允许同一账号多地同时登录 (为 true 时允许一起登录, 为 false 时新登录挤掉旧登录)
|
||||
is-concurrent: false
|
||||
# 在多人登录同一账号时,是否共用一个 token (为 true 时所有登录共用一个 token, 为 false 时每次登录新建一个 token)
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
<result column="country_name" jdbcType="VARCHAR" property="countryName" />
|
||||
<result column="language" jdbcType="VARCHAR" property="language" />
|
||||
<result column="language_name" jdbcType="VARCHAR" property="languageName" />
|
||||
<result column="country_name_english" jdbcType="VARCHAR" property="countryNameEnglish" />
|
||||
</resultMap>
|
||||
<sql id="Base_Column_List">
|
||||
<!--@mbg.generated-->
|
||||
|
||||
@@ -23,12 +23,13 @@
|
||||
<result column="updater" jdbcType="VARCHAR" property="updater" />
|
||||
<result column="deleted" jdbcType="BOOLEAN" property="deleted" />
|
||||
<result column="tenant_id" jdbcType="BIGINT" property="tenantId" />
|
||||
<result column="secUid" jdbcType="VARCHAR" property="secUid" />
|
||||
</resultMap>
|
||||
<sql id="Base_Column_List">
|
||||
<!--@mbg.generated-->
|
||||
id, display_id, user_id_str, nickname, `level`, hostcoins, follower_count, following_count,
|
||||
region, historic_high_coins, total_gift_coins, host_display_id, owner_id, create_time,
|
||||
update_time, creator, updater, deleted, tenant_id
|
||||
update_time, creator, updater, deleted, tenant_id,secUid
|
||||
</sql>
|
||||
|
||||
<resultMap id="BaseResultMapCopy" type="com.yupi.springbootinit.model.vo.bigbrother.ServerBigBrotherVO">
|
||||
@@ -47,6 +48,7 @@
|
||||
<result column="host_display_id" jdbcType="VARCHAR" property="hostDisplayId" />
|
||||
<result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
|
||||
<result column="fans_level" jdbcType="INTEGER" property="fansLevel" />
|
||||
<result column="secUid" jdbcType="VARCHAR" property="secUid" />
|
||||
</resultMap>
|
||||
|
||||
|
||||
@@ -54,7 +56,7 @@
|
||||
<select id="selectPageByCondition" resultMap="BaseResultMapCopy">
|
||||
select sbr.display_id, sbr.user_id_str,sbr.nickname,sbr.level,sbr.hostcoins,
|
||||
sbr.follower_count, sbr.following_count, sbr.region, sbr.historic_high_coins, sbr.total_gift_coins,
|
||||
sbr.host_display_id,sbr.create_time,sbr.fans_level from
|
||||
sbr.host_display_id,sbr.create_time,sbr.fans_level,sbr.secUid from
|
||||
server_big_brother sbr left join server_country_info ci ON sbr.region = ci.country_name
|
||||
where sbr.tenant_id=#{dto.tenantId}
|
||||
<!-- 大哥所属国家筛选 -->
|
||||
|
||||
Reference in New Issue
Block a user