@@ -1,7 +1,9 @@
|
||||
package com.yunhai.userbase.aspect;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.yunhai.platform.apistd.ApiResponse;
|
||||
import com.yunhai.platform.apistd.BizException;
|
||||
import com.yunhai.platform.appauth.AppAuthFilter;
|
||||
import com.yunhai.platform.utils.exception.DException;
|
||||
import com.yunhai.userbase.common.annotation.OapiLog;
|
||||
import com.yunhai.userbase.entity.ApplicationInfo;
|
||||
import com.yunhai.userbase.entity.SysOapiLog;
|
||||
@@ -90,6 +92,8 @@ public class OapiLogAspect {
|
||||
} catch (Throwable e) {
|
||||
entity.setStatusCode(500);
|
||||
entity.setErrorMsg(truncate(e.getMessage(), 2000));
|
||||
// 业务异常(DException/BizException)同样构造实际返回的响应体落库,便于详情下载
|
||||
fillErrorResponse(entity, e, saveResponse, maxResponseSize);
|
||||
throw e;
|
||||
} finally {
|
||||
entity.setCostTime(System.currentTimeMillis() - start);
|
||||
@@ -213,8 +217,42 @@ public class OapiLogAspect {
|
||||
if (!saveResponse || result == null) {
|
||||
return;
|
||||
}
|
||||
writeResponseData(entity, result, maxResponseSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* 异常路径:与 {@code GlobalExceptionHandler} 保持一致的响应体(DException/BizException → ApiResponse),
|
||||
* 使日志下载内容等于调用方实际收到的 body;其余异常不构造(响应不可预期)。
|
||||
*/
|
||||
private void fillErrorResponse(SysOapiLog entity, Throwable e, boolean saveResponse, int maxResponseSize) {
|
||||
if (!saveResponse) {
|
||||
return;
|
||||
}
|
||||
ApiResponse<?> response = toApiResponse(e);
|
||||
if (response == null) {
|
||||
return;
|
||||
}
|
||||
writeResponseData(entity, response, maxResponseSize);
|
||||
}
|
||||
|
||||
private ApiResponse<?> toApiResponse(Throwable e) {
|
||||
if (e instanceof DException) {
|
||||
DException de = (DException) e;
|
||||
return ApiResponse.fail(de.getCode(), de.getMessage(), de.getData());
|
||||
}
|
||||
if (e instanceof BizException) {
|
||||
BizException be = (BizException) e;
|
||||
return ApiResponse.fail(be.getErrorCode(), be.getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void writeResponseData(SysOapiLog entity, Object payload, int maxResponseSize) {
|
||||
if (payload == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
String resp = SensitiveDataMasker.maskObject(result);
|
||||
String resp = SensitiveDataMasker.maskObject(payload);
|
||||
if (resp == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -5,8 +5,10 @@ import org.springframework.core.annotation.Order;
|
||||
import org.springframework.validation.BindException;
|
||||
import org.springframework.validation.FieldError;
|
||||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||
import org.springframework.web.bind.MissingServletRequestParameterException;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
|
||||
|
||||
import javax.validation.ConstraintViolation;
|
||||
import javax.validation.ConstraintViolationException;
|
||||
@@ -52,6 +54,18 @@ public class GlobalExceptionHandler {
|
||||
return paramError(msg);
|
||||
}
|
||||
|
||||
/** 缺少必需的请求参数(@RequestParam 必填项未传,如 oapi 调用方漏传 groupId)。 */
|
||||
@ExceptionHandler(MissingServletRequestParameterException.class)
|
||||
public Map<String, Object> handleMissingParam(MissingServletRequestParameterException ex) {
|
||||
return paramError("缺少必需的请求参数: " + ex.getParameterName());
|
||||
}
|
||||
|
||||
/** 请求参数类型不匹配(如 Integer 参数收到非数字字符串)。 */
|
||||
@ExceptionHandler(MethodArgumentTypeMismatchException.class)
|
||||
public Map<String, Object> handleTypeMismatch(MethodArgumentTypeMismatchException ex) {
|
||||
return paramError("参数类型不匹配: " + ex.getName());
|
||||
}
|
||||
|
||||
private String fieldErrorsMessage(java.util.List<FieldError> fieldErrors) {
|
||||
if (fieldErrors == null || fieldErrors.isEmpty()) {
|
||||
return "参数校验失败";
|
||||
|
||||
Reference in New Issue
Block a user