package com.yunhai.cms.controller.api; import com.yunhai.platform.apistd.ApiResponse; import com.yunhai.platform.utils.exception.ErrorCode; import lombok.extern.slf4j.Slf4j; import org.springframework.core.Ordered; import org.springframework.core.convert.ConversionFailedException; import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.core.annotation.Order; 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; /** * 管理端参数级异常翻译(体检 H-1/H-4 根因修复)。 * *

平台 GlobalExceptionHandler 只兜 @Valid 校验/BizException/全局 Exception, * 三类 Spring MVC 参数绑定异常(缺参/类型不匹配/请求体不可读)落入兜底分支被 * 报成 code=6 "内部服务错误"。本 advice 以更高优先级把它们翻译回 code=2 参数错误, * 前端可提示、日志不再噪音;真正的业务/系统异常不受影响(仍走平台处理器,堆栈完整)。 */ @Slf4j @Order(Ordered.HIGHEST_PRECEDENCE) @RestControllerAdvice(basePackages = "com.yunhai.cms.controller.api") public class ApiParamExceptionHandler { @ExceptionHandler(MissingServletRequestParameterException.class) public ApiResponse missingParam(MissingServletRequestParameterException e) { log.warn("管理端缺必填参数: {}", e.getParameterName()); return ApiResponse.fail(ErrorCode.PARAM_ERROR, "缺少必填参数:" + e.getParameterName()); } @ExceptionHandler(MethodArgumentTypeMismatchException.class) public ApiResponse typeMismatch(MethodArgumentTypeMismatchException e) { String expected = e.getRequiredType() == null ? "" : "(应为 " + e.getRequiredType().getSimpleName() + ")"; log.warn("管理端参数类型不匹配: {}={}", e.getName(), e.getValue()); return ApiResponse.fail(ErrorCode.PARAM_ERROR, "参数格式不正确:" + e.getName() + expected); } /** JSON 解析失败:编码/语法/时间格式(jackson date-format yyyy-MM-dd HH:mm:ss) */ @ExceptionHandler(HttpMessageNotReadableException.class) public ApiResponse unreadable(HttpMessageNotReadableException e) { Throwable cause = e.getCause() == null ? e : e.getCause(); String hint = cause.getMessage() == null ? "" : ": " + firstLine(cause.getMessage()); log.warn("管理端请求体不可读 {}", firstLine(hint)); return ApiResponse.fail(ErrorCode.PARAM_ERROR, "请求体格式错误(JSON/UTF-8/时间格式,时间需 yyyy-MM-dd HH:mm:ss)"); } private static String firstLine(String s) { int i = s.indexOf('\n'); String line = i < 0 ? s : s.substring(0, i); return line.length() > 120 ? line.substring(0, 120) : line; } }