feat: 完善后端架构和service层实现
- 创建完整的entity实体类体系,包括所有业务实体 - 实现BaseEntity基类,统一管理公共字段 - 创建雪花算法ID生成器和自动填充处理器 - 简化所有mapper接口,只继承BaseMapper - 重构service层,使用LambdaQueryWrapper进行数据库操作 - 创建BasePageRequest分页查询基类 - 完善用户上下文管理和JWT认证 - 新增WebSocket聊天功能和相关控制器 - 更新前端配置和组件,完善用户认证流程 - 同步数据库建表脚本
This commit is contained in:
@@ -0,0 +1,203 @@
|
||||
package com.emotion.util;
|
||||
|
||||
import io.jsonwebtoken.*;
|
||||
import io.jsonwebtoken.security.Keys;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* JWT工具类
|
||||
*
|
||||
* @author emotion-museum
|
||||
* @date 2025-07-23
|
||||
*/
|
||||
@Component
|
||||
public class JwtUtil {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(JwtUtil.class);
|
||||
|
||||
/**
|
||||
* JWT密钥
|
||||
*/
|
||||
@Value("${emotion.jwt.secret:emotion-museum-secret-key-2025}")
|
||||
private String secret;
|
||||
|
||||
/**
|
||||
* JWT过期时间(毫秒)
|
||||
*/
|
||||
@Value("${emotion.jwt.expiration:86400000}")
|
||||
private Long expiration;
|
||||
|
||||
/**
|
||||
* 刷新Token过期时间(毫秒)
|
||||
*/
|
||||
@Value("${emotion.jwt.refresh-expiration:604800000}")
|
||||
private Long refreshExpiration;
|
||||
|
||||
/**
|
||||
* 获取密钥
|
||||
*/
|
||||
private SecretKey getSecretKey() {
|
||||
return Keys.hmacShaKeyFor(secret.getBytes());
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成Token
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param username 用户名
|
||||
* @return Token
|
||||
*/
|
||||
public String generateToken(String userId, String username) {
|
||||
return generateToken(userId, username, expiration);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成刷新Token
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param username 用户名
|
||||
* @return 刷新Token
|
||||
*/
|
||||
public String generateRefreshToken(String userId, String username) {
|
||||
return generateToken(userId, username, refreshExpiration);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成Token
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param username 用户名
|
||||
* @param expiration 过期时间(毫秒)
|
||||
* @return Token
|
||||
*/
|
||||
private String generateToken(String userId, String username, Long expiration) {
|
||||
Date now = new Date();
|
||||
Date expiryDate = new Date(now.getTime() + expiration);
|
||||
|
||||
return Jwts.builder()
|
||||
.setSubject(userId)
|
||||
.claim("username", username)
|
||||
.setIssuedAt(now)
|
||||
.setExpiration(expiryDate)
|
||||
.signWith(getSecretKey(), SignatureAlgorithm.HS512)
|
||||
.compact();
|
||||
}
|
||||
|
||||
/**
|
||||
* 从Token中获取用户ID
|
||||
*
|
||||
* @param token Token
|
||||
* @return 用户ID
|
||||
*/
|
||||
public String getUserIdFromToken(String token) {
|
||||
Claims claims = getClaimsFromToken(token);
|
||||
return claims != null ? claims.getSubject() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从Token中获取用户名
|
||||
*
|
||||
* @param token Token
|
||||
* @return 用户名
|
||||
*/
|
||||
public String getUsernameFromToken(String token) {
|
||||
Claims claims = getClaimsFromToken(token);
|
||||
return claims != null ? claims.get("username", String.class) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从Token中获取过期时间
|
||||
*
|
||||
* @param token Token
|
||||
* @return 过期时间
|
||||
*/
|
||||
public Date getExpirationDateFromToken(String token) {
|
||||
Claims claims = getClaimsFromToken(token);
|
||||
return claims != null ? claims.getExpiration() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从Token中获取Claims
|
||||
*
|
||||
* @param token Token
|
||||
* @return Claims
|
||||
*/
|
||||
private Claims getClaimsFromToken(String token) {
|
||||
try {
|
||||
return Jwts.parserBuilder()
|
||||
.setSigningKey(getSecretKey())
|
||||
.build()
|
||||
.parseClaimsJws(token)
|
||||
.getBody();
|
||||
} catch (Exception e) {
|
||||
log.warn("解析Token失败: {}", e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证Token是否有效
|
||||
*
|
||||
* @param token Token
|
||||
* @return 是否有效
|
||||
*/
|
||||
public boolean validateToken(String token) {
|
||||
if (token == null || token.trim().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
Claims claims = getClaimsFromToken(token);
|
||||
if (claims == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查是否过期
|
||||
Date expiration = claims.getExpiration();
|
||||
return expiration != null && expiration.after(new Date());
|
||||
} catch (Exception e) {
|
||||
log.warn("Token验证失败: {}", e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查Token是否过期
|
||||
*
|
||||
* @param token Token
|
||||
* @return 是否过期
|
||||
*/
|
||||
public boolean isTokenExpired(String token) {
|
||||
Date expiration = getExpirationDateFromToken(token);
|
||||
return expiration != null && expiration.before(new Date());
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新Token
|
||||
*
|
||||
* @param token 原Token
|
||||
* @return 新Token
|
||||
*/
|
||||
public String refreshToken(String token) {
|
||||
try {
|
||||
Claims claims = getClaimsFromToken(token);
|
||||
if (claims == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String userId = claims.getSubject();
|
||||
String username = claims.get("username", String.class);
|
||||
|
||||
return generateToken(userId, username);
|
||||
} catch (Exception e) {
|
||||
log.warn("刷新Token失败: {}", e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,232 @@
|
||||
package com.emotion.util;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* 雪花算法ID生成器
|
||||
* 生成64位长整型ID,转换为字符串避免前端精度丢失问题
|
||||
*
|
||||
* 雪花算法结构:
|
||||
* 1位符号位(固定为0) + 41位时间戳 + 10位机器ID + 12位序列号
|
||||
*
|
||||
* @author emotion-museum
|
||||
* @since 2025-07-23
|
||||
*/
|
||||
@Slf4j
|
||||
public class SnowflakeIdGenerator {
|
||||
|
||||
/**
|
||||
* 起始时间戳 (2024-01-01 00:00:00)
|
||||
*/
|
||||
private static final long START_TIMESTAMP = 1704067200000L;
|
||||
|
||||
/**
|
||||
* 机器ID位数
|
||||
*/
|
||||
private static final long MACHINE_ID_BITS = 10L;
|
||||
|
||||
/**
|
||||
* 序列号位数
|
||||
*/
|
||||
private static final long SEQUENCE_BITS = 12L;
|
||||
|
||||
/**
|
||||
* 机器ID最大值
|
||||
*/
|
||||
private static final long MAX_MACHINE_ID = ~(-1L << MACHINE_ID_BITS);
|
||||
|
||||
/**
|
||||
* 序列号最大值
|
||||
*/
|
||||
private static final long MAX_SEQUENCE = ~(-1L << SEQUENCE_BITS);
|
||||
|
||||
/**
|
||||
* 机器ID左移位数
|
||||
*/
|
||||
private static final long MACHINE_ID_SHIFT = SEQUENCE_BITS;
|
||||
|
||||
/**
|
||||
* 时间戳左移位数
|
||||
*/
|
||||
private static final long TIMESTAMP_SHIFT = SEQUENCE_BITS + MACHINE_ID_BITS;
|
||||
|
||||
/**
|
||||
* 机器ID
|
||||
*/
|
||||
private final long machineId;
|
||||
|
||||
/**
|
||||
* 序列号
|
||||
*/
|
||||
private long sequence = 0L;
|
||||
|
||||
/**
|
||||
* 上次生成ID的时间戳
|
||||
*/
|
||||
private long lastTimestamp = -1L;
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
*
|
||||
* @param machineId 机器ID (0-1023)
|
||||
*/
|
||||
public SnowflakeIdGenerator(long machineId) {
|
||||
if (machineId > MAX_MACHINE_ID || machineId < 0) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("机器ID必须在0到%d之间", MAX_MACHINE_ID));
|
||||
}
|
||||
this.machineId = machineId;
|
||||
log.info("雪花算法ID生成器初始化完成,机器ID: {}", machineId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 默认构造函数,使用默认机器ID
|
||||
*/
|
||||
public SnowflakeIdGenerator() {
|
||||
// 使用当前时间戳的后10位作为默认机器ID
|
||||
this(System.currentTimeMillis() % (MAX_MACHINE_ID + 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成下一个ID
|
||||
*
|
||||
* @return 生成的ID
|
||||
*/
|
||||
public synchronized long nextId() {
|
||||
long timestamp = getCurrentTimestamp();
|
||||
|
||||
// 如果当前时间小于上次ID生成的时间戳,说明系统时钟回退过,抛出异常
|
||||
if (timestamp < lastTimestamp) {
|
||||
throw new RuntimeException(
|
||||
String.format("系统时钟回退,拒绝生成ID。当前时间戳: %d, 上次时间戳: %d",
|
||||
timestamp, lastTimestamp));
|
||||
}
|
||||
|
||||
// 如果是同一时间戳,则在序列号上自增
|
||||
if (lastTimestamp == timestamp) {
|
||||
sequence = (sequence + 1) & MAX_SEQUENCE;
|
||||
// 如果序列号溢出,则等待下一个毫秒
|
||||
if (sequence == 0) {
|
||||
timestamp = getNextTimestamp(lastTimestamp);
|
||||
}
|
||||
} else {
|
||||
// 如果是新的时间戳,则序列号重置为0
|
||||
sequence = 0L;
|
||||
}
|
||||
|
||||
// 更新上次生成ID的时间戳
|
||||
lastTimestamp = timestamp;
|
||||
|
||||
// 移位并通过或运算拼到一起组成64位的ID
|
||||
return ((timestamp - START_TIMESTAMP) << TIMESTAMP_SHIFT)
|
||||
| (machineId << MACHINE_ID_SHIFT)
|
||||
| sequence;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成字符串格式的ID
|
||||
*
|
||||
* @return 字符串格式的ID
|
||||
*/
|
||||
public String nextIdAsString() {
|
||||
return String.valueOf(nextId());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前时间戳
|
||||
*
|
||||
* @return 当前时间戳
|
||||
*/
|
||||
private long getCurrentTimestamp() {
|
||||
return System.currentTimeMillis();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取下一个时间戳
|
||||
*
|
||||
* @param lastTimestamp 上次时间戳
|
||||
* @return 下一个时间戳
|
||||
*/
|
||||
private long getNextTimestamp(long lastTimestamp) {
|
||||
long timestamp = getCurrentTimestamp();
|
||||
while (timestamp <= lastTimestamp) {
|
||||
timestamp = getCurrentTimestamp();
|
||||
}
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析ID获取时间戳
|
||||
*
|
||||
* @param id 雪花算法生成的ID
|
||||
* @return 时间戳
|
||||
*/
|
||||
public long parseTimestamp(long id) {
|
||||
return (id >> TIMESTAMP_SHIFT) + START_TIMESTAMP;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析ID获取机器ID
|
||||
*
|
||||
* @param id 雪花算法生成的ID
|
||||
* @return 机器ID
|
||||
*/
|
||||
public long parseMachineId(long id) {
|
||||
return (id >> MACHINE_ID_SHIFT) & MAX_MACHINE_ID;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析ID获取序列号
|
||||
*
|
||||
* @param id 雪花算法生成的ID
|
||||
* @return 序列号
|
||||
*/
|
||||
public long parseSequence(long id) {
|
||||
return id & MAX_SEQUENCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取机器ID
|
||||
*
|
||||
* @return 机器ID
|
||||
*/
|
||||
public long getMachineId() {
|
||||
return machineId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量生成ID
|
||||
*
|
||||
* @param count 生成数量
|
||||
* @return ID数组
|
||||
*/
|
||||
public long[] nextIds(int count) {
|
||||
if (count <= 0) {
|
||||
throw new IllegalArgumentException("生成数量必须大于0");
|
||||
}
|
||||
|
||||
long[] ids = new long[count];
|
||||
for (int i = 0; i < count; i++) {
|
||||
ids[i] = nextId();
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量生成字符串格式的ID
|
||||
*
|
||||
* @param count 生成数量
|
||||
* @return 字符串ID数组
|
||||
*/
|
||||
public String[] nextIdsAsString(int count) {
|
||||
if (count <= 0) {
|
||||
throw new IllegalArgumentException("生成数量必须大于0");
|
||||
}
|
||||
|
||||
String[] ids = new String[count];
|
||||
for (int i = 0; i < count; i++) {
|
||||
ids[i] = nextIdAsString();
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,222 @@
|
||||
package com.emotion.util;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* 用户上下文持有者
|
||||
* 用于在当前线程中存储用户信息
|
||||
*
|
||||
* @author emotion-museum
|
||||
* @date 2025-07-23
|
||||
*/
|
||||
@Slf4j
|
||||
public class UserContextHolder {
|
||||
|
||||
/**
|
||||
* 用户ID线程本地变量
|
||||
*/
|
||||
private static final ThreadLocal<String> USER_ID_HOLDER = new ThreadLocal<>();
|
||||
|
||||
/**
|
||||
* 用户名线程本地变量
|
||||
*/
|
||||
private static final ThreadLocal<String> USERNAME_HOLDER = new ThreadLocal<>();
|
||||
|
||||
/**
|
||||
* 用户类型线程本地变量
|
||||
*/
|
||||
private static final ThreadLocal<String> USER_TYPE_HOLDER = new ThreadLocal<>();
|
||||
|
||||
/**
|
||||
* 客户端IP线程本地变量
|
||||
*/
|
||||
private static final ThreadLocal<String> CLIENT_IP_HOLDER = new ThreadLocal<>();
|
||||
|
||||
/**
|
||||
* 请求ID线程本地变量
|
||||
*/
|
||||
private static final ThreadLocal<String> REQUEST_ID_HOLDER = new ThreadLocal<>();
|
||||
|
||||
/**
|
||||
* 设置当前用户ID
|
||||
*
|
||||
* @param userId 用户ID
|
||||
*/
|
||||
public static void setCurrentUserId(String userId) {
|
||||
USER_ID_HOLDER.set(userId);
|
||||
log.debug("设置当前用户ID: {}", userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户ID
|
||||
*
|
||||
* @return 用户ID
|
||||
*/
|
||||
public static String getCurrentUserId() {
|
||||
return USER_ID_HOLDER.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置当前用户名
|
||||
*
|
||||
* @param username 用户名
|
||||
*/
|
||||
public static void setCurrentUsername(String username) {
|
||||
USERNAME_HOLDER.set(username);
|
||||
log.debug("设置当前用户名: {}", username);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户名
|
||||
*
|
||||
* @return 用户名
|
||||
*/
|
||||
public static String getCurrentUsername() {
|
||||
return USERNAME_HOLDER.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置当前用户类型
|
||||
*
|
||||
* @param userType 用户类型
|
||||
*/
|
||||
public static void setCurrentUserType(String userType) {
|
||||
USER_TYPE_HOLDER.set(userType);
|
||||
log.debug("设置当前用户类型: {}", userType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户类型
|
||||
*
|
||||
* @return 用户类型
|
||||
*/
|
||||
public static String getCurrentUserType() {
|
||||
return USER_TYPE_HOLDER.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置客户端IP
|
||||
*
|
||||
* @param clientIp 客户端IP
|
||||
*/
|
||||
public static void setClientIp(String clientIp) {
|
||||
CLIENT_IP_HOLDER.set(clientIp);
|
||||
log.debug("设置客户端IP: {}", clientIp);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取客户端IP
|
||||
*
|
||||
* @return 客户端IP
|
||||
*/
|
||||
public static String getClientIp() {
|
||||
return CLIENT_IP_HOLDER.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置请求ID
|
||||
*
|
||||
* @param requestId 请求ID
|
||||
*/
|
||||
public static void setRequestId(String requestId) {
|
||||
REQUEST_ID_HOLDER.set(requestId);
|
||||
log.debug("设置请求ID: {}", requestId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取请求ID
|
||||
*
|
||||
* @return 请求ID
|
||||
*/
|
||||
public static String getRequestId() {
|
||||
return REQUEST_ID_HOLDER.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置用户上下文信息
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param username 用户名
|
||||
* @param userType 用户类型
|
||||
* @param clientIp 客户端IP
|
||||
* @param requestId 请求ID
|
||||
*/
|
||||
public static void setUserContext(String userId, String username, String userType,
|
||||
String clientIp, String requestId) {
|
||||
setCurrentUserId(userId);
|
||||
setCurrentUsername(username);
|
||||
setCurrentUserType(userType);
|
||||
setClientIp(clientIp);
|
||||
setRequestId(requestId);
|
||||
|
||||
log.debug("设置用户上下文: userId={}, username={}, userType={}, clientIp={}, requestId={}",
|
||||
userId, username, userType, clientIp, requestId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除当前用户ID
|
||||
*/
|
||||
public static void clearUserId() {
|
||||
USER_ID_HOLDER.remove();
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除当前用户名
|
||||
*/
|
||||
public static void clearUsername() {
|
||||
USERNAME_HOLDER.remove();
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除当前用户类型
|
||||
*/
|
||||
public static void clearUserType() {
|
||||
USER_TYPE_HOLDER.remove();
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除客户端IP
|
||||
*/
|
||||
public static void clearClientIp() {
|
||||
CLIENT_IP_HOLDER.remove();
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除请求ID
|
||||
*/
|
||||
public static void clearRequestId() {
|
||||
REQUEST_ID_HOLDER.remove();
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除所有用户上下文信息
|
||||
*/
|
||||
public static void clear() {
|
||||
clearUserId();
|
||||
clearUsername();
|
||||
clearUserType();
|
||||
clearClientIp();
|
||||
clearRequestId();
|
||||
log.debug("清除所有用户上下文信息");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户上下文摘要信息
|
||||
*
|
||||
* @return 用户上下文摘要
|
||||
*/
|
||||
public static String getContextSummary() {
|
||||
return String.format("UserContext[userId=%s, username=%s, userType=%s, clientIp=%s, requestId=%s]",
|
||||
getCurrentUserId(), getCurrentUsername(), getCurrentUserType(),
|
||||
getClientIp(), getRequestId());
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否有用户上下文
|
||||
*
|
||||
* @return 是否有用户上下文
|
||||
*/
|
||||
public static boolean hasUserContext() {
|
||||
return getCurrentUserId() != null || getCurrentUsername() != null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
package com.emotion.util;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* 用户上下文工具类
|
||||
* 提供便捷的用户上下文操作方法
|
||||
*
|
||||
* @author emotion-museum
|
||||
* @date 2025-07-23
|
||||
*/
|
||||
@Slf4j
|
||||
public class UserContextUtils {
|
||||
|
||||
/**
|
||||
* 获取当前用户ID,如果为空则返回默认值
|
||||
*
|
||||
* @param defaultValue 默认值
|
||||
* @return 用户ID
|
||||
*/
|
||||
public static String getCurrentUserIdOrDefault(String defaultValue) {
|
||||
String userId = UserContextHolder.getCurrentUserId();
|
||||
return userId != null ? userId : defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户ID,如果为空则返回"system"
|
||||
*
|
||||
* @return 用户ID
|
||||
*/
|
||||
public static String getCurrentUserIdOrSystem() {
|
||||
return getCurrentUserIdOrDefault("system");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户名,如果为空则返回默认值
|
||||
*
|
||||
* @param defaultValue 默认值
|
||||
* @return 用户名
|
||||
*/
|
||||
public static String getCurrentUsernameOrDefault(String defaultValue) {
|
||||
String username = UserContextHolder.getCurrentUsername();
|
||||
return username != null ? username : defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户名,如果为空则返回"guest"
|
||||
*
|
||||
* @return 用户名
|
||||
*/
|
||||
public static String getCurrentUsernameOrGuest() {
|
||||
return getCurrentUsernameOrDefault("guest");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户类型,如果为空则返回默认值
|
||||
*
|
||||
* @param defaultValue 默认值
|
||||
* @return 用户类型
|
||||
*/
|
||||
public static String getCurrentUserTypeOrDefault(String defaultValue) {
|
||||
String userType = UserContextHolder.getCurrentUserType();
|
||||
return userType != null ? userType : defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户类型,如果为空则返回"GUEST"
|
||||
*
|
||||
* @return 用户类型
|
||||
*/
|
||||
public static String getCurrentUserTypeOrGuest() {
|
||||
return getCurrentUserTypeOrDefault("GUEST");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取客户端IP,如果为空则返回默认值
|
||||
*
|
||||
* @param defaultValue 默认值
|
||||
* @return 客户端IP
|
||||
*/
|
||||
public static String getClientIpOrDefault(String defaultValue) {
|
||||
String clientIp = UserContextHolder.getClientIp();
|
||||
return clientIp != null ? clientIp : defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取客户端IP,如果为空则返回"unknown"
|
||||
*
|
||||
* @return 客户端IP
|
||||
*/
|
||||
public static String getClientIpOrUnknown() {
|
||||
return getClientIpOrDefault("unknown");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取请求ID,如果为空则返回默认值
|
||||
*
|
||||
* @param defaultValue 默认值
|
||||
* @return 请求ID
|
||||
*/
|
||||
public static String getRequestIdOrDefault(String defaultValue) {
|
||||
String requestId = UserContextHolder.getRequestId();
|
||||
return requestId != null ? requestId : defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取请求ID,如果为空则返回"unknown"
|
||||
*
|
||||
* @return 请求ID
|
||||
*/
|
||||
public static String getRequestIdOrUnknown() {
|
||||
return getRequestIdOrDefault("unknown");
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查当前用户是否为访客
|
||||
*
|
||||
* @return 是否为访客
|
||||
*/
|
||||
public static boolean isGuest() {
|
||||
String userId = UserContextHolder.getCurrentUserId();
|
||||
String userType = UserContextHolder.getCurrentUserType();
|
||||
|
||||
return userId == null ||
|
||||
userId.startsWith("guest_") ||
|
||||
"GUEST".equalsIgnoreCase(userType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查当前用户是否为系统用户
|
||||
*
|
||||
* @return 是否为系统用户
|
||||
*/
|
||||
public static boolean isSystem() {
|
||||
String userId = UserContextHolder.getCurrentUserId();
|
||||
String userType = UserContextHolder.getCurrentUserType();
|
||||
|
||||
return "system".equals(userId) ||
|
||||
"SYSTEM".equalsIgnoreCase(userType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查当前用户是否为注册用户
|
||||
*
|
||||
* @return 是否为注册用户
|
||||
*/
|
||||
public static boolean isRegisteredUser() {
|
||||
return !isGuest() && !isSystem();
|
||||
}
|
||||
|
||||
/**
|
||||
* 安全地执行需要用户上下文的操作
|
||||
* 如果没有用户上下文,会设置默认的系统上下文
|
||||
*
|
||||
* @param operation 操作
|
||||
*/
|
||||
public static void executeWithContext(Runnable operation) {
|
||||
boolean hasContext = UserContextHolder.hasUserContext();
|
||||
|
||||
try {
|
||||
// 如果没有用户上下文,设置默认的系统上下文
|
||||
if (!hasContext) {
|
||||
UserContextHolder.setUserContext("system", "system", "SYSTEM", "127.0.0.1", "system");
|
||||
log.debug("设置默认系统用户上下文");
|
||||
}
|
||||
|
||||
// 执行操作
|
||||
operation.run();
|
||||
|
||||
} finally {
|
||||
// 如果是我们设置的默认上下文,执行后清理
|
||||
if (!hasContext) {
|
||||
UserContextHolder.clear();
|
||||
log.debug("清理默认系统用户上下文");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 临时设置用户上下文执行操作
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param username 用户名
|
||||
* @param userType 用户类型
|
||||
* @param operation 操作
|
||||
*/
|
||||
public static void executeWithTempContext(String userId, String username, String userType, Runnable operation) {
|
||||
// 保存当前上下文
|
||||
String originalUserId = UserContextHolder.getCurrentUserId();
|
||||
String originalUsername = UserContextHolder.getCurrentUsername();
|
||||
String originalUserType = UserContextHolder.getCurrentUserType();
|
||||
String originalClientIp = UserContextHolder.getClientIp();
|
||||
String originalRequestId = UserContextHolder.getRequestId();
|
||||
|
||||
try {
|
||||
// 设置临时上下文
|
||||
UserContextHolder.setUserContext(userId, username, userType,
|
||||
originalClientIp != null ? originalClientIp : "127.0.0.1",
|
||||
originalRequestId != null ? originalRequestId : "temp");
|
||||
|
||||
// 执行操作
|
||||
operation.run();
|
||||
|
||||
} finally {
|
||||
// 恢复原始上下文
|
||||
if (originalUserId != null || originalUsername != null) {
|
||||
UserContextHolder.setUserContext(originalUserId, originalUsername, originalUserType,
|
||||
originalClientIp, originalRequestId);
|
||||
} else {
|
||||
UserContextHolder.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user