{
-
- /**
- * 根据账号查询用户
- *
- * @param account 账号
- * @return 用户信息
- */
- User selectByAccount(@Param("account") String account);
-
- /**
- * 根据邮箱查询用户
- *
- * @param email 邮箱
- * @return 用户信息
- */
- User selectByEmail(@Param("email") String email);
-
- /**
- * 根据手机号查询用户
- *
- * @param phone 手机号
- * @return 用户信息
- */
- User selectByPhone(@Param("phone") String phone);
-
- /**
- * 根据第三方登录信息查询用户
- *
- * @param platform 平台
- * @param oauthId 第三方ID
- * @return 用户信息
- */
- User selectByOAuth(@Param("platform") String platform, @Param("oauthId") String oauthId);
-
- /**
- * 更新最后活跃时间
- *
- * @param userId 用户ID
- */
- void updateLastActiveTime(@Param("userId") String userId);
-}
diff --git a/backend/auth/server/src/main/java/com/emotionmuseum/auth/request/LoginRequest.java b/backend/auth/server/src/main/java/com/emotionmuseum/auth/request/LoginRequest.java
deleted file mode 100644
index 5ca47ab..0000000
--- a/backend/auth/server/src/main/java/com/emotionmuseum/auth/request/LoginRequest.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package com.emotionmuseum.auth.request;
-
-import com.emotionmuseum.common.request.BaseRequest;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-
-import jakarta.validation.constraints.NotBlank;
-
-/**
- * 用户登录请求
- *
- * @author huazhongmin
- * @since 2025-07-24
- */
-@Data
-@EqualsAndHashCode(callSuper = true)
-@Schema(description = "用户登录请求")
-public class LoginRequest extends BaseRequest {
-
- private static final long serialVersionUID = 1L;
-
- @Schema(description = "账号(支持账号/邮箱/手机号)", example = "test_user")
- @NotBlank(message = "账号不能为空")
- private String account;
-
- @Schema(description = "密码", example = "123456")
- @NotBlank(message = "密码不能为空")
- private String password;
-
- @Schema(description = "验证码ID", example = "captcha_123")
- @NotBlank(message = "验证码ID不能为空")
- private String captchaId;
-
- @Schema(description = "验证码", example = "1234")
- @NotBlank(message = "验证码不能为空")
- private String captcha;
-
- @Schema(description = "记住我", example = "false")
- private Boolean rememberMe = false;
-}
diff --git a/backend/auth/server/src/main/java/com/emotionmuseum/auth/request/OAuthLoginRequest.java b/backend/auth/server/src/main/java/com/emotionmuseum/auth/request/OAuthLoginRequest.java
deleted file mode 100644
index d6f188c..0000000
--- a/backend/auth/server/src/main/java/com/emotionmuseum/auth/request/OAuthLoginRequest.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package com.emotionmuseum.auth.request;
-
-import com.emotionmuseum.common.request.BaseRequest;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-
-import jakarta.validation.constraints.NotBlank;
-
-/**
- * 第三方登录请求
- *
- * @author huazhongmin
- * @since 2025-07-24
- */
-@Data
-@EqualsAndHashCode(callSuper = true)
-@Schema(description = "第三方登录请求")
-public class OAuthLoginRequest extends BaseRequest {
-
- private static final long serialVersionUID = 1L;
-
- @Schema(description = "第三方平台类型", example = "wechat")
- @NotBlank(message = "平台类型不能为空")
- private String platform;
-
- @Schema(description = "授权码", example = "auth_code_123")
- @NotBlank(message = "授权码不能为空")
- private String code;
-
- @Schema(description = "状态码", example = "state_123")
- private String state;
-
- @Schema(description = "验证码ID", example = "captcha_123")
- @NotBlank(message = "验证码ID不能为空")
- private String captchaId;
-
- @Schema(description = "验证码", example = "1234")
- @NotBlank(message = "验证码不能为空")
- private String captcha;
-}
diff --git a/backend/auth/server/src/main/java/com/emotionmuseum/auth/request/RegisterRequest.java b/backend/auth/server/src/main/java/com/emotionmuseum/auth/request/RegisterRequest.java
deleted file mode 100644
index 8df6f24..0000000
--- a/backend/auth/server/src/main/java/com/emotionmuseum/auth/request/RegisterRequest.java
+++ /dev/null
@@ -1,83 +0,0 @@
-package com.emotionmuseum.auth.request;
-
-import com.emotionmuseum.common.request.BaseRequest;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-
-import jakarta.validation.constraints.*;
-import java.time.LocalDate;
-
-/**
- * 用户注册请求
- *
- * @author huazhongmin
- * @since 2025-07-24
- */
-@Data
-@EqualsAndHashCode(callSuper = true)
-@Schema(description = "用户注册请求")
-public class RegisterRequest extends BaseRequest {
-
- private static final long serialVersionUID = 1L;
-
- @Schema(description = "账号", example = "test_user")
- @NotBlank(message = "账号不能为空")
- @Size(min = 4, max = 20, message = "账号长度必须在4-20位之间")
- @Pattern(regexp = "^[a-zA-Z0-9_]+$", message = "账号只能包含字母、数字和下划线")
- private String account;
-
- @Schema(description = "密码", example = "123456")
- @NotBlank(message = "密码不能为空")
- @Size(min = 6, max = 20, message = "密码长度必须在6-20位之间")
- private String password;
-
- @Schema(description = "确认密码", example = "123456")
- @NotBlank(message = "确认密码不能为空")
- private String confirmPassword;
-
- @Schema(description = "验证码ID", example = "captcha_123")
- @NotBlank(message = "验证码ID不能为空")
- private String captchaId;
-
- @Schema(description = "验证码", example = "1234")
- @NotBlank(message = "验证码不能为空")
- private String captcha;
-
- @Schema(description = "用户名", example = "测试用户")
- @NotBlank(message = "用户名不能为空")
- @Size(min = 2, max = 20, message = "用户名长度必须在2-20位之间")
- private String username;
-
- @Schema(description = "邮箱", example = "test@example.com")
- @NotBlank(message = "邮箱不能为空")
- @Email(message = "邮箱格式不正确")
- private String email;
-
- @Schema(description = "手机号", example = "13800138000")
- @Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确")
- private String phone;
-
- @Schema(description = "昵称", example = "小测试")
- @NotBlank(message = "昵称不能为空")
- @Size(min = 1, max = 20, message = "昵称长度必须在1-20位之间")
- private String nickname;
-
- @Schema(description = "生日", example = "1990-01-01")
- private LocalDate birthDate;
-
- @Schema(description = "所在地", example = "北京市")
- @Size(max = 50, message = "所在地长度不能超过50位")
- private String location;
-
- @Schema(description = "个人简介", example = "这是一个测试用户")
- @Size(max = 200, message = "个人简介长度不能超过200位")
- private String bio;
-
- /**
- * 验证密码一致性
- */
- public boolean isPasswordMatch() {
- return password != null && password.equals(confirmPassword);
- }
-}
diff --git a/backend/auth/server/src/main/java/com/emotionmuseum/auth/request/ResetPasswordRequest.java b/backend/auth/server/src/main/java/com/emotionmuseum/auth/request/ResetPasswordRequest.java
deleted file mode 100644
index 3caf4de..0000000
--- a/backend/auth/server/src/main/java/com/emotionmuseum/auth/request/ResetPasswordRequest.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package com.emotionmuseum.auth.request;
-
-import com.emotionmuseum.common.request.BaseRequest;
-import io.swagger.v3.oas.annotations.media.Schema;
-import jakarta.validation.constraints.NotBlank;
-import jakarta.validation.constraints.Pattern;
-import jakarta.validation.constraints.Size;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-
-/**
- * 重置密码请求
- *
- * 用于未登录情况下通过手机号与验证码(本期固定为 123456)设置新密码。
- *
- * @author huazhongmin
- * @since 2025-10-26
- */
-@Data
-@EqualsAndHashCode(callSuper = true)
-@Schema(description = "重置密码请求")
-public class ResetPasswordRequest extends BaseRequest {
-
- private static final long serialVersionUID = 1L;
-
- /**
- * 手机号
- */
- @Schema(description = "手机号", example = "13800138000")
- @NotBlank(message = "手机号不能为空")
- @Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确")
- private String phone;
-
- /**
- * 新密码
- */
- @Schema(description = "新密码", example = "NewPass_123")
- @NotBlank(message = "新密码不能为空")
- @Size(min = 6, max = 20, message = "密码长度必须在6-20位之间")
- private String newPassword;
-
- /**
- * 验证码(本期为固定值 123456)
- */
- @Schema(description = "验证码(固定为123456)", example = "123456")
- @NotBlank(message = "验证码不能为空")
- private String captcha;
-}
-
diff --git a/backend/auth/server/src/main/java/com/emotionmuseum/auth/request/SliderCaptchaVerifyRequest.java b/backend/auth/server/src/main/java/com/emotionmuseum/auth/request/SliderCaptchaVerifyRequest.java
deleted file mode 100644
index 158e41c..0000000
--- a/backend/auth/server/src/main/java/com/emotionmuseum/auth/request/SliderCaptchaVerifyRequest.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package com.emotionmuseum.auth.request;
-
-import com.emotionmuseum.common.request.BaseRequest;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-
-import jakarta.validation.constraints.NotBlank;
-import jakarta.validation.constraints.NotNull;
-
-/**
- * 滑块验证码验证请求
- *
- * @author huazhongmin
- * @since 2025-07-24
- */
-@Data
-@EqualsAndHashCode(callSuper = true)
-@Schema(description = "滑块验证码验证请求")
-public class SliderCaptchaVerifyRequest extends BaseRequest {
-
- private static final long serialVersionUID = 1L;
-
- @Schema(description = "验证码ID")
- @NotBlank(message = "验证码ID不能为空")
- private String captchaId;
-
- @Schema(description = "滑块X坐标")
- @NotNull(message = "滑块X坐标不能为空")
- private Integer x;
-
- @Schema(description = "滑块Y坐标")
- @NotNull(message = "滑块Y坐标不能为空")
- private Integer y;
-
- @Schema(description = "滑动轨迹")
- private String track;
-}
diff --git a/backend/auth/server/src/main/java/com/emotionmuseum/auth/response/CaptchaResponse.java b/backend/auth/server/src/main/java/com/emotionmuseum/auth/response/CaptchaResponse.java
deleted file mode 100644
index 0f0c984..0000000
--- a/backend/auth/server/src/main/java/com/emotionmuseum/auth/response/CaptchaResponse.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.emotionmuseum.auth.response;
-
-import com.emotionmuseum.common.response.BaseResponse;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.AllArgsConstructor;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import lombok.NoArgsConstructor;
-
-/**
- * 验证码响应
- *
- * @author huazhongmin
- * @since 2025-07-24
- */
-@Data
-@NoArgsConstructor
-@AllArgsConstructor
-@EqualsAndHashCode(callSuper = true)
-@Schema(description = "验证码响应")
-public class CaptchaResponse extends BaseResponse {
-
- private static final long serialVersionUID = 1L;
-
- @Schema(description = "验证码ID")
- private String captchaId;
-
- @Schema(description = "验证码图片Base64")
- private String captchaImage;
-
- @Schema(description = "验证码类型", example = "arithmetic")
- private String captchaType;
-
- @Schema(description = "过期时间(秒)", example = "300")
- private Long expireTime;
-}
diff --git a/backend/auth/server/src/main/java/com/emotionmuseum/auth/response/LoginResponse.java b/backend/auth/server/src/main/java/com/emotionmuseum/auth/response/LoginResponse.java
deleted file mode 100644
index 4cdd0b0..0000000
--- a/backend/auth/server/src/main/java/com/emotionmuseum/auth/response/LoginResponse.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package com.emotionmuseum.auth.response;
-
-import com.emotionmuseum.common.response.BaseResponse;
-import com.fasterxml.jackson.annotation.JsonFormat;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-
-import java.time.LocalDateTime;
-
-/**
- * 登录响应
- *
- * @author huazhongmin
- * @since 2025-07-24
- */
-@Data
-@EqualsAndHashCode(callSuper = true)
-@Schema(description = "登录响应")
-public class LoginResponse extends BaseResponse {
-
- private static final long serialVersionUID = 1L;
-
- @Schema(description = "访问Token")
- private String accessToken;
-
- @Schema(description = "刷新Token")
- private String refreshToken;
-
- @Schema(description = "Token类型", example = "Bearer")
- private String tokenType = "Bearer";
-
- @Schema(description = "Token过期时间(秒)", example = "86400")
- private Long expiresIn;
-
- @Schema(description = "用户信息")
- private UserInfoResponse userInfo;
-
- @Schema(description = "登录时间")
- @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
- private LocalDateTime loginTime;
-}
diff --git a/backend/auth/server/src/main/java/com/emotionmuseum/auth/response/ResetPasswordResponse.java b/backend/auth/server/src/main/java/com/emotionmuseum/auth/response/ResetPasswordResponse.java
deleted file mode 100644
index 5e64ae5..0000000
--- a/backend/auth/server/src/main/java/com/emotionmuseum/auth/response/ResetPasswordResponse.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package com.emotionmuseum.auth.response;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-
-/**
- * 重置密码响应
- *
- * 不返回敏感信息,仅提供结果标识与提示。
- *
- * @author huazhongmin
- * @since 2025-10-26
- */
-@Data
-@Schema(description = "重置密码响应")
-public class ResetPasswordResponse {
-
- /** 是否重置成功 */
- @Schema(description = "是否重置成功", example = "true")
- private boolean success;
-
- /** 提示信息 */
- @Schema(description = "提示信息", example = "重置密码成功")
- private String message;
-}
-
diff --git a/backend/auth/server/src/main/java/com/emotionmuseum/auth/response/SliderCaptchaResponse.java b/backend/auth/server/src/main/java/com/emotionmuseum/auth/response/SliderCaptchaResponse.java
deleted file mode 100644
index 2ab4b6c..0000000
--- a/backend/auth/server/src/main/java/com/emotionmuseum/auth/response/SliderCaptchaResponse.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package com.emotionmuseum.auth.response;
-
-import com.emotionmuseum.common.response.BaseResponse;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.AllArgsConstructor;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import lombok.NoArgsConstructor;
-
-/**
- * 滑块验证码响应
- *
- * @author huazhongmin
- * @since 2025-07-24
- */
-@Data
-@NoArgsConstructor
-@AllArgsConstructor
-@EqualsAndHashCode(callSuper = true)
-@Schema(description = "滑块验证码响应")
-public class SliderCaptchaResponse extends BaseResponse {
-
- private static final long serialVersionUID = 1L;
-
- @Schema(description = "验证码ID")
- private String captchaId;
-
- @Schema(description = "背景图片Base64")
- private String backgroundImage;
-
- @Schema(description = "滑块图片Base64")
- private String sliderImage;
-
- @Schema(description = "滑块X坐标")
- private Integer sliderX;
-
- @Schema(description = "滑块Y坐标")
- private Integer sliderY;
-
- @Schema(description = "过期时间(秒)")
- private Long expireTime;
-}
diff --git a/backend/auth/server/src/main/java/com/emotionmuseum/auth/response/UserInfoResponse.java b/backend/auth/server/src/main/java/com/emotionmuseum/auth/response/UserInfoResponse.java
deleted file mode 100644
index 8aa63f3..0000000
--- a/backend/auth/server/src/main/java/com/emotionmuseum/auth/response/UserInfoResponse.java
+++ /dev/null
@@ -1,102 +0,0 @@
-package com.emotionmuseum.auth.response;
-
-import com.emotionmuseum.common.response.BaseResponse;
-import com.fasterxml.jackson.annotation.JsonFormat;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-
-import java.math.BigDecimal;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-
-/**
- * 用户信息响应
- *
- * @author huazhongmin
- * @since 2025-07-24
- */
-@Data
-@EqualsAndHashCode(callSuper = true)
-@Schema(description = "用户信息响应")
-public class UserInfoResponse extends BaseResponse {
-
- private static final long serialVersionUID = 1L;
-
- @Schema(description = "用户ID")
- private String id;
-
- @Schema(description = "账号")
- private String account;
-
- @Schema(description = "用户名")
- private String username;
-
- @Schema(description = "邮箱")
- private String email;
-
- @Schema(description = "手机号")
- private String phone;
-
- @Schema(description = "头像URL")
- private String avatar;
-
- @Schema(description = "昵称")
- private String nickname;
-
- @Schema(description = "生日")
- @JsonFormat(pattern = "yyyy-MM-dd")
- private LocalDate birthDate;
-
- @Schema(description = "所在地")
- private String location;
-
- @Schema(description = "个人简介")
- private String bio;
-
- @Schema(description = "会员等级")
- private String memberLevel;
-
- @Schema(description = "使用天数")
- private Integer totalDays;
-
- @Schema(description = "成长数据")
- private GrowthStatsVO growthStats;
-
- @Schema(description = "状态")
- private Integer status;
-
- @Schema(description = "是否已验证")
- private Integer isVerified;
-
- @Schema(description = "创建时间")
- @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
- private LocalDateTime createTime;
-
- @Schema(description = "最后活跃时间")
- @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
- private LocalDateTime lastActiveTime;
-
- /**
- * 成长数据VO
- */
- @Data
- @Schema(description = "成长数据")
- public static class GrowthStatsVO {
-
- @Schema(description = "自我感知")
- private BigDecimal selfAwareness;
-
- @Schema(description = "情绪韧性")
- private BigDecimal emotionalResilience;
-
- @Schema(description = "行动力")
- private BigDecimal actionPower;
-
- @Schema(description = "共情力")
- private BigDecimal empathy;
-
- @Schema(description = "生活热度")
- private BigDecimal lifeEnthusiasm;
- }
-}
diff --git a/backend/auth/server/src/main/java/com/emotionmuseum/auth/security/JwtAuthenticationFilter.java b/backend/auth/server/src/main/java/com/emotionmuseum/auth/security/JwtAuthenticationFilter.java
deleted file mode 100644
index 3cb8793..0000000
--- a/backend/auth/server/src/main/java/com/emotionmuseum/auth/security/JwtAuthenticationFilter.java
+++ /dev/null
@@ -1,120 +0,0 @@
-package com.emotionmuseum.auth.security;
-
-import cn.hutool.core.util.StrUtil;
-import com.emotionmuseum.common.util.JwtUtil;
-import jakarta.servlet.FilterChain;
-import jakarta.servlet.ServletException;
-import jakarta.servlet.http.HttpServletRequest;
-import jakarta.servlet.http.HttpServletResponse;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.data.redis.core.RedisTemplate;
-import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
-import org.springframework.security.core.context.SecurityContextHolder;
-import org.springframework.security.core.userdetails.UserDetails;
-import org.springframework.security.core.userdetails.UserDetailsService;
-import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
-import org.springframework.stereotype.Component;
-import org.springframework.web.filter.OncePerRequestFilter;
-
-import java.io.IOException;
-import java.util.concurrent.TimeUnit;
-
-/**
- * JWT认证过滤器
- *
- * @author huazhongmin
- * @since 2025-07-15
- */
-@Slf4j
-@Component
-@RequiredArgsConstructor
-public class JwtAuthenticationFilter extends OncePerRequestFilter {
-
- private final JwtUtil jwtUtil;
- private final UserDetailsService userDetailsService;
- private final RedisTemplate redisTemplate;
-
- private static final String TOKEN_PREFIX = "Bearer ";
- private static final String HEADER_NAME = "Authorization";
- private static final String REDIS_TOKEN_KEY_PREFIX = "auth:token:";
-
- @Override
- protected void doFilterInternal(HttpServletRequest request,
- HttpServletResponse response,
- FilterChain filterChain) throws ServletException, IOException {
-
- try {
- String token = extractTokenFromRequest(request);
-
- if (StrUtil.isNotBlank(token) && SecurityContextHolder.getContext().getAuthentication() == null) {
- // 验证token有效性
- if (jwtUtil.validateToken(token)) {
- String userId = jwtUtil.getUserIdFromToken(token);
-
- // 检查Redis中是否存在该token(用于登出功能)
- String redisKey = REDIS_TOKEN_KEY_PREFIX + userId;
- String redisToken = (String) redisTemplate.opsForValue().get(redisKey);
-
- if (StrUtil.isNotBlank(redisToken) && redisToken.equals(token)) {
- // 加载用户详情
- UserDetails userDetails = userDetailsService.loadUserByUsername(userId);
-
- // 创建认证对象
- UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
- userDetails, null, userDetails.getAuthorities());
- authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
-
- // 设置到安全上下文
- SecurityContextHolder.getContext().setAuthentication(authentication);
-
- // 更新token在Redis中的过期时间
- redisTemplate.expire(redisKey, 24, TimeUnit.HOURS);
-
- log.debug("JWT认证成功,用户ID: {}", userId);
- } else {
- log.debug("Redis中未找到有效token,用户ID: {}", userId);
- }
- } else {
- log.debug("JWT token无效");
- }
- }
- } catch (Exception e) {
- log.error("JWT认证过程中发生错误: {}", e.getMessage());
- }
-
- filterChain.doFilter(request, response);
- }
-
- /**
- * 从请求中提取token
- */
- private String extractTokenFromRequest(HttpServletRequest request) {
- String bearerToken = request.getHeader(HEADER_NAME);
- if (StrUtil.isNotBlank(bearerToken) && bearerToken.startsWith(TOKEN_PREFIX)) {
- return bearerToken.substring(TOKEN_PREFIX.length());
- }
- return null;
- }
-
- /**
- * 判断是否跳过JWT认证
- */
- @Override
- protected boolean shouldNotFilter(HttpServletRequest request) {
- String path = request.getRequestURI();
-
- // 跳过认证的路径
- return path.startsWith("/user/register") ||
- path.startsWith("/user/login") ||
- path.startsWith("/user/refresh") ||
- path.startsWith("/user/check/") ||
- path.startsWith("/captcha/") ||
- path.startsWith("/oauth/") ||
- path.startsWith("/actuator/") ||
- path.startsWith("/swagger-ui/") ||
- path.startsWith("/v3/api-docs") ||
- path.startsWith("/doc.html") ||
- path.equals("/error");
- }
-}
diff --git a/backend/auth/server/src/main/java/com/emotionmuseum/auth/security/UserDetailsServiceImpl.java b/backend/auth/server/src/main/java/com/emotionmuseum/auth/security/UserDetailsServiceImpl.java
deleted file mode 100644
index ca9cca9..0000000
--- a/backend/auth/server/src/main/java/com/emotionmuseum/auth/security/UserDetailsServiceImpl.java
+++ /dev/null
@@ -1,117 +0,0 @@
-package com.emotionmuseum.auth.security;
-
-import com.emotionmuseum.auth.entity.User;
-import com.emotionmuseum.auth.mapper.UserMapper;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.security.core.GrantedAuthority;
-import org.springframework.security.core.authority.SimpleGrantedAuthority;
-import org.springframework.security.core.userdetails.UserDetails;
-import org.springframework.security.core.userdetails.UserDetailsService;
-import org.springframework.security.core.userdetails.UsernameNotFoundException;
-import org.springframework.stereotype.Service;
-
-import java.util.Collection;
-import java.util.Collections;
-
-/**
- * Spring Security用户详情服务实现
- *
- * @author huazhongmin
- * @since 2025-07-15
- */
-@Slf4j
-@Service
-@RequiredArgsConstructor
-public class UserDetailsServiceImpl implements UserDetailsService {
-
- private final UserMapper userMapper;
-
- @Override
- public UserDetails loadUserByUsername(String userId) throws UsernameNotFoundException {
- log.debug("加载用户详情,用户ID: {}", userId);
-
- User user = userMapper.selectById(userId);
- if (user == null) {
- log.warn("用户不存在,用户ID: {}", userId);
- throw new UsernameNotFoundException("用户不存在: " + userId);
- }
-
- if (user.getStatus() == 0) {
- log.warn("用户已被禁用,用户ID: {}", userId);
- throw new UsernameNotFoundException("用户已被禁用: " + userId);
- }
-
- return new SecurityUser(user);
- }
-
- /**
- * Spring Security用户详情实现类
- */
- public static class SecurityUser implements UserDetails {
-
- private final User user;
-
- public SecurityUser(User user) {
- this.user = user;
- }
-
- @Override
- public Collection extends GrantedAuthority> getAuthorities() {
- // 这里可以根据用户角色返回权限
- // 目前简单返回一个默认角色
- return Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER"));
- }
-
- @Override
- public String getPassword() {
- return user.getPassword();
- }
-
- @Override
- public String getUsername() {
- return user.getId();
- }
-
- /**
- * 获取用户账号
- */
- public String getAccount() {
- return user.getAccount();
- }
-
- /**
- * 获取用户昵称
- */
- public String getNickname() {
- return user.getNickname();
- }
-
- /**
- * 获取用户实体
- */
- public User getUser() {
- return user;
- }
-
- @Override
- public boolean isAccountNonExpired() {
- return true;
- }
-
- @Override
- public boolean isAccountNonLocked() {
- return user.getStatus() == 1;
- }
-
- @Override
- public boolean isCredentialsNonExpired() {
- return true;
- }
-
- @Override
- public boolean isEnabled() {
- return user.getStatus() == 1;
- }
- }
-}
diff --git a/backend/auth/server/src/main/java/com/emotionmuseum/auth/service/AuthService.java b/backend/auth/server/src/main/java/com/emotionmuseum/auth/service/AuthService.java
deleted file mode 100644
index b440504..0000000
--- a/backend/auth/server/src/main/java/com/emotionmuseum/auth/service/AuthService.java
+++ /dev/null
@@ -1,110 +0,0 @@
-package com.emotionmuseum.auth.service;
-
-import com.emotionmuseum.auth.request.LoginRequest;
-import com.emotionmuseum.auth.request.RegisterRequest;
-import com.emotionmuseum.auth.request.ResetPasswordRequest;
-import com.emotionmuseum.auth.response.LoginResponse;
-import com.emotionmuseum.auth.response.ResetPasswordResponse;
-import com.emotionmuseum.auth.response.UserInfoResponse;
-
-/**
- * 认证服务接口
- *
- *
- * 注意:所有新增接口需遵循项目接口规范与异常处理规范。
- *
- *
- * @author huazhongmin
- * @since 2025-07-16
- */
-public interface AuthService {
-
- /**
- * 用户注册
- *
- * @param request 注册请求
- * @return 用户信息响应
- */
- UserInfoResponse register(RegisterRequest request);
-
- /**
- * 用户登录
- *
- * @param request 登录请求
- * @return 登录响应
- */
- LoginResponse login(LoginRequest request);
-
- /**
- * 刷新Token
- *
- * @param refreshToken 刷新Token
- * @return 登录响应
- */
- LoginResponse refreshToken(String refreshToken);
-
- /**
- * 用户登出
- *
- * @param userId 用户ID
- */
- void logout(String userId);
-
- /**
- * 获取当前用户信息
- *
- * @return 用户信息响应
- */
- UserInfoResponse getCurrentUserInfo();
-
- /**
- * 检查账号是否存在
- *
- * @param account 账号
- * @return 是否存在
- */
- boolean existsByAccount(String account);
-
- /**
- * 检查邮箱是否存在
- *
- * @param email 邮箱
- * @return 是否存在
- */
- boolean existsByEmail(String email);
-
- /**
- * 检查手机号是否存在
- *
- * @param phone 手机号
- * @return 是否存在
- */
- boolean existsByPhone(String phone);
-
- /**
- * 根据用户ID获取用户信息
- *
- * @param userId 用户ID
- * @return 用户信息响应
- */
- UserInfoResponse getUserInfo(String userId);
-
- /**
- * 更新最后活跃时间
- *
- * @param userId 用户ID
- */
- void updateLastActiveTime(String userId);
-
- /**
- * 重置密码(未登录场景)
- *
- *
- * 通过手机号与验证码(当前固定为123456)设置新密码。
- *
- *
- * @param request 重置密码请求
- * @return 重置密码响应
- */
- ResetPasswordResponse resetPassword(ResetPasswordRequest request);
-}
diff --git a/backend/auth/server/src/main/java/com/emotionmuseum/auth/service/CaptchaService.java b/backend/auth/server/src/main/java/com/emotionmuseum/auth/service/CaptchaService.java
deleted file mode 100644
index 993547e..0000000
--- a/backend/auth/server/src/main/java/com/emotionmuseum/auth/service/CaptchaService.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.emotionmuseum.auth.service;
-
-import com.emotionmuseum.auth.response.CaptchaResponse;
-
-/**
- * 验证码服务接口
- *
- * @author huazhongmin
- * @since 2025-07-15
- */
-public interface CaptchaService {
-
- /**
- * 生成验证码
- *
- * @param type 验证码类型 (arithmetic, chinese, gif, spec)
- * @return 验证码响应
- */
- CaptchaResponse generateCaptcha(String type);
-
- /**
- * 验证验证码
- *
- * @param captchaId 验证码ID
- * @param captcha 用户输入的验证码
- * @return 是否验证成功
- */
- boolean verifyCaptcha(String captchaId, String captcha);
-
- /**
- * 删除验证码
- *
- * @param captchaId 验证码ID
- */
- void removeCaptcha(String captchaId);
-}
diff --git a/backend/auth/server/src/main/java/com/emotionmuseum/auth/service/OAuthService.java b/backend/auth/server/src/main/java/com/emotionmuseum/auth/service/OAuthService.java
deleted file mode 100644
index 332e6a1..0000000
--- a/backend/auth/server/src/main/java/com/emotionmuseum/auth/service/OAuthService.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package com.emotionmuseum.auth.service;
-
-import com.emotionmuseum.auth.dto.OAuthLoginRequest;
-import com.emotionmuseum.auth.vo.LoginResponse;
-
-/**
- * 第三方登录服务接口
- *
- * @author huazhongmin
- * @since 2025-07-15
- */
-public interface OAuthService {
-
- /**
- * 获取第三方登录授权URL
- *
- * @param platform 平台类型 (wechat, qq, wechat-mp)
- * @return 授权URL
- */
- String getAuthUrl(String platform);
-
- /**
- * 第三方登录
- *
- * @param request 第三方登录请求
- * @return 登录响应
- */
- LoginResponse oauthLogin(OAuthLoginRequest request);
-
- /**
- * 获取第三方用户信息
- *
- * @param platform 平台类型
- * @param code 授权码
- * @param state 状态码
- * @return 用户信息
- */
- Object getOAuthUserInfo(String platform, String code, String state);
-}
diff --git a/backend/auth/server/src/main/java/com/emotionmuseum/auth/service/SliderCaptchaService.java b/backend/auth/server/src/main/java/com/emotionmuseum/auth/service/SliderCaptchaService.java
deleted file mode 100644
index 02c1c54..0000000
--- a/backend/auth/server/src/main/java/com/emotionmuseum/auth/service/SliderCaptchaService.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package com.emotionmuseum.auth.service;
-
-import com.emotionmuseum.auth.response.SliderCaptchaResponse;
-import com.emotionmuseum.auth.request.SliderCaptchaVerifyRequest;
-
-/**
- * 滑块验证码服务接口
- *
- * @author huazhongmin
- * @since 2025-07-15
- */
-public interface SliderCaptchaService {
-
- /**
- * 生成滑块验证码
- *
- * @return 滑块验证码响应
- */
- SliderCaptchaResponse generateSliderCaptcha();
-
- /**
- * 验证滑块验证码
- *
- * @param request 验证请求
- * @return 是否验证成功
- */
- boolean verifySliderCaptcha(SliderCaptchaVerifyRequest request);
-
- /**
- * 删除滑块验证码
- *
- * @param captchaId 验证码ID
- */
- void removeSliderCaptcha(String captchaId);
-}
diff --git a/backend/auth/server/src/main/java/com/emotionmuseum/auth/service/impl/AuthServiceImpl.java b/backend/auth/server/src/main/java/com/emotionmuseum/auth/service/impl/AuthServiceImpl.java
deleted file mode 100644
index d0a2dca..0000000
--- a/backend/auth/server/src/main/java/com/emotionmuseum/auth/service/impl/AuthServiceImpl.java
+++ /dev/null
@@ -1,347 +0,0 @@
-package com.emotionmuseum.auth.service.impl;
-
-import cn.hutool.core.util.StrUtil;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.emotionmuseum.common.result.ResultCode;
-import com.emotionmuseum.common.util.JwtUtil;
-import com.emotionmuseum.auth.request.LoginRequest;
-import com.emotionmuseum.auth.request.RegisterRequest;
-import com.emotionmuseum.auth.request.ResetPasswordRequest;
-import com.emotionmuseum.auth.entity.User;
-import com.emotionmuseum.auth.mapper.UserMapper;
-import com.emotionmuseum.auth.service.AuthService;
-import com.emotionmuseum.auth.service.CaptchaService;
-import com.emotionmuseum.auth.response.LoginResponse;
-import com.emotionmuseum.auth.response.ResetPasswordResponse;
-import com.emotionmuseum.auth.response.UserInfoResponse;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.BeanUtils;
-import org.springframework.context.ApplicationContext;
-import org.springframework.data.redis.core.RedisTemplate;
-import org.springframework.security.core.context.SecurityContextHolder;
-import org.springframework.security.crypto.password.PasswordEncoder;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-
-import java.math.BigDecimal;
-import java.time.LocalDateTime;
-import java.util.concurrent.TimeUnit;
-
-/**
- * 认证服务实现
- *
- * @author huazhongmin
- * @since 2025-07-16
- */
-@Slf4j
-@Service
-@RequiredArgsConstructor
-public class AuthServiceImpl extends ServiceImpl implements AuthService {
-
- private final ApplicationContext applicationContext;
- private final CaptchaService captchaService;
- private final JwtUtil jwtUtil;
- private final RedisTemplate redisTemplate;
-
- private static final String REDIS_TOKEN_KEY_PREFIX = "auth:token:";
-
- @Override
- @Transactional(rollbackFor = Exception.class)
- public UserInfoResponse register(RegisterRequest request) {
- // 验证验证码
- if (!captchaService.verifyCaptcha(request.getCaptchaId(), request.getCaptcha())) {
- throw new RuntimeException(ResultCode.CAPTCHA_ERROR.getMessage());
- }
-
- // 验证密码一致性
- if (!request.isPasswordMatch()) {
- throw new RuntimeException(ResultCode.PARAM_VALIDATION_ERROR.getMessage() + ": 两次密码不一致");
- }
-
- // 检查账号是否存在
- if (existsByAccount(request.getAccount())) {
- throw new RuntimeException(ResultCode.ACCOUNT_ALREADY_EXISTS.getMessage());
- }
-
- // 检查邮箱是否存在
- if (StrUtil.isNotBlank(request.getEmail()) && existsByEmail(request.getEmail())) {
- throw new RuntimeException(ResultCode.EMAIL_ALREADY_EXISTS.getMessage());
- }
-
- // 检查手机号是否存在
- if (StrUtil.isNotBlank(request.getPhone()) && existsByPhone(request.getPhone())) {
- throw new RuntimeException("手机号已存在");
- }
-
- // 创建用户
- User user = new User();
- BeanUtils.copyProperties(request, user);
-
- // 加密密码
- PasswordEncoder passwordEncoder = applicationContext.getBean(PasswordEncoder.class);
- user.setPassword(passwordEncoder.encode(request.getPassword()));
-
- // 设置默认值
- user.setMemberLevel("free");
- user.setTotalDays(0);
- user.setSelfAwareness(new BigDecimal("50.00"));
- user.setEmotionalResilience(new BigDecimal("50.00"));
- user.setActionPower(new BigDecimal("50.00"));
- user.setEmpathy(new BigDecimal("50.00"));
- user.setLifeEnthusiasm(new BigDecimal("50.00"));
- user.setStatus(1);
- user.setIsVerified(0);
- user.setLastActiveTime(LocalDateTime.now());
-
- // 保存用户
- save(user);
-
- log.info("用户注册成功: {}", user.getAccount());
- return convertToUserInfoResponse(user);
- }
-
- @Override
- public LoginResponse login(LoginRequest request) {
- // 验证验证码
- if (!captchaService.verifyCaptcha(request.getCaptchaId(), request.getCaptcha())) {
- throw new RuntimeException(ResultCode.CAPTCHA_ERROR.getMessage());
- }
-
- // 查找用户(支持账号/邮箱/手机号登录)
- User user = findUserByAccount(request.getAccount());
- if (user == null) {
- throw new RuntimeException(ResultCode.USER_NOT_FOUND.getMessage());
- }
-
- // 验证密码
- PasswordEncoder passwordEncoder = applicationContext.getBean(PasswordEncoder.class);
- if (!passwordEncoder.matches(request.getPassword(), user.getPassword())) {
- throw new RuntimeException(ResultCode.INVALID_CREDENTIALS.getMessage());
- }
-
- // 检查用户状态
- if (user.getStatus() == 0) {
- throw new RuntimeException(ResultCode.USER_DISABLED.getMessage());
- }
-
- // 生成Token
- String accessToken = jwtUtil.generateToken(user.getId(), user.getUsername());
- String refreshToken = jwtUtil.generateRefreshToken(user.getId(), user.getUsername());
-
- // 将token存储到Redis中(用于登出和token管理)
- String redisKey = REDIS_TOKEN_KEY_PREFIX + user.getId();
- redisTemplate.opsForValue().set(redisKey, accessToken, 24, TimeUnit.HOURS);
-
- // 更新最后活跃时间
- updateLastActiveTime(user.getId());
-
- // 构建响应
- LoginResponse response = new LoginResponse();
- response.setAccessToken(accessToken);
- response.setRefreshToken(refreshToken);
- response.setExpiresIn(86400L); // 24小时
- response.setUserInfo(convertToUserInfoResponse(user));
- response.setLoginTime(LocalDateTime.now());
-
- log.info("用户登录成功: {}", user.getAccount());
- return response;
- }
-
- @Override
- public LoginResponse refreshToken(String refreshToken) {
- try {
- // 验证刷新Token
- if (!jwtUtil.validateToken(refreshToken)) {
- throw new RuntimeException("刷新Token无效");
- }
-
- // 从刷新Token中获取用户信息
- String userId = jwtUtil.getUserIdFromToken(refreshToken);
- User user = getById(userId);
- if (user == null) {
- throw new RuntimeException("用户不存在");
- }
-
- // 生成新的Token
- String newAccessToken = jwtUtil.generateToken(user.getId(), user.getUsername());
- String newRefreshToken = jwtUtil.generateRefreshToken(user.getId(), user.getUsername());
-
- // 更新Redis中的token
- String redisKey = REDIS_TOKEN_KEY_PREFIX + user.getId();
- redisTemplate.opsForValue().set(redisKey, newAccessToken, 24, TimeUnit.HOURS);
-
- // 构建响应
- LoginResponse response = new LoginResponse();
- response.setAccessToken(newAccessToken);
- response.setRefreshToken(newRefreshToken);
- response.setExpiresIn(86400L);
- response.setUserInfo(convertToUserInfoResponse(user));
- response.setLoginTime(LocalDateTime.now());
-
- log.info("Token刷新成功: {}", user.getAccount());
- return response;
- } catch (Exception e) {
- log.error("Token刷新失败: {}", e.getMessage());
- throw new RuntimeException("Token刷新失败");
- }
- }
-
- @Override
- public void logout(String userId) {
- try {
- // 从Redis中删除token
- String redisKey = REDIS_TOKEN_KEY_PREFIX + userId;
- redisTemplate.delete(redisKey);
-
- log.info("用户登出成功: {}", userId);
- } catch (Exception e) {
- log.error("用户登出失败: {}", e.getMessage());
- throw new RuntimeException("登出失败");
- }
- }
-
- @Override
- public UserInfoResponse getCurrentUserInfo() {
- // 从安全上下文获取当前用户ID
- String userId = getCurrentUserId();
- if (StrUtil.isBlank(userId)) {
- throw new RuntimeException("未登录");
- }
-
- User user = getById(userId);
- if (user == null) {
- throw new RuntimeException("用户不存在");
- }
-
- return convertToUserInfoResponse(user);
- }
-
- @Override
- public boolean existsByAccount(String account) {
- return baseMapper.selectByAccount(account) != null;
- }
-
- @Override
- public boolean existsByEmail(String email) {
- return baseMapper.selectByEmail(email) != null;
- }
-
- @Override
- public boolean existsByPhone(String phone) {
- return baseMapper.selectByPhone(phone) != null;
- }
-
- @Override
- public UserInfoResponse getUserInfo(String userId) {
- User user = getById(userId);
- if (user == null) {
- throw new RuntimeException("用户不存在");
- }
- return convertToUserInfoResponse(user);
- }
-
- /**
- * 重置密码(未登录场景)
- *
- *
- * 校验验证码(当前固定为123456),按手机号查询用户,使用 PasswordEncoder(BCrypt) 加密新密码并更新。
- *
- *
- * @param request 重置密码请求
- * @return 重置密码响应
- */
- @Override
- public ResetPasswordResponse resetPassword(ResetPasswordRequest request) {
- // 校验验证码(本期约定固定为 123456)
- if (!"123456".equals(request.getCaptcha())) {
- throw new RuntimeException(ResultCode.CAPTCHA_ERROR.getMessage());
- }
-
- // 按手机号查找用户
- User user = baseMapper.selectByPhone(request.getPhone());
- if (user == null) {
- throw new RuntimeException(ResultCode.USER_NOT_FOUND.getMessage());
- }
-
- // 获取加密器并加密新密码
- PasswordEncoder passwordEncoder = applicationContext.getBean(PasswordEncoder.class);
- String encoded = passwordEncoder.encode(request.getNewPassword());
-
- // 仅更新密码与更新时间(遵循仅更新非空字段原则)
- User toUpdate = new User();
- toUpdate.setId(user.getId());
- toUpdate.setPassword(encoded);
- updateById(toUpdate);
-
- log.info("用户重置密码成功: phone={}", request.getPhone());
- ResetPasswordResponse resp = new ResetPasswordResponse();
- resp.setSuccess(true);
- resp.setMessage("重置密码成功");
- return resp;
- }
-
- @Override
- public void updateLastActiveTime(String userId) {
- baseMapper.updateLastActiveTime(userId);
- }
-
- /**
- * 根据账号查找用户(支持账号/邮箱/手机号)
- */
- private User findUserByAccount(String account) {
- // 先按账号查找
- User user = baseMapper.selectByAccount(account);
- if (user != null) {
- return user;
- }
-
- // 按邮箱查找
- if (account.contains("@")) {
- user = baseMapper.selectByEmail(account);
- if (user != null) {
- return user;
- }
- }
-
- // 按手机号查找
- if (account.matches("^1[3-9]\\d{9}$")) {
- user = baseMapper.selectByPhone(account);
- if (user != null) {
- return user;
- }
- }
-
- return null;
- }
-
- /**
- * 转换为用户信息响应
- */
- private UserInfoResponse convertToUserInfoResponse(User user) {
- UserInfoResponse response = new UserInfoResponse();
- BeanUtils.copyProperties(user, response);
-
- // 设置成长数据
- UserInfoResponse.GrowthStatsVO growthStats = new UserInfoResponse.GrowthStatsVO();
- growthStats.setSelfAwareness(user.getSelfAwareness());
- growthStats.setEmotionalResilience(user.getEmotionalResilience());
- growthStats.setActionPower(user.getActionPower());
- growthStats.setEmpathy(user.getEmpathy());
- growthStats.setLifeEnthusiasm(user.getLifeEnthusiasm());
- response.setGrowthStats(growthStats);
-
- return response;
- }
-
- /**
- * 获取当前用户ID
- */
- private String getCurrentUserId() {
- try {
- return SecurityContextHolder.getContext().getAuthentication().getName();
- } catch (Exception e) {
- return null;
- }
- }
-}
diff --git a/backend/auth/server/src/main/java/com/emotionmuseum/auth/service/impl/CaptchaServiceImpl.java b/backend/auth/server/src/main/java/com/emotionmuseum/auth/service/impl/CaptchaServiceImpl.java
deleted file mode 100644
index 33a4c67..0000000
--- a/backend/auth/server/src/main/java/com/emotionmuseum/auth/service/impl/CaptchaServiceImpl.java
+++ /dev/null
@@ -1,119 +0,0 @@
-package com.emotionmuseum.auth.service.impl;
-
-import cn.hutool.core.util.IdUtil;
-import cn.hutool.core.util.StrUtil;
-import com.emotionmuseum.auth.response.CaptchaResponse;
-import com.emotionmuseum.auth.response.SliderCaptchaResponse;
-import com.emotionmuseum.auth.request.SliderCaptchaVerifyRequest;
-import com.emotionmuseum.auth.service.CaptchaService;
-import com.emotionmuseum.auth.service.SliderCaptchaService;
-import com.wf.captcha.base.Captcha;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.context.ApplicationContext;
-import org.springframework.data.redis.core.RedisTemplate;
-import org.springframework.stereotype.Service;
-
-import java.util.concurrent.TimeUnit;
-
-/**
- * 验证码服务实现
- *
- * @author huazhongmin
- * @since 2025-07-15
- */
-@Slf4j
-@Service
-@RequiredArgsConstructor
-public class CaptchaServiceImpl implements CaptchaService {
-
- private final RedisTemplate redisTemplate;
- private final ApplicationContext applicationContext;
-
- private static final String CAPTCHA_KEY_PREFIX = "captcha:";
- private static final long CAPTCHA_EXPIRE_TIME = 300; // 5分钟
-
- @Override
- public CaptchaResponse generateCaptcha(String type) {
- try {
- // 根据类型获取验证码Bean
- String beanName = getBeanNameByType(type);
- Captcha captcha = (Captcha) applicationContext.getBean(beanName);
-
- // 生成验证码
- String captchaId = IdUtil.simpleUUID();
- String captchaText = captcha.text();
- String captchaImage = captcha.toBase64();
-
- // 存储到Redis
- String redisKey = CAPTCHA_KEY_PREFIX + captchaId;
- redisTemplate.opsForValue().set(redisKey, captchaText.toLowerCase(), CAPTCHA_EXPIRE_TIME, TimeUnit.SECONDS);
-
- log.debug("生成验证码成功,ID: {}, 内容: {}", captchaId, captchaText);
-
- return new CaptchaResponse(captchaId, captchaImage, type, CAPTCHA_EXPIRE_TIME);
- } catch (Exception e) {
- log.error("生成验证码失败: {}", e.getMessage());
- throw new RuntimeException("生成验证码失败");
- }
- }
-
- @Override
- public boolean verifyCaptcha(String captchaId, String captcha) {
- if (StrUtil.isBlank(captchaId) || StrUtil.isBlank(captcha)) {
- return false;
- }
-
- try {
- String redisKey = CAPTCHA_KEY_PREFIX + captchaId;
- String storedCaptcha = (String) redisTemplate.opsForValue().get(redisKey);
-
- if (StrUtil.isBlank(storedCaptcha)) {
- log.warn("验证码已过期或不存在,ID: {}", captchaId);
- return false;
- }
-
- // 验证码不区分大小写
- boolean isValid = storedCaptcha.equalsIgnoreCase(captcha.trim());
-
- if (isValid) {
- // 验证成功后删除验证码
- redisTemplate.delete(redisKey);
- log.debug("验证码验证成功,ID: {}", captchaId);
- } else {
- log.warn("验证码验证失败,ID: {}, 期望: {}, 实际: {}", captchaId, storedCaptcha, captcha);
- }
-
- return isValid;
- } catch (Exception e) {
- log.error("验证验证码失败: {}", e.getMessage());
- return false;
- }
- }
-
- @Override
- public void removeCaptcha(String captchaId) {
- if (StrUtil.isNotBlank(captchaId)) {
- String redisKey = CAPTCHA_KEY_PREFIX + captchaId;
- redisTemplate.delete(redisKey);
- log.debug("删除验证码,ID: {}", captchaId);
- }
- }
-
- /**
- * 根据类型获取Bean名称
- */
- private String getBeanNameByType(String type) {
- String defaultType = StrUtil.blankToDefault(type, "spec");
- switch (defaultType) {
- case "arithmetic":
- return "arithmeticCaptcha";
- case "chinese":
- return "chineseCaptcha";
- case "gif":
- return "gifCaptcha";
- default:
- return "specCaptcha";
- }
- }
-}
diff --git a/backend/auth/server/src/main/java/com/emotionmuseum/auth/service/impl/OAuthServiceImpl.java b/backend/auth/server/src/main/java/com/emotionmuseum/auth/service/impl/OAuthServiceImpl.java
deleted file mode 100644
index f99a6e0..0000000
--- a/backend/auth/server/src/main/java/com/emotionmuseum/auth/service/impl/OAuthServiceImpl.java
+++ /dev/null
@@ -1,101 +0,0 @@
-package com.emotionmuseum.auth.service.impl;
-
-import com.emotionmuseum.auth.dto.OAuthLoginRequest;
-import com.emotionmuseum.auth.service.OAuthService;
-import com.emotionmuseum.auth.vo.LoginResponse;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.stereotype.Service;
-
-/**
- * 第三方登录服务实现类
- *
- * @author huazhongmin
- * @since 2025-07-15
- */
-@Slf4j
-@Service
-public class OAuthServiceImpl implements OAuthService {
-
- @Value("${oauth.wechat.client-id:}")
- private String wechatClientId;
-
- @Value("${oauth.wechat.client-secret:}")
- private String wechatClientSecret;
-
- @Value("${oauth.wechat.redirect-uri:}")
- private String wechatRedirectUri;
-
- @Value("${oauth.qq.client-id:}")
- private String qqClientId;
-
- @Value("${oauth.qq.client-secret:}")
- private String qqClientSecret;
-
- @Value("${oauth.qq.redirect-uri:}")
- private String qqRedirectUri;
-
- @Override
- public String getAuthUrl(String platform) {
- log.info("获取第三方登录授权URL, platform: {}", platform);
-
- switch (platform.toLowerCase()) {
- case "wechat":
- return buildWechatAuthUrl();
- case "qq":
- return buildQQAuthUrl();
- default:
- throw new IllegalArgumentException("不支持的第三方平台: " + platform);
- }
- }
-
- @Override
- public LoginResponse oauthLogin(OAuthLoginRequest request) {
- log.info("第三方登录, platform: {}, code: {}", request.getPlatform(), request.getCode());
-
- // TODO: 实现第三方登录逻辑
- // 1. 根据code获取access_token
- // 2. 根据access_token获取用户信息
- // 3. 查询或创建用户
- // 4. 生成JWT token
-
- throw new UnsupportedOperationException("第三方登录功能暂未实现");
- }
-
- @Override
- public Object getOAuthUserInfo(String platform, String code, String state) {
- log.info("获取第三方用户信息, platform: {}, code: {}, state: {}", platform, code, state);
-
- // TODO: 实现获取第三方用户信息逻辑
-
- throw new UnsupportedOperationException("获取第三方用户信息功能暂未实现");
- }
-
- /**
- * 构建微信授权URL
- */
- private String buildWechatAuthUrl() {
- if (wechatClientId.isEmpty()) {
- throw new IllegalStateException("微信OAuth配置未完成");
- }
-
- // TODO: 构建微信授权URL
- return "https://open.weixin.qq.com/connect/oauth2/authorize?appid=" + wechatClientId +
- "&redirect_uri=" + wechatRedirectUri +
- "&response_type=code&scope=snsapi_userinfo&state=wechat#wechat_redirect";
- }
-
- /**
- * 构建QQ授权URL
- */
- private String buildQQAuthUrl() {
- if (qqClientId.isEmpty()) {
- throw new IllegalStateException("QQ OAuth配置未完成");
- }
-
- // TODO: 构建QQ授权URL
- return "https://graph.qq.com/oauth2.0/authorize?response_type=code&client_id=" + qqClientId +
- "&redirect_uri=" + qqRedirectUri +
- "&state=qq&scope=get_user_info";
- }
-}
diff --git a/backend/auth/server/src/main/java/com/emotionmuseum/auth/service/impl/SliderCaptchaServiceImpl.java b/backend/auth/server/src/main/java/com/emotionmuseum/auth/service/impl/SliderCaptchaServiceImpl.java
deleted file mode 100644
index f634c99..0000000
--- a/backend/auth/server/src/main/java/com/emotionmuseum/auth/service/impl/SliderCaptchaServiceImpl.java
+++ /dev/null
@@ -1,210 +0,0 @@
-package com.emotionmuseum.auth.service.impl;
-
-import cn.hutool.core.util.IdUtil;
-import cn.hutool.core.util.StrUtil;
-import com.emotionmuseum.auth.response.SliderCaptchaResponse;
-import com.emotionmuseum.auth.request.SliderCaptchaVerifyRequest;
-import com.emotionmuseum.auth.service.SliderCaptchaService;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.data.redis.core.RedisTemplate;
-import org.springframework.stereotype.Service;
-
-import javax.imageio.ImageIO;
-import java.awt.*;
-import java.awt.image.BufferedImage;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.util.Base64;
-import java.util.Random;
-import java.util.concurrent.TimeUnit;
-
-/**
- * 滑块验证码服务实现
- *
- * @author huazhongmin
- * @since 2025-07-15
- */
-@Slf4j
-@Service
-@RequiredArgsConstructor
-public class SliderCaptchaServiceImpl implements SliderCaptchaService {
-
- private final RedisTemplate redisTemplate;
-
- private static final String SLIDER_CAPTCHA_KEY_PREFIX = "slider_captcha:";
- private static final long SLIDER_CAPTCHA_EXPIRE_TIME = 300; // 5分钟
- private static final int BACKGROUND_WIDTH = 300;
- private static final int BACKGROUND_HEIGHT = 150;
- private static final int SLIDER_WIDTH = 60;
- private static final int SLIDER_HEIGHT = 60;
- private static final int TOLERANCE = 5; // 容错范围
-
- @Override
- public SliderCaptchaResponse generateSliderCaptcha() {
- try {
- String captchaId = IdUtil.simpleUUID();
-
- // 生成随机位置
- Random random = new Random();
- int sliderX = random.nextInt(BACKGROUND_WIDTH - SLIDER_WIDTH - 50) + 50;
- int sliderY = random.nextInt(BACKGROUND_HEIGHT - SLIDER_HEIGHT - 20) + 20;
-
- // 生成背景图片
- BufferedImage backgroundImage = generateBackgroundImage(sliderX, sliderY);
- String backgroundBase64 = imageToBase64(backgroundImage);
-
- // 生成滑块图片
- BufferedImage sliderImage = generateSliderImage();
- String sliderBase64 = imageToBase64(sliderImage);
-
- // 存储到Redis
- String redisKey = SLIDER_CAPTCHA_KEY_PREFIX + captchaId;
- SliderCaptchaData data = new SliderCaptchaData(sliderX, sliderY);
- redisTemplate.opsForValue().set(redisKey, data, SLIDER_CAPTCHA_EXPIRE_TIME, TimeUnit.SECONDS);
-
- log.debug("生成滑块验证码成功,ID: {}, 位置: ({}, {})", captchaId, sliderX, sliderY);
-
- return new SliderCaptchaResponse(captchaId, backgroundBase64, sliderBase64, 0, sliderY, SLIDER_CAPTCHA_EXPIRE_TIME);
- } catch (Exception e) {
- log.error("生成滑块验证码失败: {}", e.getMessage());
- throw new RuntimeException("生成滑块验证码失败");
- }
- }
-
- @Override
- public boolean verifySliderCaptcha(SliderCaptchaVerifyRequest request) {
- if (StrUtil.isBlank(request.getCaptchaId()) || request.getX() == null) {
- return false;
- }
-
- try {
- String redisKey = SLIDER_CAPTCHA_KEY_PREFIX + request.getCaptchaId();
- SliderCaptchaData data = (SliderCaptchaData) redisTemplate.opsForValue().get(redisKey);
-
- if (data == null) {
- log.warn("滑块验证码已过期或不存在,ID: {}", request.getCaptchaId());
- return false;
- }
-
- // 验证X坐标是否在容错范围内
- boolean isValid = Math.abs(data.getSliderX() - request.getX()) <= TOLERANCE;
-
- if (isValid) {
- // 验证成功后删除验证码
- redisTemplate.delete(redisKey);
- log.debug("滑块验证码验证成功,ID: {}", request.getCaptchaId());
- } else {
- log.warn("滑块验证码验证失败,ID: {}, 期望X: {}, 实际X: {}",
- request.getCaptchaId(), data.getSliderX(), request.getX());
- }
-
- return isValid;
- } catch (Exception e) {
- log.error("验证滑块验证码失败: {}", e.getMessage());
- return false;
- }
- }
-
- @Override
- public void removeSliderCaptcha(String captchaId) {
- if (StrUtil.isNotBlank(captchaId)) {
- String redisKey = SLIDER_CAPTCHA_KEY_PREFIX + captchaId;
- redisTemplate.delete(redisKey);
- log.debug("删除滑块验证码,ID: {}", captchaId);
- }
- }
-
- /**
- * 生成背景图片
- */
- private BufferedImage generateBackgroundImage(int sliderX, int sliderY) {
- BufferedImage image = new BufferedImage(BACKGROUND_WIDTH, BACKGROUND_HEIGHT, BufferedImage.TYPE_INT_RGB);
- Graphics2D g2d = image.createGraphics();
-
- // 设置抗锯齿
- g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
-
- // 绘制渐变背景
- GradientPaint gradient = new GradientPaint(0, 0, new Color(135, 206, 250),
- BACKGROUND_WIDTH, BACKGROUND_HEIGHT, new Color(70, 130, 180));
- g2d.setPaint(gradient);
- g2d.fillRect(0, 0, BACKGROUND_WIDTH, BACKGROUND_HEIGHT);
-
- // 绘制一些装饰性图形
- Random random = new Random();
- g2d.setColor(new Color(255, 255, 255, 100));
- for (int i = 0; i < 20; i++) {
- int x = random.nextInt(BACKGROUND_WIDTH);
- int y = random.nextInt(BACKGROUND_HEIGHT);
- int size = random.nextInt(20) + 5;
- g2d.fillOval(x, y, size, size);
- }
-
- // 绘制滑块缺口
- g2d.setColor(new Color(0, 0, 0, 150));
- g2d.fillRoundRect(sliderX, sliderY, SLIDER_WIDTH, SLIDER_HEIGHT, 10, 10);
-
- g2d.dispose();
- return image;
- }
-
- /**
- * 生成滑块图片
- */
- private BufferedImage generateSliderImage() {
- BufferedImage image = new BufferedImage(SLIDER_WIDTH, SLIDER_HEIGHT, BufferedImage.TYPE_INT_ARGB);
- Graphics2D g2d = image.createGraphics();
-
- // 设置抗锯齿
- g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
-
- // 绘制滑块
- g2d.setColor(new Color(70, 130, 180));
- g2d.fillRoundRect(0, 0, SLIDER_WIDTH, SLIDER_HEIGHT, 10, 10);
-
- // 绘制边框
- g2d.setColor(new Color(255, 255, 255));
- g2d.setStroke(new BasicStroke(2));
- g2d.drawRoundRect(1, 1, SLIDER_WIDTH - 2, SLIDER_HEIGHT - 2, 10, 10);
-
- // 绘制箭头
- g2d.setColor(Color.WHITE);
- int[] xPoints = {SLIDER_WIDTH/2 - 8, SLIDER_WIDTH/2 + 8, SLIDER_WIDTH/2};
- int[] yPoints = {SLIDER_HEIGHT/2, SLIDER_HEIGHT/2, SLIDER_HEIGHT/2 - 8};
- g2d.fillPolygon(xPoints, yPoints, 3);
-
- g2d.dispose();
- return image;
- }
-
- /**
- * 图片转Base64
- */
- private String imageToBase64(BufferedImage image) throws IOException {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- ImageIO.write(image, "PNG", baos);
- byte[] bytes = baos.toByteArray();
- return "data:image/png;base64," + Base64.getEncoder().encodeToString(bytes);
- }
-
- /**
- * 滑块验证码数据
- */
- public static class SliderCaptchaData {
- private int sliderX;
- private int sliderY;
-
- public SliderCaptchaData() {}
-
- public SliderCaptchaData(int sliderX, int sliderY) {
- this.sliderX = sliderX;
- this.sliderY = sliderY;
- }
-
- public int getSliderX() { return sliderX; }
- public void setSliderX(int sliderX) { this.sliderX = sliderX; }
- public int getSliderY() { return sliderY; }
- public void setSliderY(int sliderY) { this.sliderY = sliderY; }
- }
-}
diff --git a/backend/auth/server/src/main/java/com/emotionmuseum/auth/vo/LoginResponse.java b/backend/auth/server/src/main/java/com/emotionmuseum/auth/vo/LoginResponse.java
deleted file mode 100644
index 6258e52..0000000
--- a/backend/auth/server/src/main/java/com/emotionmuseum/auth/vo/LoginResponse.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package com.emotionmuseum.auth.vo;
-
-import com.fasterxml.jackson.annotation.JsonFormat;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-
-import java.time.LocalDateTime;
-
-/**
- * 登录响应
- *
- * @author huazhongmin
- * @since 2025-07-12
- */
-@Data
-@Schema(description = "登录响应")
-public class LoginResponse {
-
- @Schema(description = "访问Token")
- private String accessToken;
-
- @Schema(description = "刷新Token")
- private String refreshToken;
-
- @Schema(description = "Token类型", example = "Bearer")
- private String tokenType = "Bearer";
-
- @Schema(description = "Token过期时间(秒)", example = "86400")
- private Long expiresIn;
-
- @Schema(description = "用户信息")
- private UserInfoResponse userInfo;
-
- @Schema(description = "登录时间")
- @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
- private LocalDateTime loginTime;
-}
diff --git a/backend/auth/server/src/main/java/com/emotionmuseum/auth/vo/UserInfoResponse.java b/backend/auth/server/src/main/java/com/emotionmuseum/auth/vo/UserInfoResponse.java
deleted file mode 100644
index b73aa51..0000000
--- a/backend/auth/server/src/main/java/com/emotionmuseum/auth/vo/UserInfoResponse.java
+++ /dev/null
@@ -1,97 +0,0 @@
-package com.emotionmuseum.auth.vo;
-
-import com.fasterxml.jackson.annotation.JsonFormat;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-
-import java.math.BigDecimal;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-
-/**
- * 用户信息响应
- *
- * @author huazhongmin
- * @since 2025-07-16
- */
-@Data
-@Schema(description = "用户信息响应")
-public class UserInfoResponse {
-
- @Schema(description = "用户ID")
- private String id;
-
- @Schema(description = "账号")
- private String account;
-
- @Schema(description = "用户名")
- private String username;
-
- @Schema(description = "邮箱")
- private String email;
-
- @Schema(description = "手机号")
- private String phone;
-
- @Schema(description = "头像URL")
- private String avatar;
-
- @Schema(description = "昵称")
- private String nickname;
-
- @Schema(description = "生日")
- @JsonFormat(pattern = "yyyy-MM-dd")
- private LocalDate birthDate;
-
- @Schema(description = "所在地")
- private String location;
-
- @Schema(description = "个人简介")
- private String bio;
-
- @Schema(description = "会员等级")
- private String memberLevel;
-
- @Schema(description = "使用天数")
- private Integer totalDays;
-
- @Schema(description = "成长数据")
- private GrowthStatsVO growthStats;
-
- @Schema(description = "状态")
- private Integer status;
-
- @Schema(description = "是否已验证")
- private Integer isVerified;
-
- @Schema(description = "创建时间")
- @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
- private LocalDateTime createTime;
-
- @Schema(description = "最后活跃时间")
- @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
- private LocalDateTime lastActiveTime;
-
- /**
- * 成长数据VO
- */
- @Data
- @Schema(description = "成长数据")
- public static class GrowthStatsVO {
-
- @Schema(description = "自我感知")
- private BigDecimal selfAwareness;
-
- @Schema(description = "情绪韧性")
- private BigDecimal emotionalResilience;
-
- @Schema(description = "行动力")
- private BigDecimal actionPower;
-
- @Schema(description = "共情力")
- private BigDecimal empathy;
-
- @Schema(description = "生活热度")
- private BigDecimal lifeEnthusiasm;
- }
-}
diff --git a/backend/auth/server/src/main/resources/application-local.yml b/backend/auth/server/src/main/resources/application-local.yml
deleted file mode 100644
index 4c43ab2..0000000
--- a/backend/auth/server/src/main/resources/application-local.yml
+++ /dev/null
@@ -1,103 +0,0 @@
-server:
- port: 19008
-
-spring:
- # 数据源配置
- datasource:
- driver-class-name: com.mysql.cj.jdbc.Driver
- url: jdbc:mysql://localhost:3306/emotion_museum?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
- username: root
- password: 123456
-
- # 连接池配置
- hikari:
- minimum-idle: 5
- maximum-pool-size: 20
- idle-timeout: 300000
- connection-timeout: 20000
- max-lifetime: 1200000
- pool-name: EmotionAuthHikariCP
-
- # Redis配置
- data:
- redis:
- host: localhost
- port: 6379
- password:
- database: 0
- timeout: 5000ms
- lettuce:
- pool:
- max-active: 20
- max-idle: 10
- min-idle: 5
- max-wait: 2000ms
-
- # 云服务配置
- cloud:
- nacos:
- discovery:
- server-addr: localhost:8848
- username: nacos
- password: Peanut2817*#
- config:
- server-addr: localhost:8848
- username: nacos
- password: Peanut2817*#
-
-# MyBatis Plus配置
-mybatis-plus:
- configuration:
- map-underscore-to-camel-case: true
- log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
- global-config:
- db-config:
- id-type: assign_uuid
- logic-delete-field: deleted
- logic-delete-value: 1
- logic-not-delete-value: 0
-
-# 监控配置
-management:
- endpoints:
- web:
- exposure:
- include: health,info,metrics,prometheus
- endpoint:
- health:
- show-details: always
- metrics:
- export:
- prometheus:
- enabled: true
-
-# 日志配置
-logging:
- level:
- com.emotionmuseum: debug
- com.baomidou.mybatisplus: debug
- pattern:
- console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level [%logger{50}] - %msg%n"
-
-# JWT配置
-jwt:
- secret: emotion-museum-secret-key-2025
- expiration: 86400
- refresh-expiration: 604800
-
-# 验证码配置
-captcha:
- type: arithmetic
- length: 4
- expire-time: 300
-
-# OAuth配置
-oauth:
- wechat:
- client-id:
- client-secret:
- redirect-uri:
- qq:
- client-id:
- client-secret:
- redirect-uri:
diff --git a/backend/auth/server/src/main/resources/application-prod.yml b/backend/auth/server/src/main/resources/application-prod.yml
deleted file mode 100644
index 9698fdf..0000000
--- a/backend/auth/server/src/main/resources/application-prod.yml
+++ /dev/null
@@ -1,104 +0,0 @@
-server:
- port: 19008
-
-spring:
- # 数据源配置
- datasource:
- driver-class-name: com.mysql.cj.jdbc.Driver
- url: jdbc:mysql://${MYSQL_HOST}:${MYSQL_PORT}/${MYSQL_DATABASE}?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
- username: ${MYSQL_USERNAME}
- password: EmotionMuseum2025*#
-
- # 连接池配置
- hikari:
- minimum-idle: 10
- maximum-pool-size: 50
- idle-timeout: 300000
- connection-timeout: 20000
- max-lifetime: 1200000
- pool-name: EmotionAuthHikariCP
-
- # Redis配置
- data:
- redis:
- host: ${REDIS_HOST}
- port: ${REDIS_PORT}
- password: ${REDIS_PASSWORD}
- database: ${REDIS_DATABASE}
- timeout: 5000ms
- lettuce:
- pool:
- max-active: 50
- max-idle: 20
- min-idle: 10
- max-wait: 2000ms
-
- # 云服务配置
- cloud:
- nacos:
- discovery:
- server-addr: ${NACOS_SERVER_ADDR}
- username: ${NACOS_USERNAME}
- password: EmotionMuseum2025*#
- config:
- server-addr: ${NACOS_SERVER_ADDR}
- username: ${NACOS_USERNAME}
- password: EmotionMuseum2025*#
-
-# MyBatis Plus配置
-mybatis-plus:
- configuration:
- map-underscore-to-camel-case: true
- log-impl: org.apache.ibatis.logging.nologging.NoLoggingImpl
- global-config:
- db-config:
- id-type: assign_uuid
- logic-delete-field: deleted
- logic-delete-value: 1
- logic-not-delete-value: 0
-
-# 监控配置
-management:
- endpoints:
- web:
- exposure:
- include: health,info,metrics,prometheus
- endpoint:
- health:
- show-details: when-authorized
- metrics:
- export:
- prometheus:
- enabled: true
-
-# 日志配置
-logging:
- level:
- com.emotionmuseum: info
- com.baomidou.mybatisplus: warn
- root: warn
- pattern:
- console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level [%logger{50}] - %msg%n"
-
-# JWT配置
-jwt:
- secret: ${JWT_SECRET}
- expiration: ${JWT_EXPIRATION:86400}
- refresh-expiration: ${JWT_REFRESH_EXPIRATION:604800}
-
-# 验证码配置
-captcha:
- type: arithmetic
- length: 4
- expire-time: 300
-
-# OAuth配置
-oauth:
- wechat:
- client-id: ${WECHAT_CLIENT_ID}
- client-secret: ${WECHAT_CLIENT_SECRET}
- redirect-uri: ${WECHAT_REDIRECT_URI}
- qq:
- client-id: ${QQ_CLIENT_ID}
- client-secret: ${QQ_CLIENT_SECRET}
- redirect-uri: ${QQ_REDIRECT_URI}
diff --git a/backend/auth/server/src/main/resources/application-test.yml b/backend/auth/server/src/main/resources/application-test.yml
deleted file mode 100644
index c49dafd..0000000
--- a/backend/auth/server/src/main/resources/application-test.yml
+++ /dev/null
@@ -1,103 +0,0 @@
-server:
- port: 19008
-
-spring:
- # 数据源配置
- datasource:
- driver-class-name: com.mysql.cj.jdbc.Driver
- url: jdbc:mysql://${MYSQL_HOST}:${MYSQL_PORT}/${MYSQL_DATABASE}?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
- username: ${MYSQL_USERNAME}
- password: EmotionMuseum2025*#
-
- # 连接池配置
- hikari:
- minimum-idle: 5
- maximum-pool-size: 20
- idle-timeout: 300000
- connection-timeout: 20000
- max-lifetime: 1200000
- pool-name: EmotionAuthHikariCP
-
- # Redis配置
- data:
- redis:
- host: ${REDIS_HOST}
- port: ${REDIS_PORT}
- password: ${REDIS_PASSWORD}
- database: ${REDIS_DATABASE}
- timeout: 5000ms
- lettuce:
- pool:
- max-active: 20
- max-idle: 10
- min-idle: 5
- max-wait: 2000ms
-
- # 云服务配置
- cloud:
- nacos:
- discovery:
- server-addr: ${NACOS_SERVER_ADDR}
- username: ${NACOS_USERNAME}
- password: EmotionMuseum2025*#
- config:
- server-addr: ${NACOS_SERVER_ADDR}
- username: ${NACOS_USERNAME}
- password: EmotionMuseum2025*#
-
-# MyBatis Plus配置
-mybatis-plus:
- configuration:
- map-underscore-to-camel-case: true
- log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
- global-config:
- db-config:
- id-type: assign_uuid
- logic-delete-field: deleted
- logic-delete-value: 1
- logic-not-delete-value: 0
-
-# 监控配置
-management:
- endpoints:
- web:
- exposure:
- include: health,info,metrics,prometheus
- endpoint:
- health:
- show-details: always
- metrics:
- export:
- prometheus:
- enabled: true
-
-# 日志配置
-logging:
- level:
- com.emotionmuseum: info
- com.baomidou.mybatisplus: info
- pattern:
- console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level [%logger{50}] - %msg%n"
-
-# JWT配置
-jwt:
- secret: ${JWT_SECRET:emotion-museum-secret-key-2025}
- expiration: ${JWT_EXPIRATION:86400}
- refresh-expiration: ${JWT_REFRESH_EXPIRATION:604800}
-
-# 验证码配置
-captcha:
- type: arithmetic
- length: 4
- expire-time: 300
-
-# OAuth配置
-oauth:
- wechat:
- client-id: ${WECHAT_CLIENT_ID}
- client-secret: ${WECHAT_CLIENT_SECRET}
- redirect-uri: ${WECHAT_REDIRECT_URI}
- qq:
- client-id: ${QQ_CLIENT_ID}
- client-secret: ${QQ_CLIENT_SECRET}
- redirect-uri: ${QQ_REDIRECT_URI}
diff --git a/backend/auth/server/src/main/resources/application.yml b/backend/auth/server/src/main/resources/application.yml
deleted file mode 100644
index 7d49a01..0000000
--- a/backend/auth/server/src/main/resources/application.yml
+++ /dev/null
@@ -1,23 +0,0 @@
-spring:
- application:
- name: emotion-auth
- profiles:
- active: ${SPRING_PROFILES_ACTIVE:local}
- main:
- allow-bean-definition-overriding: true
- cloud:
- nacos:
- config:
- enabled: false
- discovery:
- enabled: true
- server-addr: 101.200.208.45:8848
- username: nacos
- password: Peanut2817*#
-
-
-
-logging:
- file:
- path: /data/logs/emotion-museum/auth
-
diff --git a/backend/auth/server/src/main/resources/mapper/UserMapper.xml b/backend/auth/server/src/main/resources/mapper/UserMapper.xml
deleted file mode 100644
index 576448e..0000000
--- a/backend/auth/server/src/main/resources/mapper/UserMapper.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- UPDATE user
- SET last_active_time = NOW(), update_time = NOW()
- WHERE id = #{userId} AND is_deleted = 0
-
-
-
diff --git a/backend/build-all.sh b/backend/build-all.sh
deleted file mode 100644
index be256f2..0000000
--- a/backend/build-all.sh
+++ /dev/null
@@ -1,261 +0,0 @@
-#!/bin/bash
-
-# 情感博物馆 - Jenkins构建脚本
-# 作者: emotion-museum
-# 日期: 2025-07-18
-# 用途: 在Jenkins服务器上构建所有微服务jar包
-
-set -e
-
-# 配置变量
-PROFILE="${DEPLOY_ENV:-test}"
-PROJECT_NAME="${PROJECT_NAME:-emotion-museum}"
-
-# Jenkins构建信息
-BUILD_NUMBER="${BUILD_NUMBER:-manual}"
-JOB_NAME="${JOB_NAME:-local-build}"
-BUILD_URL="${BUILD_URL:-}"
-
-# 颜色输出
-RED='\033[0;31m'
-GREEN='\033[0;32m'
-YELLOW='\033[1;33m'
-BLUE='\033[0;34m'
-NC='\033[0m'
-
-# 日志函数
-log_info() {
- echo -e "${BLUE}[INFO]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
-}
-
-log_success() {
- echo -e "${GREEN}[SUCCESS]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
-}
-
-log_warning() {
- echo -e "${YELLOW}[WARNING]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
-}
-
-log_error() {
- echo -e "${RED}[ERROR]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
-}
-
-# 服务列表
-SERVICES=(
- "emotion-gateway:19000"
- "emotion-user:19001"
- "emotion-ai:19002"
- "emotion-record:19003"
- "emotion-growth:19004"
- "emotion-explore:19005"
- "emotion-reward:19006"
- "emotion-websocket:19007"
- "emotion-auth:19008"
- "emotion-stats:19009"
-)
-
-# 检查构建环境
-check_build_environment() {
- log_info "检查构建环境..."
-
- # 检查Java版本
- if command -v java &> /dev/null; then
- local java_version=$(java -version 2>&1 | head -1 | cut -d'"' -f2)
- log_info "Java版本: $java_version"
- else
- log_error "Java未安装"
- exit 1
- fi
-
- # 检查Maven版本
- if command -v mvn &> /dev/null; then
- local maven_version=$(mvn -version | head -1 | awk '{print $3}')
- log_info "Maven版本: $maven_version"
- else
- log_error "Maven未安装"
- exit 1
- fi
-
- # 检查是否在Jenkins环境中
- if [ -n "$JENKINS_HOME" ] || [ -n "$BUILD_NUMBER" ]; then
- log_info "检测到Jenkins环境"
- log_info "构建编号: $BUILD_NUMBER"
- log_info "任务名称: $JOB_NAME"
- else
- log_info "本地构建环境"
- fi
-
- log_success "构建环境检查通过"
-}
-
-# 清理旧的构建产物
-clean_old_artifacts() {
- log_info "清理旧的构建产物..."
-
- # 清理父项目
- mvn clean -q
-
- # 清理各个子模块
- for service_info in "${SERVICES[@]}"; do
- service_name=$(echo $service_info | cut -d':' -f1)
- if [ -d "$service_name" ]; then
- log_info "清理模块: $service_name"
- cd $service_name
- mvn clean -q
- cd ..
- fi
- done
-
- log_success "构建产物清理完成"
-}
-
-# 构建所有服务
-build_all_services() {
- log_info "开始构建所有微服务..."
-
- # 先构建父项目
- log_info "构建父项目..."
- if mvn install -DskipTests -q; then
- log_success "父项目构建成功"
- else
- log_error "父项目构建失败"
- exit 1
- fi
-
- # 构建各个微服务
- local build_success=0
- local build_failed=0
-
- for service_info in "${SERVICES[@]}"; do
- service_name=$(echo $service_info | cut -d':' -f1)
- log_info "构建服务: $service_name"
-
- if [ ! -d "$service_name" ]; then
- log_warning "服务目录不存在: $service_name"
- continue
- fi
-
- cd $service_name
- if mvn package -DskipTests -P${PROFILE} -q; then
- # 检查jar包是否生成
- if [ -f "target/${service_name}-1.0.0.jar" ]; then
- local jar_size=$(du -h "target/${service_name}-1.0.0.jar" | cut -f1)
- log_success "✅ $service_name 构建成功 (大小: $jar_size)"
- build_success=$((build_success + 1))
- else
- log_error "❌ $service_name jar包未生成"
- build_failed=$((build_failed + 1))
- fi
- else
- log_error "❌ $service_name 构建失败"
- build_failed=$((build_failed + 1))
- fi
- cd ..
- done
-
- log_info "构建统计: 成功 $build_success, 失败 $build_failed"
-
- if [ $build_failed -eq 0 ]; then
- log_success "所有服务构建成功"
- return 0
- else
- log_error "部分服务构建失败"
- return 1
- fi
-}
-
-# 生成构建报告
-generate_build_report() {
- local total_time=$1
-
- echo ""
- echo "========================================"
- echo " 构建完成报告"
- echo "========================================"
- echo "项目名称: $PROJECT_NAME"
- echo "构建环境: $PROFILE"
- echo "构建时间: $(date '+%Y-%m-%d %H:%M:%S')"
- echo "总耗时: ${total_time}s"
- if [ "$BUILD_NUMBER" != "manual" ]; then
- echo "Jenkins构建: #$BUILD_NUMBER"
- echo "Jenkins任务: $JOB_NAME"
- [ -n "$BUILD_URL" ] && echo "构建链接: $BUILD_URL"
- fi
- echo "========================================"
-
- echo ""
- echo "📦 构建产物详情:"
- printf "%-20s %-10s %-10s %s\n" "服务名称" "状态" "大小" "路径"
- echo "----------------------------------------"
-
- local total_size=0
- for service_info in "${SERVICES[@]}"; do
- service_name=$(echo $service_info | cut -d':' -f1)
- jar_file="${service_name}/target/${service_name}-1.0.0.jar"
-
- if [ -f "$jar_file" ]; then
- jar_size=$(du -h "$jar_file" | cut -f1)
- # 兼容macOS和Linux的文件大小获取
- if [[ "$OSTYPE" == "darwin"* ]]; then
- jar_bytes=$(stat -f%z "$jar_file" 2>/dev/null || echo "0")
- else
- jar_bytes=$(stat -c%s "$jar_file" 2>/dev/null || echo "0")
- fi
- total_size=$((total_size + jar_bytes))
- printf "%-20s ${GREEN}%-10s${NC} %-10s %s\n" "$service_name" "✅ 成功" "$jar_size" "$jar_file"
- else
- printf "%-20s ${RED}%-10s${NC} %-10s %s\n" "$service_name" "❌ 失败" "N/A" "未生成"
- fi
- done
-
- echo ""
- echo "📊 构建统计:"
- echo " 总产物大小: $(echo $total_size | awk '{printf "%.1fMB", $1/1024/1024}')"
- echo " 构建工作空间: $(pwd)"
- echo ""
- echo "========================================"
- echo "🎉 构建任务完成!"
-}
-
-# 主函数
-main() {
- local start_time=$(date +%s)
-
- log_info "🔨 开始Jenkins构建任务..."
- log_info "构建环境: $PROFILE"
- log_info "项目名称: $PROJECT_NAME"
-
- # 检查构建环境
- check_build_environment
-
- # 清理旧产物
- clean_old_artifacts
-
- # 构建所有服务
- if build_all_services; then
- log_success "所有服务构建成功"
- build_result=0
- else
- log_error "部分服务构建失败"
- build_result=1
- fi
-
- # 计算总耗时
- local end_time=$(date +%s)
- local total_time=$((end_time - start_time))
-
- # 生成构建报告
- generate_build_report $total_time
-
- # 返回构建结果
- if [ $build_result -eq 0 ]; then
- log_success "🎉 Jenkins构建任务完成!"
- exit 0
- else
- log_error "⚠️ 构建任务部分失败,请检查错误日志"
- exit 1
- fi
-}
-
-# 执行主函数
-main "$@"
diff --git a/backend/common/pom.xml b/backend/common/pom.xml
deleted file mode 100644
index c5c9cde..0000000
--- a/backend/common/pom.xml
+++ /dev/null
@@ -1,83 +0,0 @@
-
-
- 4.0.0
-
-
- com.emotionmuseum
- backend
- 1.0.0
-
-
- common
- common
- 公共模块
-
-
-
-
- org.springframework.boot
- spring-boot-starter-web
-
-
-
-
- org.springframework.boot
- spring-boot-starter-validation
-
-
-
-
- com.baomidou
- mybatis-plus-boot-starter
-
-
-
-
- org.springframework.boot
- spring-boot-starter-data-redis
-
-
-
-
- org.projectlombok
- lombok
- true
-
-
-
-
- cn.hutool
- hutool-all
-
-
-
- com.alibaba.fastjson2
- fastjson2
-
-
-
-
- io.jsonwebtoken
- jjwt-api
-
-
-
- io.jsonwebtoken
- jjwt-impl
-
-
-
- io.jsonwebtoken
- jjwt-jackson
-
-
-
-
- com.github.xiaoymin
- knife4j-openapi3-spring-boot-starter
-
-
-
diff --git a/backend/common/src/main/java/com/emotionmuseum/common/config/MybatisPlusConfig.java b/backend/common/src/main/java/com/emotionmuseum/common/config/MybatisPlusConfig.java
deleted file mode 100644
index 9eae747..0000000
--- a/backend/common/src/main/java/com/emotionmuseum/common/config/MybatisPlusConfig.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package com.emotionmuseum.common.config;
-
-import com.baomidou.mybatisplus.annotation.DbType;
-import com.baomidou.mybatisplus.core.config.GlobalConfig;
-import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
-import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
-import com.emotionmuseum.common.handler.EmotionMetaObjectHandler;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-
-/**
- * MyBatis-Plus 配置类
- *
- * @author huazhongmin
- * @since 2025-07-12
- */
-@Configuration
-public class MybatisPlusConfig {
-
- /**
- * MyBatis-Plus 拦截器配置
- * 添加分页插件
- */
- @Bean
- public MybatisPlusInterceptor mybatisPlusInterceptor() {
- MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
-
- // 分页插件
- PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();
- paginationInnerInterceptor.setDbType(DbType.MYSQL);
- paginationInnerInterceptor.setOverflow(false);
- paginationInnerInterceptor.setMaxLimit(1000L);
- interceptor.addInnerInterceptor(paginationInnerInterceptor);
-
- return interceptor;
- }
-
- /**
- * 全局配置
- */
- @Bean
- public GlobalConfig globalConfig() {
- GlobalConfig globalConfig = new GlobalConfig();
-
- // 设置元数据处理器
- globalConfig.setMetaObjectHandler(new EmotionMetaObjectHandler());
-
- // 设置逻辑删除配置
- GlobalConfig.DbConfig dbConfig = new GlobalConfig.DbConfig();
- dbConfig.setLogicDeleteField("is_deleted"); // 逻辑删除字段名
- dbConfig.setLogicDeleteValue("1"); // 删除值
- dbConfig.setLogicNotDeleteValue("0"); // 未删除值
- globalConfig.setDbConfig(dbConfig);
-
- return globalConfig;
- }
-}
diff --git a/backend/common/src/main/java/com/emotionmuseum/common/config/RestTemplateConfig.java b/backend/common/src/main/java/com/emotionmuseum/common/config/RestTemplateConfig.java
deleted file mode 100644
index ce0f4d0..0000000
--- a/backend/common/src/main/java/com/emotionmuseum/common/config/RestTemplateConfig.java
+++ /dev/null
@@ -1,97 +0,0 @@
-package com.emotionmuseum.common.config;
-
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.boot.web.client.RestTemplateBuilder;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.http.client.ClientHttpRequestInterceptor;
-import org.springframework.http.client.ClientHttpResponse;
-import org.springframework.web.client.RestTemplate;
-
-import java.io.IOException;
-import java.time.Duration;
-import java.util.Collections;
-
-/**
- * RestTemplate配置类
- *
- * @author huazhongmin
- * @since 2025-07-12
- */
-@Slf4j
-@Configuration
-public class RestTemplateConfig {
-
- /**
- * 默认RestTemplate
- */
- @Bean("restTemplate")
- public RestTemplate restTemplate(RestTemplateBuilder builder) {
- return builder
- .setConnectTimeout(Duration.ofSeconds(30))
- .setReadTimeout(Duration.ofSeconds(60))
- .interceptors(Collections.singletonList(loggingInterceptor()))
- .build();
- }
-
- /**
- * 长连接RestTemplate(用于AI接口等耗时操作)
- */
- @Bean("longRestTemplate")
- public RestTemplate longRestTemplate(RestTemplateBuilder builder) {
- return builder
- .setConnectTimeout(Duration.ofSeconds(60))
- .setReadTimeout(Duration.ofSeconds(300))
- .interceptors(Collections.singletonList(loggingInterceptor()))
- .build();
- }
-
- /**
- * 快速RestTemplate(用于内部服务调用)
- */
- @Bean("fastRestTemplate")
- public RestTemplate fastRestTemplate(RestTemplateBuilder builder) {
- return builder
- .setConnectTimeout(Duration.ofSeconds(5))
- .setReadTimeout(Duration.ofSeconds(10))
- .interceptors(Collections.singletonList(loggingInterceptor()))
- .build();
- }
-
- /**
- * 请求日志拦截器
- */
- private ClientHttpRequestInterceptor loggingInterceptor() {
- return (request, body, execution) -> {
- long startTime = System.currentTimeMillis();
-
- // 记录请求信息
- log.debug("HTTP Request: {} {}", request.getMethod(), request.getURI());
- if (body.length > 0 && body.length < 1000) {
- log.debug("Request Body: {}", new String(body));
- }
-
- ClientHttpResponse response = null;
- try {
- response = execution.execute(request, body);
-
- // 记录响应信息
- long duration = System.currentTimeMillis() - startTime;
- log.debug("HTTP Response: {} {} - {}ms",
- response.getStatusCode().value(),
- response.getStatusText(),
- duration);
-
- return response;
- } catch (IOException e) {
- long duration = System.currentTimeMillis() - startTime;
- log.error("HTTP Request failed: {} {} - {}ms, Error: {}",
- request.getMethod(),
- request.getURI(),
- duration,
- e.getMessage());
- throw e;
- }
- };
- }
-}
diff --git a/backend/common/src/main/java/com/emotionmuseum/common/config/SnowflakeConfig.java b/backend/common/src/main/java/com/emotionmuseum/common/config/SnowflakeConfig.java
deleted file mode 100644
index 06fa35d..0000000
--- a/backend/common/src/main/java/com/emotionmuseum/common/config/SnowflakeConfig.java
+++ /dev/null
@@ -1,109 +0,0 @@
-package com.emotionmuseum.common.config;
-
-import com.emotionmuseum.common.util.SnowflakeIdGenerator;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-
-import java.net.InetAddress;
-import java.net.NetworkInterface;
-import java.util.Enumeration;
-
-/**
- * 雪花算法配置类
- *
- * @author huazhongmin
- * @since 2025-07-13
- */
-@Slf4j
-@Configuration
-public class SnowflakeConfig {
-
- /**
- * 机器ID配置,可通过配置文件指定
- */
- @Value("${snowflake.machine-id:#{null}}")
- private Long configuredMachineId;
-
- /**
- * 创建雪花算法ID生成器Bean
- *
- * @return SnowflakeIdGenerator实例
- */
- @Bean
- public SnowflakeIdGenerator snowflakeIdGenerator() {
- long machineId = getMachineId();
- log.info("雪花算法配置完成,使用机器ID: {}", machineId);
- return new SnowflakeIdGenerator(machineId);
- }
-
- /**
- * 获取机器ID
- * 优先级:配置文件 > 网络接口MAC地址 > 系统时间戳
- *
- * @return 机器ID
- */
- private long getMachineId() {
- // 1. 优先使用配置文件中的机器ID
- if (configuredMachineId != null) {
- long machineId = configuredMachineId % 1024; // 确保在0-1023范围内
- log.info("使用配置文件中的机器ID: {} (原始值: {})", machineId, configuredMachineId);
- return machineId;
- }
-
- // 2. 尝试使用网络接口MAC地址生成机器ID
- try {
- long machineId = getMachineIdFromMac();
- log.info("使用MAC地址生成的机器ID: {}", machineId);
- return machineId;
- } catch (Exception e) {
- log.warn("无法从MAC地址生成机器ID: {}", e.getMessage());
- }
-
- // 3. 使用系统时间戳作为后备方案
- long machineId = System.currentTimeMillis() % 1024;
- log.info("使用系统时间戳生成的机器ID: {}", machineId);
- return machineId;
- }
-
- /**
- * 从MAC地址生成机器ID
- *
- * @return 机器ID
- * @throws Exception 获取MAC地址失败
- */
- private long getMachineIdFromMac() throws Exception {
- // 获取本机所有网络接口
- Enumeration networkInterfaces = NetworkInterface.getNetworkInterfaces();
-
- while (networkInterfaces.hasMoreElements()) {
- NetworkInterface networkInterface = networkInterfaces.nextElement();
-
- // 跳过回环接口和虚拟接口
- if (networkInterface.isLoopback() || networkInterface.isVirtual() || !networkInterface.isUp()) {
- continue;
- }
-
- byte[] mac = networkInterface.getHardwareAddress();
- if (mac != null && mac.length >= 6) {
- // 使用MAC地址的后两个字节生成机器ID
- long machineId = ((long) (mac[mac.length - 2] & 0xFF) << 8)
- | (long) (mac[mac.length - 1] & 0xFF);
- return machineId % 1024; // 确保在0-1023范围内
- }
- }
-
- // 如果没有找到合适的网络接口,使用本机IP地址
- InetAddress localHost = InetAddress.getLocalHost();
- byte[] address = localHost.getAddress();
- if (address.length >= 4) {
- // 使用IP地址的后两个字节生成机器ID
- long machineId = ((long) (address[address.length - 2] & 0xFF) << 8)
- | (long) (address[address.length - 1] & 0xFF);
- return machineId % 1024;
- }
-
- throw new RuntimeException("无法获取网络接口信息生成机器ID");
- }
-}
diff --git a/backend/common/src/main/java/com/emotionmuseum/common/config/WebMvcConfig.java b/backend/common/src/main/java/com/emotionmuseum/common/config/WebMvcConfig.java
deleted file mode 100644
index 1dfa62a..0000000
--- a/backend/common/src/main/java/com/emotionmuseum/common/config/WebMvcConfig.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package com.emotionmuseum.common.config;
-
-import com.emotionmuseum.common.interceptor.UserContextInterceptor;
-import lombok.RequiredArgsConstructor;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
-import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
-
-/**
- * Web MVC 配置类
- * 注册拦截器和其他Web相关配置
- *
- * @author huazhongmin
- * @since 2025-07-12
- */
-@Configuration
-@RequiredArgsConstructor
-public class WebMvcConfig implements WebMvcConfigurer {
-
- private final UserContextInterceptor userContextInterceptor;
-
- /**
- * 注册拦截器
- */
- @Override
- public void addInterceptors(InterceptorRegistry registry) {
- registry.addInterceptor(userContextInterceptor)
- .addPathPatterns("/**") // 拦截所有请求
- .excludePathPatterns(
- // 排除静态资源
- "/static/**",
- "/css/**",
- "/js/**",
- "/images/**",
- "/favicon.ico",
-
- // 排除Swagger相关
- "/swagger-ui/**",
- "/swagger-resources/**",
- "/v2/api-docs",
- "/v3/api-docs",
- "/doc.html",
-
- // 排除健康检查
- "/actuator/**",
- "/health",
-
- // 排除错误页面
- "/error"
- )
- .order(1); // 设置拦截器执行顺序
- }
-}
diff --git a/backend/common/src/main/java/com/emotionmuseum/common/dto/PageQuery.java b/backend/common/src/main/java/com/emotionmuseum/common/dto/PageQuery.java
deleted file mode 100644
index 70bc668..0000000
--- a/backend/common/src/main/java/com/emotionmuseum/common/dto/PageQuery.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package com.emotionmuseum.common.dto;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-
-import jakarta.validation.constraints.Max;
-import jakarta.validation.constraints.Min;
-import jakarta.validation.constraints.NotNull;
-
-/**
- * 分页查询基类
- *
- * @author huazhongmin
- * @since 2025-07-12
- */
-@Data
-@Schema(description = "分页查询参数")
-public class PageQuery {
-
- /**
- * 页码
- */
- @Schema(description = "页码", example = "1")
- @NotNull(message = "页码不能为空")
- @Min(value = 1, message = "页码最小为1")
- private Integer pageNum = 1;
-
- /**
- * 每页大小
- */
- @Schema(description = "每页大小", example = "10")
- @NotNull(message = "每页大小不能为空")
- @Min(value = 1, message = "每页大小最小为1")
- @Max(value = 100, message = "每页大小最大为100")
- private Integer pageSize = 10;
-
- /**
- * 排序字段
- */
- @Schema(description = "排序字段", example = "create_time")
- private String orderBy;
-
- /**
- * 排序方向
- */
- @Schema(description = "排序方向", example = "desc")
- private String orderDirection = "desc";
-
- /**
- * 搜索关键词
- */
- @Schema(description = "搜索关键词")
- private String keyword;
-}
diff --git a/backend/common/src/main/java/com/emotionmuseum/common/entity/BaseEntity.java b/backend/common/src/main/java/com/emotionmuseum/common/entity/BaseEntity.java
deleted file mode 100644
index 03fa2da..0000000
--- a/backend/common/src/main/java/com/emotionmuseum/common/entity/BaseEntity.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package com.emotionmuseum.common.entity;
-
-import com.baomidou.mybatisplus.annotation.*;
-import com.fasterxml.jackson.annotation.JsonFormat;
-import lombok.Data;
-
-import java.io.Serializable;
-import java.time.LocalDateTime;
-
-/**
- * 基础实体类
- * 包含所有表的公共字段:create_by, create_time, update_by, update_time, is_deleted,
- * remarks
- *
- * @author huazhongmin
- * @since 2025-07-12
- */
-@Data
-public abstract class BaseEntity implements Serializable {
-
- private static final long serialVersionUID = 1L;
-
- /**
- * 主键ID - 使用雪花算法生成的字符串ID
- * 避免前端JavaScript精度丢失问题
- */
- @TableId(value = "id", type = IdType.INPUT)
- private String id;
-
- /**
- * 创建人ID
- */
- @TableField(value = "create_by", fill = FieldFill.INSERT)
- private String createBy;
-
- /**
- * 创建时间
- */
- @TableField(value = "create_time", fill = FieldFill.INSERT)
- @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
- private LocalDateTime createTime;
-
- /**
- * 更新人ID
- */
- @TableField(value = "update_by", fill = FieldFill.INSERT_UPDATE)
- private String updateBy;
-
- /**
- * 更新时间
- */
- @TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
- @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
- private LocalDateTime updateTime;
-
- /**
- * 是否删除:0-未删除,1-已删除
- */
- @TableLogic(value = "0", delval = "1")
- @TableField(value = "is_deleted", fill = FieldFill.INSERT)
- private Integer isDeleted;
-
- /**
- * 备注
- */
- @TableField(value = "remarks")
- private String remarks;
-}
diff --git a/backend/common/src/main/java/com/emotionmuseum/common/exception/AuthException.java b/backend/common/src/main/java/com/emotionmuseum/common/exception/AuthException.java
deleted file mode 100644
index ab16a1c..0000000
--- a/backend/common/src/main/java/com/emotionmuseum/common/exception/AuthException.java
+++ /dev/null
@@ -1,62 +0,0 @@
-package com.emotionmuseum.common.exception;
-
-import com.emotionmuseum.common.result.ResultCode;
-import lombok.Getter;
-
-/**
- * 认证异常
- *
- * @author huazhongmin
- * @since 2025-07-24
- */
-@Getter
-public class AuthException extends RuntimeException {
-
- private static final long serialVersionUID = 1L;
-
- /**
- * 错误码
- */
- private final Integer code;
-
- /**
- * 错误消息
- */
- private final String message;
-
- public AuthException(String message) {
- super(message);
- this.code = ResultCode.UNAUTHORIZED.getCode();
- this.message = message;
- }
-
- public AuthException(Integer code, String message) {
- super(message);
- this.code = code;
- this.message = message;
- }
-
- public AuthException(ResultCode resultCode) {
- super(resultCode.getMessage());
- this.code = resultCode.getCode();
- this.message = resultCode.getMessage();
- }
-
- public AuthException(String message, Throwable cause) {
- super(message, cause);
- this.code = ResultCode.UNAUTHORIZED.getCode();
- this.message = message;
- }
-
- public AuthException(Integer code, String message, Throwable cause) {
- super(message, cause);
- this.code = code;
- this.message = message;
- }
-
- public AuthException(ResultCode resultCode, Throwable cause) {
- super(resultCode.getMessage(), cause);
- this.code = resultCode.getCode();
- this.message = resultCode.getMessage();
- }
-}
diff --git a/backend/common/src/main/java/com/emotionmuseum/common/exception/BusinessException.java b/backend/common/src/main/java/com/emotionmuseum/common/exception/BusinessException.java
deleted file mode 100644
index 1b18a8d..0000000
--- a/backend/common/src/main/java/com/emotionmuseum/common/exception/BusinessException.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package com.emotionmuseum.common.exception;
-
-import com.emotionmuseum.common.result.ResultCode;
-import lombok.Getter;
-
-/**
- * 业务异常
- *
- * @author huazhongmin
- * @since 2025-07-24
- */
-@Getter
-public class BusinessException extends RuntimeException {
-
- private static final long serialVersionUID = 1L;
-
- /**
- * 错误码
- */
- private final Integer code;
-
- /**
- * 错误消息
- */
- private final String message;
-
- public BusinessException(String message) {
- super(message);
- this.code = ResultCode.BUSINESS_ERROR.getCode();
- this.message = message;
- }
-
- public BusinessException(Integer code, String message) {
- super(message);
- this.code = code;
- this.message = message;
- }
-
- public BusinessException(ResultCode resultCode) {
- super(resultCode.getMessage());
- this.code = resultCode.getCode();
- this.message = resultCode.getMessage();
- }
-
- public BusinessException(ResultCode resultCode, String message) {
- super(message);
- this.code = resultCode.getCode();
- this.message = message;
- }
-
- public BusinessException(String message, Throwable cause) {
- super(message, cause);
- this.code = ResultCode.BUSINESS_ERROR.getCode();
- this.message = message;
- }
-
- public BusinessException(Integer code, String message, Throwable cause) {
- super(message, cause);
- this.code = code;
- this.message = message;
- }
-
- public BusinessException(ResultCode resultCode, Throwable cause) {
- super(resultCode.getMessage(), cause);
- this.code = resultCode.getCode();
- this.message = resultCode.getMessage();
- }
-}
diff --git a/backend/common/src/main/java/com/emotionmuseum/common/exception/CaptchaException.java b/backend/common/src/main/java/com/emotionmuseum/common/exception/CaptchaException.java
deleted file mode 100644
index 30770ae..0000000
--- a/backend/common/src/main/java/com/emotionmuseum/common/exception/CaptchaException.java
+++ /dev/null
@@ -1,62 +0,0 @@
-package com.emotionmuseum.common.exception;
-
-import com.emotionmuseum.common.result.ResultCode;
-import lombok.Getter;
-
-/**
- * 验证码异常
- *
- * @author huazhongmin
- * @since 2025-07-24
- */
-@Getter
-public class CaptchaException extends RuntimeException {
-
- private static final long serialVersionUID = 1L;
-
- /**
- * 错误码
- */
- private final Integer code;
-
- /**
- * 错误消息
- */
- private final String message;
-
- public CaptchaException(String message) {
- super(message);
- this.code = ResultCode.CAPTCHA_ERROR.getCode();
- this.message = message;
- }
-
- public CaptchaException(Integer code, String message) {
- super(message);
- this.code = code;
- this.message = message;
- }
-
- public CaptchaException(ResultCode resultCode) {
- super(resultCode.getMessage());
- this.code = resultCode.getCode();
- this.message = resultCode.getMessage();
- }
-
- public CaptchaException(String message, Throwable cause) {
- super(message, cause);
- this.code = ResultCode.CAPTCHA_ERROR.getCode();
- this.message = message;
- }
-
- public CaptchaException(Integer code, String message, Throwable cause) {
- super(message, cause);
- this.code = code;
- this.message = message;
- }
-
- public CaptchaException(ResultCode resultCode, Throwable cause) {
- super(resultCode.getMessage(), cause);
- this.code = resultCode.getCode();
- this.message = resultCode.getMessage();
- }
-}
diff --git a/backend/common/src/main/java/com/emotionmuseum/common/exception/GlobalExceptionHandler.java b/backend/common/src/main/java/com/emotionmuseum/common/exception/GlobalExceptionHandler.java
deleted file mode 100644
index 69ba2ed..0000000
--- a/backend/common/src/main/java/com/emotionmuseum/common/exception/GlobalExceptionHandler.java
+++ /dev/null
@@ -1,153 +0,0 @@
-package com.emotionmuseum.common.exception;
-
-import com.emotionmuseum.common.result.Result;
-import com.emotionmuseum.common.result.ResultCode;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.http.HttpStatus;
-import org.springframework.validation.BindException;
-import org.springframework.validation.FieldError;
-import org.springframework.web.bind.MethodArgumentNotValidException;
-import org.springframework.web.bind.annotation.ExceptionHandler;
-import org.springframework.web.bind.annotation.ResponseStatus;
-import org.springframework.web.bind.annotation.RestControllerAdvice;
-
-import jakarta.servlet.http.HttpServletRequest;
-import jakarta.validation.ConstraintViolation;
-import jakarta.validation.ConstraintViolationException;
-import java.util.Set;
-
-/**
- * 全局异常处理器
- *
- * @author huazhongmin
- * @since 2025-07-24
- */
-@Slf4j
-@RestControllerAdvice
-public class GlobalExceptionHandler {
-
- /**
- * 处理认证异常
- */
- @ExceptionHandler(AuthException.class)
- public Result handleAuthException(AuthException e, HttpServletRequest request) {
- log.warn("认证异常: {} {} - {}", request.getMethod(), request.getRequestURI(), e.getMessage());
- return Result.error(e.getCode(), e.getMessage());
- }
-
- /**
- * 处理令牌异常
- */
- @ExceptionHandler(TokenException.class)
- public Result handleTokenException(TokenException e, HttpServletRequest request) {
- log.warn("令牌异常: {} {} - {}", request.getMethod(), request.getRequestURI(), e.getMessage());
- return Result.error(e.getCode(), e.getMessage());
- }
-
- /**
- * 处理验证码异常
- */
- @ExceptionHandler(CaptchaException.class)
- public Result handleCaptchaException(CaptchaException e, HttpServletRequest request) {
- log.warn("验证码异常: {} {} - {}", request.getMethod(), request.getRequestURI(), e.getMessage());
- return Result.error(e.getCode(), e.getMessage());
- }
-
- /**
- * 处理业务异常
- */
- @ExceptionHandler(BusinessException.class)
- public Result handleBusinessException(BusinessException e, HttpServletRequest request) {
- log.warn("业务异常: {} {} - {}", request.getMethod(), request.getRequestURI(), e.getMessage());
- return Result.error(e.getCode(), e.getMessage());
- }
-
- /**
- * 处理参数校验异常
- */
- @ExceptionHandler(MethodArgumentNotValidException.class)
- @ResponseStatus(HttpStatus.BAD_REQUEST)
- public Result handleMethodArgumentNotValidException(MethodArgumentNotValidException e, HttpServletRequest request) {
- log.warn("参数校验失败: {} {}", request.getMethod(), request.getRequestURI(), e);
-
- StringBuilder message = new StringBuilder("参数校验失败: ");
- for (FieldError error : e.getBindingResult().getFieldErrors()) {
- message.append(error.getField()).append(" ").append(error.getDefaultMessage()).append("; ");
- }
-
- return Result.error(ResultCode.PARAM_VALIDATION_ERROR.getCode(), message.toString());
- }
-
- /**
- * 处理Bean校验异常
- */
- @ExceptionHandler(BindException.class)
- @ResponseStatus(HttpStatus.BAD_REQUEST)
- public Result handleBindException(BindException e, HttpServletRequest request) {
- log.warn("参数绑定失败: {} {}", request.getMethod(), request.getRequestURI(), e);
-
- StringBuilder message = new StringBuilder("参数绑定失败: ");
- for (FieldError error : e.getBindingResult().getFieldErrors()) {
- message.append(error.getField()).append(" ").append(error.getDefaultMessage()).append("; ");
- }
-
- return Result.error(ResultCode.PARAM_VALIDATION_ERROR.getCode(), message.toString());
- }
-
- /**
- * 处理约束校验异常
- */
- @ExceptionHandler(ConstraintViolationException.class)
- @ResponseStatus(HttpStatus.BAD_REQUEST)
- public Result handleConstraintViolationException(ConstraintViolationException e, HttpServletRequest request) {
- log.warn("约束校验失败: {} {}", request.getMethod(), request.getRequestURI(), e);
-
- StringBuilder message = new StringBuilder("约束校验失败: ");
- Set> violations = e.getConstraintViolations();
- for (ConstraintViolation> violation : violations) {
- message.append(violation.getPropertyPath()).append(" ").append(violation.getMessage()).append("; ");
- }
-
- return Result.error(ResultCode.PARAM_VALIDATION_ERROR.getCode(), message.toString());
- }
-
- /**
- * 处理非法参数异常
- */
- @ExceptionHandler(IllegalArgumentException.class)
- @ResponseStatus(HttpStatus.BAD_REQUEST)
- public Result handleIllegalArgumentException(IllegalArgumentException e, HttpServletRequest request) {
- log.warn("非法参数: {} {}", request.getMethod(), request.getRequestURI(), e);
- return Result.error(ResultCode.BAD_REQUEST.getCode(), "参数错误: " + e.getMessage());
- }
-
- /**
- * 处理空指针异常
- */
- @ExceptionHandler(NullPointerException.class)
- @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
- public Result handleNullPointerException(NullPointerException e, HttpServletRequest request) {
- log.error("空指针异常: {} {}", request.getMethod(), request.getRequestURI(), e);
- return Result.error(ResultCode.INTERNAL_SERVER_ERROR.getCode(), "系统内部错误");
- }
-
- /**
- * 处理运行时异常
- */
- @ExceptionHandler(RuntimeException.class)
- @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
- public Result handleRuntimeException(RuntimeException e, HttpServletRequest request) {
- log.error("运行时异常: {} {}", request.getMethod(), request.getRequestURI(), e);
- return Result.error(ResultCode.INTERNAL_SERVER_ERROR.getCode(), "系统运行异常: " + e.getMessage());
- }
-
- /**
- * 处理所有其他异常
- */
- @ExceptionHandler(Exception.class)
- @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
- public Result handleException(Exception e, HttpServletRequest request) {
- log.error("未知异常: {} {}", request.getMethod(), request.getRequestURI(), e);
- return Result.error(ResultCode.INTERNAL_SERVER_ERROR.getCode(), "系统异常,请联系管理员");
- }
-}
diff --git a/backend/common/src/main/java/com/emotionmuseum/common/exception/TokenException.java b/backend/common/src/main/java/com/emotionmuseum/common/exception/TokenException.java
deleted file mode 100644
index 3602016..0000000
--- a/backend/common/src/main/java/com/emotionmuseum/common/exception/TokenException.java
+++ /dev/null
@@ -1,62 +0,0 @@
-package com.emotionmuseum.common.exception;
-
-import com.emotionmuseum.common.result.ResultCode;
-import lombok.Getter;
-
-/**
- * Token异常
- *
- * @author huazhongmin
- * @since 2025-07-24
- */
-@Getter
-public class TokenException extends RuntimeException {
-
- private static final long serialVersionUID = 1L;
-
- /**
- * 错误码
- */
- private final Integer code;
-
- /**
- * 错误消息
- */
- private final String message;
-
- public TokenException(String message) {
- super(message);
- this.code = ResultCode.TOKEN_INVALID.getCode();
- this.message = message;
- }
-
- public TokenException(Integer code, String message) {
- super(message);
- this.code = code;
- this.message = message;
- }
-
- public TokenException(ResultCode resultCode) {
- super(resultCode.getMessage());
- this.code = resultCode.getCode();
- this.message = resultCode.getMessage();
- }
-
- public TokenException(String message, Throwable cause) {
- super(message, cause);
- this.code = ResultCode.TOKEN_INVALID.getCode();
- this.message = message;
- }
-
- public TokenException(Integer code, String message, Throwable cause) {
- super(message, cause);
- this.code = code;
- this.message = message;
- }
-
- public TokenException(ResultCode resultCode, Throwable cause) {
- super(resultCode.getMessage(), cause);
- this.code = resultCode.getCode();
- this.message = resultCode.getMessage();
- }
-}
diff --git a/backend/common/src/main/java/com/emotionmuseum/common/handler/EmotionMetaObjectHandler.java b/backend/common/src/main/java/com/emotionmuseum/common/handler/EmotionMetaObjectHandler.java
deleted file mode 100644
index 41be9d9..0000000
--- a/backend/common/src/main/java/com/emotionmuseum/common/handler/EmotionMetaObjectHandler.java
+++ /dev/null
@@ -1,226 +0,0 @@
-package com.emotionmuseum.common.handler;
-
-import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
-import com.emotionmuseum.common.util.SnowflakeIdGenerator;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.ibatis.reflection.MetaObject;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Component;
-
-import java.time.LocalDateTime;
-
-/**
- * MyBatis-Plus 自动填充处理器
- * 自动填充公共字段:id, create_by, create_time, update_by, update_time
- * 支持雪花算法自动生成主键ID
- *
- * @author huazhongmin
- * @since 2025-07-12
- */
-@Slf4j
-@Component
-public class EmotionMetaObjectHandler implements MetaObjectHandler {
-
- /**
- * 雪花算法ID生成器
- */
- @Autowired
- private SnowflakeIdGenerator snowflakeIdGenerator;
-
- /**
- * 插入时自动填充
- */
- @Override
- public void insertFill(MetaObject metaObject) {
- try {
- LocalDateTime now = LocalDateTime.now();
- String currentUserId = getCurrentUserId();
-
- // 填充主键ID(如果为空)
- fillPrimaryKey(metaObject);
-
- // 填充创建时间
- this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, now);
-
- // 填充更新时间
- this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, now);
-
- // 填充创建人ID
- if (currentUserId != null) {
- this.strictInsertFill(metaObject, "createBy", String.class, currentUserId);
- }
-
- // 填充更新人ID
- if (currentUserId != null) {
- this.strictInsertFill(metaObject, "updateBy", String.class, currentUserId);
- }
-
- // 填充逻辑删除字段默认值
- this.strictInsertFill(metaObject, "isDeleted", Integer.class, 0);
-
- log.debug("插入时自动填充完成: createTime={}, updateTime={}, createBy={}, updateBy={}",
- now, now, currentUserId, currentUserId);
-
- } catch (Exception e) {
- // 自动填充失败不应该影响业务逻辑
- log.warn("插入时自动填充失败,但不影响业务逻辑: {}", e.getMessage());
- }
- }
-
- /**
- * 更新时自动填充
- */
- @Override
- public void updateFill(MetaObject metaObject) {
- try {
- LocalDateTime now = LocalDateTime.now();
- String currentUserId = getCurrentUserId();
-
- // 填充更新时间
- this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, now);
-
- // 填充更新人ID
- if (currentUserId != null) {
- this.strictUpdateFill(metaObject, "updateBy", String.class, currentUserId);
- }
-
- log.debug("更新时自动填充完成: updateTime={}, updateBy={}", now, currentUserId);
-
- } catch (Exception e) {
- // 自动填充失败不应该影响业务逻辑
- log.warn("更新时自动填充失败,但不影响业务逻辑: {}", e.getMessage());
- }
- }
-
- /**
- * 填充主键ID
- * 如果主键ID为空,则使用雪花算法生成
- *
- * @param metaObject 元对象
- */
- private void fillPrimaryKey(MetaObject metaObject) {
- try {
- // 检查是否有id字段
- if (metaObject.hasSetter("id")) {
- Object idValue = metaObject.getValue("id");
- // 如果ID为空,则生成新的ID
- if (idValue == null || (idValue instanceof String && ((String) idValue).isEmpty())) {
- String newId = snowflakeIdGenerator.nextIdAsString();
- this.strictInsertFill(metaObject, "id", String.class, newId);
- log.debug("自动生成主键ID: {}", newId);
- }
- }
- } catch (Exception e) {
- log.warn("主键ID自动填充失败,但不影响业务逻辑: {}", e.getMessage());
- }
- }
-
- /**
- * 获取当前用户ID
- * 优先级:
- * 1. 从ThreadLocal获取(如果有用户上下文)
- * 2. 从Spring Security获取(如果有认证信息)
- * 3. 返回系统默认值
- *
- * @return 当前用户ID,如果获取失败返回null
- */
- private String getCurrentUserId() {
- try {
- // 1. 尝试从ThreadLocal获取用户ID(如果有用户上下文工具类)
- String userIdFromContext = getUserIdFromContext();
- if (userIdFromContext != null) {
- return userIdFromContext;
- }
-
- // 2. 尝试从Spring Security获取用户ID
- String userIdFromSecurity = getUserIdFromSecurity();
- if (userIdFromSecurity != null) {
- return userIdFromSecurity;
- }
-
- // 3. 返回系统默认值(用于系统操作或未登录用户)
- return "system";
-
- } catch (Exception e) {
- log.debug("获取当前用户ID失败: {}", e.getMessage());
- return "system";
- }
- }
-
- /**
- * 从用户上下文获取用户ID
- * 这里可以集成自定义的用户上下文工具类
- *
- * @return 用户ID或null
- */
- private String getUserIdFromContext() {
- try {
- // TODO: 集成用户上下文工具类
- // 例如:return UserContextHolder.getCurrentUserId();
-
- // 临时实现:从线程变量获取
- return UserContextHolder.getCurrentUserId();
-
- } catch (Exception e) {
- log.debug("从用户上下文获取用户ID失败: {}", e.getMessage());
- return null;
- }
- }
-
- /**
- * 从Spring Security获取用户ID
- *
- * @return 用户ID或null
- */
- private String getUserIdFromSecurity() {
- try {
- // TODO: 集成Spring Security
- // Authentication authentication =
- // SecurityContextHolder.getContext().getAuthentication();
- // if (authentication != null && authentication.isAuthenticated()
- // && !"anonymousUser".equals(authentication.getPrincipal())) {
- // UserDetails userDetails = (UserDetails) authentication.getPrincipal();
- // return userDetails.getUsername(); // 或者从UserDetails中获取用户ID
- // }
- return null;
-
- } catch (Exception e) {
- log.debug("从Spring Security获取用户ID失败: {}", e.getMessage());
- return null;
- }
- }
-
- /**
- * 用户上下文持有者
- * 用于在当前线程中存储用户信息
- */
- public static class UserContextHolder {
-
- private static final ThreadLocal USER_ID_HOLDER = new ThreadLocal<>();
-
- /**
- * 设置当前用户ID
- *
- * @param userId 用户ID
- */
- public static void setCurrentUserId(String userId) {
- USER_ID_HOLDER.set(userId);
- }
-
- /**
- * 获取当前用户ID
- *
- * @return 用户ID
- */
- public static String getCurrentUserId() {
- return USER_ID_HOLDER.get();
- }
-
- /**
- * 清除当前用户ID
- */
- public static void clear() {
- USER_ID_HOLDER.remove();
- }
- }
-}
diff --git a/backend/common/src/main/java/com/emotionmuseum/common/interceptor/UserContextInterceptor.java b/backend/common/src/main/java/com/emotionmuseum/common/interceptor/UserContextInterceptor.java
deleted file mode 100644
index e4d810a..0000000
--- a/backend/common/src/main/java/com/emotionmuseum/common/interceptor/UserContextInterceptor.java
+++ /dev/null
@@ -1,209 +0,0 @@
-package com.emotionmuseum.common.interceptor;
-
-import com.emotionmuseum.common.handler.EmotionMetaObjectHandler;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Component;
-import org.springframework.util.StringUtils;
-import org.springframework.web.servlet.HandlerInterceptor;
-
-import jakarta.servlet.http.HttpServletRequest;
-import jakarta.servlet.http.HttpServletResponse;
-
-/**
- * 用户上下文拦截器
- * 自动从请求头中提取用户信息并设置到ThreadLocal中
- *
- * @author huazhongmin
- * @since 2025-07-12
- */
-@Slf4j
-@Component
-public class UserContextInterceptor implements HandlerInterceptor {
-
- /**
- * 用户ID请求头名称
- */
- private static final String USER_ID_HEADER = "X-User-Id";
-
- /**
- * 用户名请求头名称
- */
- private static final String USERNAME_HEADER = "X-Username";
-
- /**
- * Authorization请求头名称
- */
- private static final String AUTHORIZATION_HEADER = "Authorization";
-
- @Override
- public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
- throws Exception {
- try {
- // 1. 优先从自定义请求头获取用户ID
- String userId = request.getHeader(USER_ID_HEADER);
-
- // 2. 如果没有自定义请求头,尝试从其他方式获取
- if (!StringUtils.hasText(userId)) {
- userId = extractUserIdFromRequest(request);
- }
-
- // 3. 如果仍然没有用户ID,使用默认值
- if (!StringUtils.hasText(userId)) {
- userId = generateGuestUserId(request);
- }
-
- // 4. 设置到ThreadLocal中
- EmotionMetaObjectHandler.UserContextHolder.setCurrentUserId(userId);
-
- log.debug("设置用户上下文: userId={}, requestUri={}", userId, request.getRequestURI());
-
- } catch (Exception e) {
- // 设置用户上下文失败不应该影响请求处理
- log.warn("设置用户上下文失败,使用默认值: {}", e.getMessage());
- EmotionMetaObjectHandler.UserContextHolder.setCurrentUserId("system");
- }
-
- return true;
- }
-
- @Override
- public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
- throws Exception {
- try {
- // 清除ThreadLocal,避免内存泄漏
- EmotionMetaObjectHandler.UserContextHolder.clear();
- log.debug("清除用户上下文: requestUri={}", request.getRequestURI());
- } catch (Exception e) {
- log.warn("清除用户上下文失败: {}", e.getMessage());
- }
- }
-
- /**
- * 从请求中提取用户ID
- *
- * @param request HTTP请求
- * @return 用户ID或null
- */
- private String extractUserIdFromRequest(HttpServletRequest request) {
- try {
- // 1. 从Authorization头解析JWT token(如果有)
- String authHeader = request.getHeader(AUTHORIZATION_HEADER);
- if (StringUtils.hasText(authHeader) && authHeader.startsWith("Bearer ")) {
- String token = authHeader.substring(7);
- String userIdFromToken = extractUserIdFromToken(token);
- if (StringUtils.hasText(userIdFromToken)) {
- return userIdFromToken;
- }
- }
-
- // 2. 从用户名请求头获取
- String username = request.getHeader(USERNAME_HEADER);
- if (StringUtils.hasText(username)) {
- return username;
- }
-
- // 3. 从请求参数获取
- String userIdParam = request.getParameter("userId");
- if (StringUtils.hasText(userIdParam)) {
- return userIdParam;
- }
-
- return null;
-
- } catch (Exception e) {
- log.debug("从请求中提取用户ID失败: {}", e.getMessage());
- return null;
- }
- }
-
- /**
- * 从JWT token中提取用户ID
- *
- * @param token JWT token
- * @return 用户ID或null
- */
- private String extractUserIdFromToken(String token) {
- try {
- // TODO: 实现JWT token解析逻辑
- // 这里可以集成JWT工具类来解析token
- // 例如:
- // Claims claims = JwtUtils.parseToken(token);
- // return claims.getSubject();
-
- log.debug("JWT token解析功能待实现");
- return null;
-
- } catch (Exception e) {
- log.debug("解析JWT token失败: {}", e.getMessage());
- return null;
- }
- }
-
- /**
- * 为访客用户生成临时用户ID
- *
- * @param request HTTP请求
- * @return 临时用户ID
- */
- private String generateGuestUserId(HttpServletRequest request) {
- try {
- // 1. 尝试从Session获取
- String sessionId = request.getSession(false) != null ? request.getSession().getId() : null;
- if (StringUtils.hasText(sessionId)) {
- return "guest_session_" + sessionId;
- }
-
- // 2. 基于IP和User-Agent生成
- String clientIp = getClientIpAddress(request);
- String userAgent = request.getHeader("User-Agent");
-
- if (StringUtils.hasText(clientIp)) {
- String hash = String.valueOf((clientIp + userAgent).hashCode());
- return "guest_" + Math.abs(Integer.parseInt(hash));
- }
-
- // 3. 使用时间戳作为最后的备选方案
- return "guest_" + System.currentTimeMillis();
-
- } catch (Exception e) {
- log.debug("生成访客用户ID失败: {}", e.getMessage());
- return "guest_" + System.currentTimeMillis();
- }
- }
-
- /**
- * 获取客户端真实IP地址
- *
- * @param request HTTP请求
- * @return 客户端IP地址
- */
- private String getClientIpAddress(HttpServletRequest request) {
- try {
- String xForwardedFor = request.getHeader("X-Forwarded-For");
- if (StringUtils.hasText(xForwardedFor) && !"unknown".equalsIgnoreCase(xForwardedFor)) {
- return xForwardedFor.split(",")[0].trim();
- }
-
- String xRealIp = request.getHeader("X-Real-IP");
- if (StringUtils.hasText(xRealIp) && !"unknown".equalsIgnoreCase(xRealIp)) {
- return xRealIp;
- }
-
- String proxyClientIp = request.getHeader("Proxy-Client-IP");
- if (StringUtils.hasText(proxyClientIp) && !"unknown".equalsIgnoreCase(proxyClientIp)) {
- return proxyClientIp;
- }
-
- String wlProxyClientIp = request.getHeader("WL-Proxy-Client-IP");
- if (StringUtils.hasText(wlProxyClientIp) && !"unknown".equalsIgnoreCase(wlProxyClientIp)) {
- return wlProxyClientIp;
- }
-
- return request.getRemoteAddr();
-
- } catch (Exception e) {
- log.debug("获取客户端IP地址失败: {}", e.getMessage());
- return "unknown";
- }
- }
-}
diff --git a/backend/common/src/main/java/com/emotionmuseum/common/request/BasePageRequest.java b/backend/common/src/main/java/com/emotionmuseum/common/request/BasePageRequest.java
deleted file mode 100644
index f9f8392..0000000
--- a/backend/common/src/main/java/com/emotionmuseum/common/request/BasePageRequest.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package com.emotionmuseum.common.request;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-
-import jakarta.validation.constraints.Max;
-import jakarta.validation.constraints.Min;
-
-/**
- * 基础分页请求类
- *
- * @author huazhongmin
- * @since 2025-07-24
- */
-@Data
-@EqualsAndHashCode(callSuper = true)
-@Schema(description = "基础分页请求")
-public abstract class BasePageRequest extends BaseRequest {
-
- private static final long serialVersionUID = 1L;
-
- /**
- * 页码,从1开始
- */
- @Schema(description = "页码,从1开始", example = "1", minimum = "1")
- @Min(value = 1, message = "页码必须大于0")
- private Integer pageNum = 1;
-
- /**
- * 每页大小
- */
- @Schema(description = "每页大小", example = "20", minimum = "1", maximum = "100")
- @Min(value = 1, message = "每页大小必须大于0")
- @Max(value = 100, message = "每页大小不能超过100")
- private Integer pageSize = 20;
-
- /**
- * 排序字段
- */
- @Schema(description = "排序字段", example = "create_time")
- private String sortField;
-
- /**
- * 排序方向
- */
- @Schema(description = "排序方向", example = "DESC", allowableValues = {"ASC", "DESC"})
- private String sortOrder = "DESC";
-
- /**
- * 搜索关键词
- */
- @Schema(description = "搜索关键词", example = "关键词")
- private String keyword;
-}
diff --git a/backend/common/src/main/java/com/emotionmuseum/common/request/BaseRequest.java b/backend/common/src/main/java/com/emotionmuseum/common/request/BaseRequest.java
deleted file mode 100644
index 51a80f7..0000000
--- a/backend/common/src/main/java/com/emotionmuseum/common/request/BaseRequest.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package com.emotionmuseum.common.request;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-
-import jakarta.validation.constraints.NotBlank;
-import java.io.Serializable;
-
-/**
- * 基础请求类
- *
- * @author huazhongmin
- * @since 2025-07-24
- */
-@Data
-@Schema(description = "基础请求")
-public abstract class BaseRequest implements Serializable {
-
- private static final long serialVersionUID = 1L;
-
- /**
- * 请求ID,用于链路追踪
- */
- @Schema(description = "请求ID", example = "req_123456789")
- private String requestId;
-
- /**
- * 客户端IP地址
- */
- @Schema(description = "客户端IP地址", example = "192.168.1.100")
- private String clientIp;
-
- /**
- * 用户代理信息
- */
- @Schema(description = "用户代理信息", example = "Mozilla/5.0...")
- private String userAgent;
-
- /**
- * 请求时间戳
- */
- @Schema(description = "请求时间戳", example = "1721808000000")
- private Long timestamp;
-
- /**
- * 设备类型
- */
- @Schema(description = "设备类型", example = "WEB", allowableValues = {"WEB", "MOBILE", "APP"})
- private String deviceType;
-
- /**
- * 应用版本
- */
- @Schema(description = "应用版本", example = "1.0.0")
- private String appVersion;
-
- public BaseRequest() {
- this.timestamp = System.currentTimeMillis();
- }
-}
diff --git a/backend/common/src/main/java/com/emotionmuseum/common/response/BasePageResponse.java b/backend/common/src/main/java/com/emotionmuseum/common/response/BasePageResponse.java
deleted file mode 100644
index 3081d82..0000000
--- a/backend/common/src/main/java/com/emotionmuseum/common/response/BasePageResponse.java
+++ /dev/null
@@ -1,101 +0,0 @@
-package com.emotionmuseum.common.response;
-
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-
-import java.util.List;
-
-/**
- * 基础分页响应类
- *
- * @author huazhongmin
- * @since 2025-07-24
- */
-@Data
-@EqualsAndHashCode(callSuper = true)
-@Schema(description = "基础分页响应")
-public class BasePageResponse extends BaseResponse {
-
- private static final long serialVersionUID = 1L;
-
- /**
- * 当前页码
- */
- @Schema(description = "当前页码", example = "1")
- private Long current;
-
- /**
- * 每页大小
- */
- @Schema(description = "每页大小", example = "20")
- private Long size;
-
- /**
- * 总记录数
- */
- @Schema(description = "总记录数", example = "100")
- private Long total;
-
- /**
- * 总页数
- */
- @Schema(description = "总页数", example = "5")
- private Long pages;
-
- /**
- * 数据列表
- */
- @Schema(description = "数据列表")
- private List records;
-
- /**
- * 是否有下一页
- */
- @Schema(description = "是否有下一页", example = "true")
- private Boolean hasNext;
-
- /**
- * 是否有上一页
- */
- @Schema(description = "是否有上一页", example = "false")
- private Boolean hasPrevious;
-
- public BasePageResponse() {
- super();
- }
-
- public BasePageResponse(IPage page) {
- super();
- this.current = page.getCurrent();
- this.size = page.getSize();
- this.total = page.getTotal();
- this.pages = page.getPages();
- this.records = page.getRecords();
- this.hasNext = this.current != null && this.pages != null && this.current < this.pages;
- this.hasPrevious = this.current != null && this.current > 1;
- }
-
- /**
- * 静态工厂方法
- */
- public static BasePageResponse of(IPage page) {
- return new BasePageResponse<>(page);
- }
-
- /**
- * 静态工厂方法
- */
- public static BasePageResponse of(List records, Long current, Long size, Long total) {
- BasePageResponse response = new BasePageResponse<>();
- response.setRecords(records);
- response.setCurrent(current);
- response.setSize(size);
- response.setTotal(total);
- response.setPages((total + size - 1) / size);
- response.setHasNext(current < response.getPages());
- response.setHasPrevious(current > 1);
- return response;
- }
-}
diff --git a/backend/common/src/main/java/com/emotionmuseum/common/response/BaseResponse.java b/backend/common/src/main/java/com/emotionmuseum/common/response/BaseResponse.java
deleted file mode 100644
index 002d14c..0000000
--- a/backend/common/src/main/java/com/emotionmuseum/common/response/BaseResponse.java
+++ /dev/null
@@ -1,73 +0,0 @@
-package com.emotionmuseum.common.response;
-
-import com.fasterxml.jackson.annotation.JsonInclude;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-
-import java.io.Serializable;
-
-/**
- * 基础响应类
- *
- * @author huazhongmin
- * @since 2025-07-24
- */
-@Data
-@JsonInclude(JsonInclude.Include.NON_NULL)
-@Schema(description = "基础响应")
-public abstract class BaseResponse implements Serializable {
-
- private static final long serialVersionUID = 1L;
-
- /**
- * 响应时间戳
- */
- @Schema(description = "响应时间戳", example = "1721808000000")
- private Long timestamp;
-
- /**
- * 请求ID,用于链路追踪
- */
- @Schema(description = "请求ID", example = "req_123456789")
- private String requestId;
-
- /**
- * 服务器处理时间(毫秒)
- */
- @Schema(description = "服务器处理时间(毫秒)", example = "150")
- private Long processingTime;
-
- /**
- * 服务节点标识
- */
- @Schema(description = "服务节点标识", example = "node-001")
- private String serverNode;
-
- public BaseResponse() {
- this.timestamp = System.currentTimeMillis();
- }
-
- /**
- * 设置请求ID
- */
- public BaseResponse requestId(String requestId) {
- this.requestId = requestId;
- return this;
- }
-
- /**
- * 设置处理时间
- */
- public BaseResponse processingTime(Long processingTime) {
- this.processingTime = processingTime;
- return this;
- }
-
- /**
- * 设置服务节点
- */
- public BaseResponse serverNode(String serverNode) {
- this.serverNode = serverNode;
- return this;
- }
-}
diff --git a/backend/common/src/main/java/com/emotionmuseum/common/result/Result.java b/backend/common/src/main/java/com/emotionmuseum/common/result/Result.java
deleted file mode 100644
index 38d78e5..0000000
--- a/backend/common/src/main/java/com/emotionmuseum/common/result/Result.java
+++ /dev/null
@@ -1,186 +0,0 @@
-package com.emotionmuseum.common.result;
-
-import com.fasterxml.jackson.annotation.JsonInclude;
-import lombok.Data;
-
-import java.io.Serializable;
-
-/**
- * 统一响应结果
- *
- * @author huazhongmin
- * @since 2025-07-12
- */
-@Data
-@JsonInclude(JsonInclude.Include.NON_NULL)
-public class Result implements Serializable {
-
- private static final long serialVersionUID = 1L;
-
- /**
- * 响应码
- */
- private Integer code;
-
- /**
- * 响应消息
- */
- private String message;
-
- /**
- * 响应数据
- */
- private T data;
-
- /**
- * 时间戳
- */
- private Long timestamp;
-
- /**
- * 请求ID
- */
- private String requestId;
-
- public Result() {
- this.timestamp = System.currentTimeMillis();
- }
-
- public Result(Integer code, String message) {
- this();
- this.code = code;
- this.message = message;
- }
-
- public Result(Integer code, String message, T data) {
- this(code, message);
- this.data = data;
- }
-
- /**
- * 成功响应
- */
- public static Result success() {
- return new Result<>(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMessage());
- }
-
- /**
- * 成功响应(带数据)
- */
- public static Result success(T data) {
- return new Result<>(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMessage(), data);
- }
-
- /**
- * 成功响应(自定义消息)
- */
- public static Result success(String message, T data) {
- return new Result<>(ResultCode.SUCCESS.getCode(), message, data);
- }
-
- /**
- * 失败响应
- */
- public static Result error() {
- return new Result<>(ResultCode.INTERNAL_SERVER_ERROR.getCode(), ResultCode.INTERNAL_SERVER_ERROR.getMessage());
- }
-
- /**
- * 失败响应(自定义消息)
- */
- public static Result error(String message) {
- return new Result<>(ResultCode.INTERNAL_SERVER_ERROR.getCode(), message);
- }
-
- /**
- * 失败响应(自定义码和消息)
- */
- public static Result error(Integer code, String message) {
- return new Result<>(code, message);
- }
-
- /**
- * 失败响应(结果码枚举)
- */
- public static Result error(ResultCode resultCode) {
- return new Result<>(resultCode.getCode(), resultCode.getMessage());
- }
-
- /**
- * 失败响应(结果码枚举 + 数据)
- */
- public static Result error(ResultCode resultCode, T data) {
- return new Result<>(resultCode.getCode(), resultCode.getMessage(), data);
- }
-
- /**
- * 判断是否成功
- */
- public boolean isSuccess() {
- return ResultCode.SUCCESS.getCode().equals(this.code);
- }
-
- /**
- * 设置请求ID
- */
- public Result requestId(String requestId) {
- this.requestId = requestId;
- return this;
- }
-
- /**
- * 未授权响应
- */
- public static Result unauthorized() {
- return new Result<>(ResultCode.UNAUTHORIZED.getCode(), ResultCode.UNAUTHORIZED.getMessage());
- }
-
- /**
- * 未授权响应(自定义消息)
- */
- public static Result unauthorized(String message) {
- return new Result<>(ResultCode.UNAUTHORIZED.getCode(), message);
- }
-
- /**
- * 禁止访问响应
- */
- public static Result forbidden() {
- return new Result<>(ResultCode.FORBIDDEN.getCode(), ResultCode.FORBIDDEN.getMessage());
- }
-
- /**
- * 禁止访问响应(自定义消息)
- */
- public static Result forbidden(String message) {
- return new Result<>(ResultCode.FORBIDDEN.getCode(), message);
- }
-
- /**
- * 请求参数错误响应
- */
- public static Result badRequest() {
- return new Result<>(ResultCode.BAD_REQUEST.getCode(), ResultCode.BAD_REQUEST.getMessage());
- }
-
- /**
- * 请求参数错误响应(自定义消息)
- */
- public static Result badRequest(String message) {
- return new Result<>(ResultCode.BAD_REQUEST.getCode(), message);
- }
-
- /**
- * 资源不存在响应
- */
- public static Result notFound() {
- return new Result<>(ResultCode.NOT_FOUND.getCode(), ResultCode.NOT_FOUND.getMessage());
- }
-
- /**
- * 资源不存在响应(自定义消息)
- */
- public static Result notFound(String message) {
- return new Result<>(ResultCode.NOT_FOUND.getCode(), message);
- }
-}
diff --git a/backend/common/src/main/java/com/emotionmuseum/common/result/ResultCode.java b/backend/common/src/main/java/com/emotionmuseum/common/result/ResultCode.java
deleted file mode 100644
index d4c690e..0000000
--- a/backend/common/src/main/java/com/emotionmuseum/common/result/ResultCode.java
+++ /dev/null
@@ -1,123 +0,0 @@
-package com.emotionmuseum.common.result;
-
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-
-/**
- * 响应状态码枚举
- *
- * @author huazhongmin
- * @since 2025-07-12
- */
-@Getter
-@AllArgsConstructor
-public enum ResultCode {
-
- // ========== 通用状态码 ==========
- SUCCESS(200, "操作成功"),
- BAD_REQUEST(400, "请求参数错误"),
- UNAUTHORIZED(401, "未授权"),
- FORBIDDEN(403, "禁止访问"),
- NOT_FOUND(404, "资源不存在"),
- METHOD_NOT_ALLOWED(405, "请求方法不允许"),
- INTERNAL_SERVER_ERROR(500, "服务器内部错误"),
- SERVICE_UNAVAILABLE(503, "服务不可用"),
-
- // ========== 业务状态码 1000-1999 ==========
- BUSINESS_ERROR(1000, "业务处理失败"),
- PARAM_VALIDATION_ERROR(1001, "参数校验失败"),
- DATA_NOT_FOUND(1002, "数据不存在"),
- DATA_ALREADY_EXISTS(1003, "数据已存在"),
- OPERATION_NOT_ALLOWED(1004, "操作不被允许"),
-
- // ========== 用户相关 2000-2099 ==========
- USER_NOT_FOUND(2000, "用户不存在"),
- USER_ALREADY_EXISTS(2001, "用户已存在"),
- USER_DISABLED(2002, "用户已被禁用"),
- USER_NOT_VERIFIED(2003, "用户未验证"),
- INVALID_CREDENTIALS(2004, "用户名或密码错误"),
- PASSWORD_TOO_WEAK(2005, "密码强度不够"),
- PHONE_ALREADY_EXISTS(2006, "手机号已存在"),
- EMAIL_ALREADY_EXISTS(2007, "邮箱已存在"),
- ACCOUNT_ALREADY_EXISTS(2008, "账号已存在"),
-
- // ========== 认证相关 2100-2199 ==========
- TOKEN_INVALID(2100, "Token无效"),
- TOKEN_EXPIRED(2101, "Token已过期"),
- TOKEN_MISSING(2102, "Token缺失"),
- REFRESH_TOKEN_INVALID(2103, "刷新Token无效"),
- LOGIN_REQUIRED(2104, "请先登录"),
- PERMISSION_DENIED(2105, "权限不足"),
- CAPTCHA_ERROR(2106, "验证码错误"),
- CAPTCHA_EXPIRED(2107, "验证码已过期"),
-
- // ========== AI对话相关 2200-2299 ==========
- AI_SERVICE_ERROR(2200, "AI服务异常"),
- CONVERSATION_NOT_FOUND(2201, "对话不存在"),
- MESSAGE_SEND_FAILED(2202, "消息发送失败"),
- EMOTION_ANALYSIS_FAILED(2203, "情绪分析失败"),
- AI_RESPONSE_TIMEOUT(2204, "AI响应超时"),
-
- // ========== 情绪记录相关 2300-2399 ==========
- EMOTION_RECORD_NOT_FOUND(2300, "情绪记录不存在"),
- EMOTION_TYPE_INVALID(2301, "情绪类型无效"),
- EMOTION_INTENSITY_INVALID(2302, "情绪强度无效"),
- EMOTION_DATE_INVALID(2303, "情绪日期无效"),
-
- // ========== 成长课题相关 2400-2499 ==========
- TOPIC_NOT_FOUND(2400, "课题不存在"),
- TOPIC_NOT_UNLOCKED(2401, "课题未解锁"),
- TOPIC_ALREADY_COMPLETED(2402, "课题已完成"),
- INTERACTION_NOT_FOUND(2403, "互动记录不存在"),
- TOPIC_CATEGORY_INVALID(2404, "课题分类无效"),
-
- // ========== 地图探索相关 2500-2599 ==========
- LOCATION_NOT_FOUND(2500, "地点不存在"),
- LOCATION_ALREADY_EXISTS(2501, "地点已存在"),
- COORDINATE_INVALID(2502, "坐标无效"),
- POST_NOT_FOUND(2503, "帖子不存在"),
- COMMENT_NOT_FOUND(2504, "评论不存在"),
-
- // ========== 成就奖励相关 2600-2699 ==========
- ACHIEVEMENT_NOT_FOUND(2600, "成就不存在"),
- ACHIEVEMENT_ALREADY_UNLOCKED(2601, "成就已解锁"),
- REWARD_NOT_FOUND(2602, "奖励不存在"),
- INSUFFICIENT_POINTS(2603, "积分不足"),
- REWARD_ALREADY_CLAIMED(2604, "奖励已领取"),
-
- // ========== 统计分析相关 2700-2799 ==========
- STATS_CALCULATION_ERROR(2700, "统计计算错误"),
- REPORT_GENERATION_FAILED(2701, "报告生成失败"),
- DATA_EXPORT_FAILED(2702, "数据导出失败"),
-
- // ========== 文件上传相关 2800-2899 ==========
- FILE_UPLOAD_FAILED(2800, "文件上传失败"),
- FILE_TYPE_NOT_SUPPORTED(2801, "文件类型不支持"),
- FILE_SIZE_EXCEEDED(2802, "文件大小超限"),
- FILE_NOT_FOUND(2803, "文件不存在"),
-
- // ========== 第三方服务相关 2900-2999 ==========
- THIRD_PARTY_SERVICE_ERROR(2900, "第三方服务异常"),
- SMS_SEND_FAILED(2901, "短信发送失败"),
- EMAIL_SEND_FAILED(2902, "邮件发送失败"),
- MAP_SERVICE_ERROR(2903, "地图服务异常"),
- PAYMENT_SERVICE_ERROR(2904, "支付服务异常"),
-
- // ========== 系统相关 9000-9999 ==========
- SYSTEM_MAINTENANCE(9000, "系统维护中"),
- RATE_LIMIT_EXCEEDED(9001, "请求频率超限"),
- DATABASE_ERROR(9002, "数据库异常"),
- CACHE_ERROR(9003, "缓存异常"),
- MQ_ERROR(9004, "消息队列异常"),
- CONFIG_ERROR(9005, "配置错误");
-
- /**
- * 状态码
- */
- private final Integer code;
-
- /**
- * 状态消息
- */
- private final String message;
-}
diff --git a/backend/common/src/main/java/com/emotionmuseum/common/util/HttpUtil.java b/backend/common/src/main/java/com/emotionmuseum/common/util/HttpUtil.java
deleted file mode 100644
index 2e7c413..0000000
--- a/backend/common/src/main/java/com/emotionmuseum/common/util/HttpUtil.java
+++ /dev/null
@@ -1,202 +0,0 @@
-package com.emotionmuseum.common.util;
-
-import cn.hutool.core.util.StrUtil;
-import com.alibaba.fastjson2.JSON;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.http.*;
-import org.springframework.stereotype.Component;
-import org.springframework.web.client.RestClientException;
-import org.springframework.web.client.RestTemplate;
-
-import java.util.Map;
-
-/**
- * HTTP工具类
- *
- * @author huazhongmin
- * @since 2025-07-12
- */
-@Slf4j
-@Component
-public class HttpUtil {
-
- @Autowired
- @Qualifier("restTemplate")
- private RestTemplate restTemplate;
-
- @Autowired
- @Qualifier("longRestTemplate")
- private RestTemplate longRestTemplate;
-
- @Autowired
- @Qualifier("fastRestTemplate")
- private RestTemplate fastRestTemplate;
-
- /**
- * GET请求
- */
- public T get(String url, Class responseType) {
- return get(url, null, responseType);
- }
-
- /**
- * GET请求(带请求头)
- */
- public T get(String url, HttpHeaders headers, Class responseType) {
- try {
- HttpEntity entity = new HttpEntity<>(headers);
- ResponseEntity response = restTemplate.exchange(url, HttpMethod.GET, entity, responseType);
- return response.getBody();
- } catch (RestClientException e) {
- log.error("GET请求失败: url={}, error={}", url, e.getMessage());
- throw new RuntimeException("HTTP GET请求失败: " + e.getMessage());
- }
- }
-
- /**
- * POST请求
- */
- public T post(String url, Object requestBody, Class responseType) {
- return post(url, requestBody, null, responseType);
- }
-
- /**
- * POST请求(带请求头)
- */
- public T post(String url, Object requestBody, HttpHeaders headers, Class responseType) {
- try {
- if (headers == null) {
- headers = new HttpHeaders();
- }
- headers.setContentType(MediaType.APPLICATION_JSON);
-
- String jsonBody = requestBody instanceof String ?
- (String) requestBody : JSON.toJSONString(requestBody);
-
- HttpEntity entity = new HttpEntity<>(jsonBody, headers);
- ResponseEntity response = restTemplate.exchange(url, HttpMethod.POST, entity, responseType);
- return response.getBody();
- } catch (RestClientException e) {
- log.error("POST请求失败: url={}, body={}, error={}", url, requestBody, e.getMessage());
- throw new RuntimeException("HTTP POST请求失败: " + e.getMessage());
- }
- }
-
- /**
- * PUT请求
- */
- public T put(String url, Object requestBody, Class responseType) {
- return put(url, requestBody, null, responseType);
- }
-
- /**
- * PUT请求(带请求头)
- */
- public T put(String url, Object requestBody, HttpHeaders headers, Class responseType) {
- try {
- if (headers == null) {
- headers = new HttpHeaders();
- }
- headers.setContentType(MediaType.APPLICATION_JSON);
-
- String jsonBody = requestBody instanceof String ?
- (String) requestBody : JSON.toJSONString(requestBody);
-
- HttpEntity entity = new HttpEntity<>(jsonBody, headers);
- ResponseEntity response = restTemplate.exchange(url, HttpMethod.PUT, entity, responseType);
- return response.getBody();
- } catch (RestClientException e) {
- log.error("PUT请求失败: url={}, body={}, error={}", url, requestBody, e.getMessage());
- throw new RuntimeException("HTTP PUT请求失败: " + e.getMessage());
- }
- }
-
- /**
- * DELETE请求
- */
- public T delete(String url, Class responseType) {
- return delete(url, null, responseType);
- }
-
- /**
- * DELETE请求(带请求头)
- */
- public T delete(String url, HttpHeaders headers, Class responseType) {
- try {
- HttpEntity entity = new HttpEntity<>(headers);
- ResponseEntity response = restTemplate.exchange(url, HttpMethod.DELETE, entity, responseType);
- return response.getBody();
- } catch (RestClientException e) {
- log.error("DELETE请求失败: url={}, error={}", url, e.getMessage());
- throw new RuntimeException("HTTP DELETE请求失败: " + e.getMessage());
- }
- }
-
- /**
- * 长连接POST请求(用于AI接口)
- */
- public T longPost(String url, Object requestBody, HttpHeaders headers, Class responseType) {
- try {
- if (headers == null) {
- headers = new HttpHeaders();
- }
- headers.setContentType(MediaType.APPLICATION_JSON);
-
- String jsonBody = requestBody instanceof String ?
- (String) requestBody : JSON.toJSONString(requestBody);
-
- HttpEntity entity = new HttpEntity<>(jsonBody, headers);
- ResponseEntity