diff --git a/pom.xml b/pom.xml index db8b8b4d..9c14ce4b 100644 --- a/pom.xml +++ b/pom.xml @@ -427,6 +427,11 @@ bcpkix-jdk18on 1.78.1 + + + org.springframework.boot + spring-boot-starter-aop + diff --git a/src/main/java/com/ai/da/common/aspect/ControllerLoggingAspect.java b/src/main/java/com/ai/da/common/aspect/ControllerLoggingAspect.java new file mode 100644 index 00000000..391a0dda --- /dev/null +++ b/src/main/java/com/ai/da/common/aspect/ControllerLoggingAspect.java @@ -0,0 +1,170 @@ +package com.ai.da.common.aspect; + +import com.ai.da.common.context.UserContext; +import com.ai.da.model.vo.AuthPrincipalVo; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; +import org.springframework.web.multipart.MultipartFile; + +import java.util.HashMap; +import java.util.Map; + +/** + * Controller日志切面 + * 记录所有Controller接口的请求参数和用户信息 + */ +@Aspect +@Component +public class ControllerLoggingAspect { + + private static final Logger logger = LoggerFactory.getLogger(ControllerLoggingAspect.class); + + /** + * 定义切点:所有Controller方法 + */ + @Pointcut("execution(* com.ai.da.controller..*(..))") + public void controllerMethods() { + } + + /** + * Controller方法执行前记录日志 + */ +// @Before("controllerMethods()") + public void logControllerBefore(JoinPoint joinPoint) { + ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); + if (attributes != null) { + HttpServletRequest request = attributes.getRequest(); + + // 获取当前用户ID + Long userId = null; + AuthPrincipalVo authPrincipalVo = UserContext.getUserHolder(); + if (authPrincipalVo != null) { + userId = authPrincipalVo.getId(); + } + + // 获取请求参数 + Map params = getRequestParams(joinPoint, request); + + logger.info("=== 请求开始 ==="); + logger.info("用户ID: {}", userId); + logger.info("请求URL: {}", request.getRequestURL().toString()); + logger.info("请求方法: {}", request.getMethod()); + logger.info("请求IP: {}", getClientIpAddress(request)); + logger.info("调用方法: {}.{}", joinPoint.getSignature().getDeclaringType().getSimpleName(), joinPoint.getSignature().getName()); + logger.info("请求参数: {}", params); + } + } + + /** + * 获取请求参数 + */ + private Map getRequestParams(JoinPoint joinPoint, HttpServletRequest request) { + Map params = new HashMap<>(); + + // 1. 获取Query String参数 + String queryString = request.getQueryString(); + if (queryString != null && !queryString.isEmpty()) { + params.put("queryString", queryString); + } + + // 2. 获取方法参数(包含 @PathVariable, @RequestParam, @RequestBody 等) + Object[] args = joinPoint.getArgs(); + + if (args != null && args.length > 0) { + Map methodParams = new HashMap<>(); + for (int i = 0; i < args.length; i++) { + Object arg = args[i]; + // 过滤掉不可序列化的参数 + if (arg != null) { + if (isIgnorable(arg)) { + // 对于可忽略的类型,记录类型名 + methodParams.put("arg" + i, "[" + arg.getClass().getSimpleName() + "]"); + } else { + try { + methodParams.put("arg" + i, arg); + } catch (Exception e) { + methodParams.put("arg" + i, arg.toString()); + } + } + } + } + if (!methodParams.isEmpty()) { + params.put("methodParams", methodParams); + } + } + + return params; + } + + /** + * 判断是否需要过滤的参数类型 + */ + private boolean isIgnorable(Object obj) { + return obj instanceof HttpServletRequest + || obj instanceof HttpServletResponse + || obj instanceof MultipartFile + || obj instanceof MultipartFile[]; + } + + /** + * Controller方法抛出异常时记录日志 + */ + @AfterThrowing(pointcut = "controllerMethods()", throwing = "exception") + public void logControllerAfterThrowing(JoinPoint joinPoint, Throwable exception) { + ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); + + Long userId = null; + AuthPrincipalVo authPrincipalVo = UserContext.getUserHolder(); + if (authPrincipalVo != null) { + userId = authPrincipalVo.getId(); + } + + // 获取请求参数 + Map params = new HashMap<>(); + if (attributes != null) { + HttpServletRequest request = attributes.getRequest(); + params = getRequestParams(joinPoint, request); + } + + logger.error("=== 请求异常 ==="); + logger.error("用户ID: {}", userId); + logger.error("调用方法: {}.{}", joinPoint.getSignature().getDeclaringType().getSimpleName(), joinPoint.getSignature().getName()); + logger.error("请求参数: {}", params); + logger.error("异常信息: ", exception); + logger.error("=== 异常结束 ==="); + } + + /** + * 获取客户端真实IP地址 + */ + private String getClientIpAddress(HttpServletRequest request) { + String xForwardedFor = request.getHeader("X-Forwarded-For"); + 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(); + } +} diff --git a/src/main/java/com/ai/da/service/impl/GenerateServiceImpl.java b/src/main/java/com/ai/da/service/impl/GenerateServiceImpl.java index fa080170..6d7907cf 100644 --- a/src/main/java/com/ai/da/service/impl/GenerateServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/GenerateServiceImpl.java @@ -785,8 +785,9 @@ public class GenerateServiceImpl extends ServiceImpl i long requestEndTime = System.currentTimeMillis(); log.info("HTTP请求完成 - 响应状态: {}, 耗时: {}ms, taskId: {}", response.code(), (requestEndTime - requestStartTime), taskId); + String result = response.body().string(); if (!response.isSuccessful()) { - log.warn("Google API响应失败,状态码: {} for taskId: {}", response.code(), taskId); + log.warn("Google API响应失败,状态码: {} for taskId: {},结果:{}", response.code(), taskId,result); if (attempt < maxRetries) { Thread.sleep(retryDelay * attempt); // 递增延迟 continue; @@ -795,7 +796,7 @@ public class GenerateServiceImpl extends ServiceImpl i } } - String result = response.body().string(); + // log.info("Google 响应结果:{}", result); com.alibaba.fastjson.JSONObject jsonResponse = JSON.parseObject(result); @@ -1065,6 +1066,12 @@ public class GenerateServiceImpl extends ServiceImpl i String result = response.body().string(); + if (response.code() != 200) { + log.error("Google API 请求失败 - taskId: {}, 尝试: {}, URL: {}, 状态码: {}, 响应结果: {}", + taskId, attempt, endpoint, response.code(), result); + throw new BusinessException("system.error"); + } + // log.info("Google 响应结果:{}", result); com.alibaba.fastjson.JSONObject jsonResponse = JSON.parseObject(result); @@ -1260,14 +1267,31 @@ public class GenerateServiceImpl extends ServiceImpl i modelAndPromptMap.put(ModelConstants.USE_MODEL, ModelConstants.LOCAL_MODEL); } } else if (ModelConstants.SKETCHBOARD.equals(generateDTO.getLevel1Type())) { - String[] split = generateDTO.getText().split(","); - String style = split[0].trim(); - if ("Lolita".equals( style)){ - style = "洛丽塔"; + String style = ""; + String userPrompt = ""; + // 找到第一个逗号的位置 + int firstCommaIndex = generateDTO.getText().indexOf(","); + if (firstCommaIndex != -1) { + // 截取第一个逗号前的内容作为style + style = generateDTO.getText().substring(0, firstCommaIndex).trim(); + // 截取第一个逗号后的所有内容作为userPrompt(去除首尾空格) + userPrompt = generateDTO.getText().substring(firstCommaIndex + 1).trim(); + + if ("Lolita".equals(style)) { + style = "洛丽塔"; + } + } else { + // 兼容无逗号的情况:style为空,全部内容作为userPrompt + userPrompt = generateDTO.getText().trim(); } - String userPrompt = split[1]; + String prompt = userPrompt + "rules:front view sketch only,plain white background, single garment only, orthographic, centered on white background, borderless canvas, thin monochrome black line art.\n" + - " No clothes hanger, no fake clothes hanger, no human-related lines, no color fill, no words, no text, no black background, no boundary or frame.sketch style:"+ style; + " No clothes hanger, no fake clothes hanger, no human-related lines, no color fill, no words, no text, no black background, no boundary or frame."; + + if (!style.trim().isEmpty() && !"all".equalsIgnoreCase(style)) { + prompt += ".sketch style:" + style.trim(); + } + modelAndPromptMap.put(ModelConstants.PROMPT, prompt); if (isUseImage) { if (ModelConstants.ADVANCED.equals(modelName)) {