diff --git a/src/main/java/com/aida/lanecarford/aspect/LoggingAspect.java b/src/main/java/com/aida/lanecarford/aspect/LoggingAspect.java index 8c7e272..cc1f866 100644 --- a/src/main/java/com/aida/lanecarford/aspect/LoggingAspect.java +++ b/src/main/java/com/aida/lanecarford/aspect/LoggingAspect.java @@ -10,11 +10,12 @@ import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import jakarta.servlet.http.HttpServletRequest; + import java.util.Arrays; /** * 日志切面 - * + * * @author AI Assistant * @since 2024-01-01 */ @@ -28,13 +29,15 @@ public class LoggingAspect { * 定义切点:所有Controller方法 */ @Pointcut("execution(* com.aida.lanecarford.controller..*(..))") - public void controllerMethods() {} + public void controllerMethods() { + } /** * 定义切点:所有Service方法 */ @Pointcut("execution(* com.aida.lanecarford.service..*(..))") - public void serviceMethods() {} + public void serviceMethods() { + } /** * Controller方法执行前记录日志 @@ -44,12 +47,13 @@ public class LoggingAspect { ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); if (attributes != null) { HttpServletRequest request = attributes.getRequest(); - + logger.info("=== 请求开始 ==="); logger.info("请求URL: {}", request.getRequestURL().toString()); logger.info("请求方法: {}", request.getMethod()); logger.info("请求IP: {}", getClientIpAddress(request)); - logger.info("调用方法: {}.{}", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName()); +// logger.info("调用方法: {}.{}", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName()); + logger.info("调用方法: {}.{}", joinPoint.getSignature().getDeclaringType().getSimpleName(), joinPoint.getSignature().getName()); logger.info("请求参数: {}", Arrays.toString(joinPoint.getArgs())); } } @@ -59,7 +63,7 @@ public class LoggingAspect { */ @AfterReturning(pointcut = "controllerMethods()", returning = "result") public void logControllerAfterReturning(JoinPoint joinPoint, Object result) { - logger.info("方法执行成功: {}.{}", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName()); + logger.info("方法执行成功: {}.{}", joinPoint.getSignature().getDeclaringType().getSimpleName(), joinPoint.getSignature().getName()); logger.info("返回结果: {}", result); logger.info("=== 请求结束 ==="); } @@ -69,7 +73,7 @@ public class LoggingAspect { */ @AfterThrowing(pointcut = "controllerMethods()", throwing = "exception") public void logControllerAfterThrowing(JoinPoint joinPoint, Throwable exception) { - logger.error("方法执行异常: {}.{}", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName()); + logger.error("方法执行异常: {}.{}", joinPoint.getSignature().getDeclaringType().getSimpleName(), joinPoint.getSignature().getName()); logger.error("异常信息: ", exception); logger.info("=== 请求异常结束 ==="); } @@ -80,15 +84,15 @@ public class LoggingAspect { @Around("serviceMethods()") public Object logServiceAround(ProceedingJoinPoint joinPoint) throws Throwable { long startTime = System.currentTimeMillis(); - String methodName = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName(); - +// String methodName = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName(); + String methodName = joinPoint.getSignature().getDeclaringType().getSimpleName() + "." + joinPoint.getSignature().getName(); try { logger.debug("Service方法开始执行: {}", methodName); Object result = joinPoint.proceed(); - + long endTime = System.currentTimeMillis(); logger.debug("Service方法执行成功: {}, 耗时: {}ms", methodName, (endTime - startTime)); - + return result; } catch (Exception e) { long endTime = System.currentTimeMillis(); @@ -106,22 +110,22 @@ public class LoggingAspect { if (xForwardedFor != null && !xForwardedFor.isEmpty() && !"unknown".equalsIgnoreCase(xForwardedFor)) { return xForwardedFor.split(",")[0]; } - + String xRealIp = request.getHeader("X-Real-IP"); if (xRealIp != null && !xRealIp.isEmpty() && !"unknown".equalsIgnoreCase(xRealIp)) { return xRealIp; } - + String proxyClientIp = request.getHeader("Proxy-Client-IP"); if (proxyClientIp != null && !proxyClientIp.isEmpty() && !"unknown".equalsIgnoreCase(proxyClientIp)) { return proxyClientIp; } - + String wlProxyClientIp = request.getHeader("WL-Proxy-Client-IP"); if (wlProxyClientIp != null && !wlProxyClientIp.isEmpty() && !"unknown".equalsIgnoreCase(wlProxyClientIp)) { return wlProxyClientIp; } - + return request.getRemoteAddr(); } } \ No newline at end of file diff --git a/src/main/java/com/aida/lanecarford/aspect/PerformanceAspect.java b/src/main/java/com/aida/lanecarford/aspect/PerformanceAspect.java index be3394d..a52a443 100644 --- a/src/main/java/com/aida/lanecarford/aspect/PerformanceAspect.java +++ b/src/main/java/com/aida/lanecarford/aspect/PerformanceAspect.java @@ -9,7 +9,7 @@ import org.springframework.stereotype.Component; /** * 性能监控切面 - * + * * @author AI Assistant * @since 2024-01-01 */ @@ -22,7 +22,7 @@ public class PerformanceAspect { /** * 监控Controller方法性能 */ - @Around("execution(* com.aida.lanecarford.controller..*(..))") +// @Around("execution(* com.aida.lanecarford.controller..*(..))") public Object monitorControllerPerformance(ProceedingJoinPoint joinPoint) throws Throwable { return monitorMethodPerformance(joinPoint, "Controller"); } @@ -30,7 +30,7 @@ public class PerformanceAspect { /** * 监控Service方法性能 */ - @Around("execution(* com.aida.lanecarford.service..*(..))") +// @Around("execution(* com.aida.lanecarford.service..*(..))") public Object monitorServicePerformance(ProceedingJoinPoint joinPoint) throws Throwable { return monitorMethodPerformance(joinPoint, "Service"); } @@ -38,7 +38,7 @@ public class PerformanceAspect { /** * 监控数据库操作性能 */ - @Around("execution(* com.aida.lanecarford.mapper..*(..))") +// @Around("execution(* com.aida.lanecarford.mapper..*(..))") public Object monitorMapperPerformance(ProceedingJoinPoint joinPoint) throws Throwable { return monitorMethodPerformance(joinPoint, "Mapper"); } @@ -49,28 +49,28 @@ public class PerformanceAspect { private Object monitorMethodPerformance(ProceedingJoinPoint joinPoint, String layer) throws Throwable { long startTime = System.currentTimeMillis(); String methodName = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName(); - + try { Object result = joinPoint.proceed(); long endTime = System.currentTimeMillis(); long executionTime = endTime - startTime; - + // 记录性能日志 logPerformance(layer, methodName, executionTime, true); - + // 如果执行时间过长,记录警告 if (executionTime > getWarningThreshold(layer)) { logger.warn("{}方法执行时间过长: {} - {}ms", layer, methodName, executionTime); } - + return result; } catch (Exception e) { long endTime = System.currentTimeMillis(); long executionTime = endTime - startTime; - + // 记录异常性能日志 logPerformance(layer, methodName, executionTime, false); - + throw e; } } @@ -80,10 +80,10 @@ public class PerformanceAspect { */ private void logPerformance(String layer, String methodName, long executionTime, boolean success) { if (logger.isDebugEnabled()) { - logger.debug("性能监控 - {}: {} - {}ms - {}", - layer, methodName, executionTime, success ? "成功" : "失败"); + logger.debug("性能监控 - {}: {} - {}ms - {}", + layer, methodName, executionTime, success ? "成功" : "失败"); } - + // 可以在这里添加性能数据收集逻辑,比如发送到监控系统 collectPerformanceMetrics(layer, methodName, executionTime, success); } @@ -114,7 +114,7 @@ public class PerformanceAspect { // - 发送到时序数据库 // - 更新内存中的统计信息 // - 发送到监控系统 - + // 示例:简单的内存统计 PerformanceMetrics.recordExecution(layer, methodName, executionTime, success); } @@ -123,7 +123,7 @@ public class PerformanceAspect { * 简单的性能指标收集器 */ private static class PerformanceMetrics { - + public static void recordExecution(String layer, String methodName, long executionTime, boolean success) { // 简单的日志记录,实际项目中可以替换为更复杂的指标收集 if (executionTime > 1000) { // 超过1秒的操作 diff --git a/src/main/java/com/aida/lanecarford/common/enums/StatusEnum.java b/src/main/java/com/aida/lanecarford/common/enums/StatusEnum.java index 768bfcc..2582866 100644 --- a/src/main/java/com/aida/lanecarford/common/enums/StatusEnum.java +++ b/src/main/java/com/aida/lanecarford/common/enums/StatusEnum.java @@ -1,6 +1,7 @@ package com.aida.lanecarford.common.enums; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; import lombok.Getter; @@ -8,13 +9,18 @@ import java.util.stream.Stream; @Getter @AllArgsConstructor +@Schema(description = "生成状态枚举") public enum StatusEnum { + @Schema(description = "等待中") PENDING(0), + @Schema(description = "成功") SUCCEEDED(1), + @Schema(description = "失败") FAILED(2), + @Schema(description = "运行中") RUNNING(3); private int code; @@ -24,5 +30,4 @@ public enum StatusEnum { } - } diff --git a/src/main/java/com/aida/lanecarford/controller/LoginController.java b/src/main/java/com/aida/lanecarford/controller/LoginController.java index 6fb3f34..d856d41 100644 --- a/src/main/java/com/aida/lanecarford/controller/LoginController.java +++ b/src/main/java/com/aida/lanecarford/controller/LoginController.java @@ -2,6 +2,7 @@ package com.aida.lanecarford.controller; import com.aida.lanecarford.common.ApiResponse; import com.aida.lanecarford.dto.LoginRequest; +import com.aida.lanecarford.entity.User; import com.aida.lanecarford.service.LoginService; import com.aida.lanecarford.vo.LoginVO; import io.swagger.v3.oas.annotations.Hidden; @@ -23,8 +24,8 @@ public class LoginController { private final LoginService loginService; @Operation( - summary = "预检查并发送邮箱验证码", - description = "根据操作类型验证邮箱有效性并发送验证码。支持注册、登录、忘记密码三种操作类型。" + summary = "预检查并发送邮箱验证码", + description = "根据操作类型验证邮箱有效性并发送验证码。支持注册、登录、忘记密码三种操作类型。" ) @PostMapping("/precheckAndSendEmail") @Hidden @@ -44,8 +45,8 @@ public class LoginController { } @Operation( - summary = "用户注册或登录", - description = "通过验证码完成用户注册或登录,返回JWT令牌和用户信息。" + summary = "用户注册或登录", + description = "通过验证码完成用户注册或登录,返回JWT令牌和用户信息。" ) @PostMapping("/registerOrLogin") public ApiResponse registerOrLogin(@Valid @RequestBody LoginRequest loginRequest) { @@ -53,8 +54,8 @@ public class LoginController { } @Operation( - summary = "用户登出", - description = "清除用户登录状态,使当前JWT令牌失效。" + summary = "用户登出", + description = "清除用户登录状态,使当前JWT令牌失效。" ) @GetMapping("/logout") public ApiResponse logout() { @@ -63,8 +64,8 @@ public class LoginController { } @Operation( - summary = "忘记密码", - description = "通过邮箱验证码重置用户密码。需要先获取验证码,然后提供新密码。" + summary = "忘记密码", + description = "通过邮箱验证码重置用户密码。需要先获取验证码,然后提供新密码。" ) @PostMapping("/forgotPwd") public ApiResponse forgotPwd(@Valid @RequestBody LoginRequest loginRequest) { @@ -73,8 +74,8 @@ public class LoginController { } @Operation( - summary = "检查登录状态", - description = "验证当前用户的登录状态是否有效,检查JWT令牌是否过期。" + summary = "检查登录状态", + description = "验证当前用户的登录状态是否有效,检查JWT令牌是否过期。" ) @GetMapping("/checkLoginStatus") public ApiResponse checkLoginStatus() { @@ -86,4 +87,13 @@ public class LoginController { } } + @Operation( + summary = "获取用户信息", + description = "通过token获取当前用户信息" + ) + @GetMapping("/getUserInfo") + public ApiResponse getUserInfo() { + return ApiResponse.success(loginService.getUserInfo()); + } + } diff --git a/src/main/java/com/aida/lanecarford/dto/BaseRequest.java b/src/main/java/com/aida/lanecarford/dto/BaseRequest.java index 6d8e6df..dd527ba 100644 --- a/src/main/java/com/aida/lanecarford/dto/BaseRequest.java +++ b/src/main/java/com/aida/lanecarford/dto/BaseRequest.java @@ -5,17 +5,15 @@ import lombok.Data; import jakarta.validation.constraints.Max; import jakarta.validation.constraints.Min; + import java.io.Serializable; /** * 请求参数基类 - * - * @author AI Assistant - * @since 2024-01-01 */ @Data @Schema(description = "请求参数基类") -public abstract class BaseRequest implements Serializable { +public class BaseRequest implements Serializable { private static final long serialVersionUID = 1L; @@ -71,8 +69,8 @@ public abstract class BaseRequest implements Serializable { * 是否有时间范围筛选 */ public boolean hasTimeRange() { - return startTime != null && !startTime.trim().isEmpty() - && endTime != null && !endTime.trim().isEmpty(); + return startTime != null && !startTime.trim().isEmpty() + && endTime != null && !endTime.trim().isEmpty(); } /** diff --git a/src/main/java/com/aida/lanecarford/dto/OutfitCallbackDTO.java b/src/main/java/com/aida/lanecarford/dto/OutfitCallbackDTO.java index aaaeaf7..275bc67 100644 --- a/src/main/java/com/aida/lanecarford/dto/OutfitCallbackDTO.java +++ b/src/main/java/com/aida/lanecarford/dto/OutfitCallbackDTO.java @@ -3,6 +3,7 @@ package com.aida.lanecarford.dto; import lombok.Data; import java.util.List; +import java.util.Map; @Data public class OutfitCallbackDTO { @@ -14,5 +15,5 @@ public class OutfitCallbackDTO { private String path; - private List items; + private List> items; } diff --git a/src/main/java/com/aida/lanecarford/service/LoginService.java b/src/main/java/com/aida/lanecarford/service/LoginService.java index 148c7ec..4ddefb5 100644 --- a/src/main/java/com/aida/lanecarford/service/LoginService.java +++ b/src/main/java/com/aida/lanecarford/service/LoginService.java @@ -26,4 +26,6 @@ public interface LoginService extends IService { void forgotPwd(LoginRequest loginRequest); boolean checkLoginStatus(); + + User getUserInfo(); } diff --git a/src/main/java/com/aida/lanecarford/service/impl/LoginServiceImpl.java b/src/main/java/com/aida/lanecarford/service/impl/LoginServiceImpl.java index 50d559d..e4c2fe8 100644 --- a/src/main/java/com/aida/lanecarford/service/impl/LoginServiceImpl.java +++ b/src/main/java/com/aida/lanecarford/service/impl/LoginServiceImpl.java @@ -3,6 +3,7 @@ package com.aida.lanecarford.service.impl; import com.aida.lanecarford.common.constant.RedisURIConstants; import com.aida.lanecarford.common.enums.AuthenticationOperationTypeEnum; import com.aida.lanecarford.common.enums.LanguageEnum; +import com.aida.lanecarford.common.response.ResultEnum; import com.aida.lanecarford.common.security.JwtUtil; import com.aida.lanecarford.common.security.context.UserContext; import com.aida.lanecarford.dto.LoginRequest; @@ -246,11 +247,18 @@ public class LoginServiceImpl extends ServiceImpl implements L return false; } - // 谷歌登录 - - + // todo 谷歌登录 + // 获取用户信息 + public User getUserInfo() { + AuthPrincipalVO userHolder = UserContext.getUserHolder(); + User user = getById(userHolder.getId()); + if (Objects.isNull(user)) { + throw new BusinessException("User information cannot be found", ResultEnum.ERROR.getCode()); + } + return user; + } } diff --git a/src/main/java/com/aida/lanecarford/service/impl/StyleServiceImpl.java b/src/main/java/com/aida/lanecarford/service/impl/StyleServiceImpl.java index d819b25..113a01c 100644 --- a/src/main/java/com/aida/lanecarford/service/impl/StyleServiceImpl.java +++ b/src/main/java/com/aida/lanecarford/service/impl/StyleServiceImpl.java @@ -64,7 +64,7 @@ public class StyleServiceImpl extends ServiceImpl implements outfitRequest.setGender(requestOutfitDTO.getGender()); outfitRequestMapper.insert(outfitRequest); - String response = SendRequestUtil.sendPost(CommonConstants.REQUEST_OUTFIT, JSON.toJSONString(params)); + String response = SendRequestUtil.sendPostWithRetry(CommonConstants.REQUEST_OUTFIT, JSON.toJSONString(params)); JSONObject jsonObject = JSONObject.parseObject(response); // todo 确认这里的status的取值 if (Objects.isNull(response) /*|| !jsonObject.getString("status").equals("ok")*/) { @@ -75,7 +75,7 @@ public class StyleServiceImpl extends ServiceImpl implements List requestIds = jsonObject.getJSONArray("outfit_ids").toJavaList(String.class); - for(String requestId : requestIds) { + for (String requestId : requestIds) { // 生成需要 6~8s, 所以这里可以先请求再存储 Style style = new Style(); style.setCustomerId(requestOutfitDTO.getCustomerId()); @@ -175,7 +175,7 @@ public class StyleServiceImpl extends ServiceImpl implements String key = RedisURIConstants.outfitResultCache + requestID; Object outfit = cacheUtil.getCache(key); - if (Objects.isNull(outfit)){ + if (Objects.isNull(outfit)) { reQueryIds.add(requestID); continue; } diff --git a/src/main/java/com/aida/lanecarford/util/SendRequestUtil.java b/src/main/java/com/aida/lanecarford/util/SendRequestUtil.java index 7e34448..8a48da1 100644 --- a/src/main/java/com/aida/lanecarford/util/SendRequestUtil.java +++ b/src/main/java/com/aida/lanecarford/util/SendRequestUtil.java @@ -12,7 +12,7 @@ import java.util.Map; @Component public class SendRequestUtil { - public static String sendPost(String url, String requestBodyStr){ + public static String sendPost(String url, String requestBodyStr) { int status; String body; try (HttpResponse execute = HttpRequest.post(url) @@ -53,6 +53,61 @@ public class SendRequestUtil { throw new BusinessException("System error (External interface failure)"); } + public static String sendPostWithRetry(String url, String requestBodyStr) { + return sendPost(url, requestBodyStr, 3, 1000); // 默认重试3次,间隔1秒 + } + + public static String sendPost(String url, String requestBodyStr, int maxRetries, long retryInterval) { + int status = 0; + String body = null; + int retryCount = 0; + + while (retryCount <= maxRetries) { + try { + log.debug("发送POST请求,URL: {}, 重试次数: {}/{}", url, retryCount, maxRetries); + + HttpResponse execute = HttpRequest.post(url) + .header("Content-Type", "application/json") + .body(requestBodyStr) + .timeout(180000) + .execute(); + + status = execute.getStatus(); + body = execute.body(); + + if (status == 200) { + log.debug("请求成功,URL: {}, 状态码: {}", url, status); + return body; + } else { + log.warn("请求返回非200状态码,URL: {}, 状态码: {}, Body: {}", url, status, body); + } + + } catch (Exception e) { + log.warn("请求发生异常,URL: {}, 异常信息: {}, 重试次数: {}/{}", + url, e.getMessage(), retryCount, maxRetries); + } + + // 判断是否继续重试 + if (retryCount < maxRetries) { + retryCount++; + try { + log.debug("等待 {}ms 后重试...", retryInterval); + Thread.sleep(retryInterval); + // 可选:递增重试间隔(指数退避) + retryInterval = (long) (retryInterval * 1.5); + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + throw new RuntimeException("重试被中断", ie); + } + } else { + break; + } + } + + log.error("请求最终失败,URL: {}, 最大重试次数: {}, 最后状态码: {}, 最后响应: {}", + url, maxRetries, status, body); + return null; + } } diff --git a/src/main/java/com/aida/lanecarford/util/StringListConverter.java b/src/main/java/com/aida/lanecarford/util/StringListConverter.java index d487ab5..7ee717b 100644 --- a/src/main/java/com/aida/lanecarford/util/StringListConverter.java +++ b/src/main/java/com/aida/lanecarford/util/StringListConverter.java @@ -7,6 +7,7 @@ import lombok.extern.slf4j.Slf4j; import java.util.ArrayList; import java.util.List; +import java.util.Map; @Slf4j public class StringListConverter { @@ -16,7 +17,7 @@ public class StringListConverter { /** * 将 List 转换为 JSON 字符串 */ - public static String listToJson(List list) { + public static String listToJson(List> list) { if (list == null || list.isEmpty()) { return "[]"; } @@ -31,12 +32,13 @@ public class StringListConverter { /** * 将 JSON 字符串转换为 List */ - public static List jsonToList(String json) { + public static List> jsonToList(String json) { if (json == null || json.trim().isEmpty()) { return new ArrayList<>(); } try { - return objectMapper.readValue(json, new TypeReference>() {}); + return objectMapper.readValue(json, new TypeReference<>() { + }); } catch (JsonProcessingException e) { log.error("JSON转List失败: {}", json, e); throw new RuntimeException("JSON转List失败", e); diff --git a/src/main/java/com/aida/lanecarford/vo/OutfitResultVO.java b/src/main/java/com/aida/lanecarford/vo/OutfitResultVO.java index 6720d72..4423f7f 100644 --- a/src/main/java/com/aida/lanecarford/vo/OutfitResultVO.java +++ b/src/main/java/com/aida/lanecarford/vo/OutfitResultVO.java @@ -1,18 +1,29 @@ package com.aida.lanecarford.vo; +import com.aida.lanecarford.common.enums.StatusEnum; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.NoArgsConstructor; @Data @NoArgsConstructor +@Schema(description = "AI穿搭推荐结果响应参数") public class OutfitResultVO { + @Schema(description = "记录ID", example = "21") private Long id; + @Schema(description = "请求ID", example = "7c30e8f6-fdc6-4699-9239-ae6a9d3cf948") private String requestId; + @Schema(description = "图片路径", example = "https://example.com/images/outfit_123.jpg") private String path; + @Schema( + description = "处理状态", + implementation = StatusEnum.class, + requiredMode = Schema.RequiredMode.REQUIRED + ) private String status; public OutfitResultVO(Long id, String requestId, String status) { diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index 0a1f38a..832c3b2 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -45,7 +45,7 @@ spring: mybatis-plus: configuration: map-underscore-to-camel-case: true - log-impl: org.apache.ibatis.logging.stdout.StdOutImpl + # log-impl: org.apache.ibatis.logging.stdout.StdOutImpl global-config: db-config: logic-delete-field: deleted diff --git a/src/main/resources/sql/schema.sql b/src/main/resources/sql/schema.sql index 2e51b2a..fc7b698 100644 --- a/src/main/resources/sql/schema.sql +++ b/src/main/resources/sql/schema.sql @@ -1,6 +1,6 @@ -- Lane Carford AI系统基础架构数据库表结构 -- 创建数据库 -CREATE DATABASE IF NOT EXISTS lanecarford CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; +CREATE DATABASE IF NOT EXISTS lanecrawford CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE lanecrawford; -- 1. 用户表