yxh
6 天以前 68ff33beff11310e830b0615b5a81f83fad0f683
jh-framework/jh-spring-boot-starter-web/src/main/java/cn/lihu/jh/framework/web/core/handler/GlobalExceptionHandler.java
@@ -4,6 +4,8 @@
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.exc.InvalidFormatException;
import cn.lihu.jh.framework.apilog.core.service.ApiErrorLogFrameworkService;
import cn.lihu.jh.framework.common.exception.ServiceException;
import cn.lihu.jh.framework.common.exception.util.ServiceExceptionUtil;
@@ -17,6 +19,7 @@
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.util.Assert;
import org.springframework.validation.BindException;
@@ -124,6 +127,46 @@
    }
    /**
     * 处理请求体(@RequestBody)反序列化失败。
     *
     * <h3>为什么需要单独处理</h3>
     * 之前没有这个处理器,JSON 里的字段类型不对(例如 {@code "bookCheckType": "常规心电图"},
     * 而实体字段是 {@code Integer})时会抛 {@link HttpMessageNotReadableException},
     * 一路落到 {@link #defaultExceptionHandler} 兜底 —— 前端只看到 <b>500「系统异常」</b>,
     * 完全看不出是参数格式问题(实测 2026-10-28 排查 {@code /ecg/appointment/create} 即为此)。
     *
     * <p>现在改为返回 <b>400</b> 并明确指出「哪个字段、收到什么值、期望什么类型」。
     */
    @ExceptionHandler(HttpMessageNotReadableException.class)
    public CommonResult<?> httpMessageNotReadableExceptionHandler(HttpMessageNotReadableException ex) {
        log.warn("[httpMessageNotReadableExceptionHandler]", ex);
        return CommonResult.error(BAD_REQUEST.getCode(), "请求参数格式错误:" + buildMessageNotReadableDetail(ex));
    }
    /**
     * 把反序列化异常翻译成人能看懂的说明:字段名 + 收到的值 + 期望的类型。
     */
    private String buildMessageNotReadableDetail(HttpMessageNotReadableException ex) {
        Throwable cause = ex.getMostSpecificCause();
        // ① 字段类型不匹配(最常见):拿到了字段名 / 实际值 / 期望类型
        if (cause instanceof InvalidFormatException) {
            InvalidFormatException ife = (InvalidFormatException) cause;
            String field = ife.getPath().isEmpty()
                    ? "" : ife.getPath().get(ife.getPath().size() - 1).getFieldName();
            Object value = ife.getValue();
            Class<?> target = ife.getTargetType();
            return String.format("字段「%s」类型不正确(收到值:%s,期望类型:%s)",
                    StrUtil.blankToDefault(field, "未知字段"), value, null == target ? "未知" : target.getSimpleName());
        }
        // ② 请求体缺失 / JSON 语法错误等:用最具体的原因
        if (cause instanceof JsonParseException) {
            return "JSON 格式不正确:" + ((JsonParseException) cause).getOriginalMessage();
        }
        String message = null == cause ? ex.getMessage() : cause.getMessage();
        return StrUtil.blankToDefault(message, "请求体无法解析");
    }
    /**
     * 处理 SpringMVC 参数校验不正确
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)