diff --git a/zkh-web/src/main/java/vip/jcfd/web/controller/CustomErrorController.java b/zkh-web/src/main/java/vip/jcfd/web/controller/CustomErrorController.java index 6d7e7de..d57442a 100644 --- a/zkh-web/src/main/java/vip/jcfd/web/controller/CustomErrorController.java +++ b/zkh-web/src/main/java/vip/jcfd/web/controller/CustomErrorController.java @@ -2,6 +2,8 @@ package vip.jcfd.web.controller; import jakarta.servlet.RequestDispatcher; import jakarta.servlet.http.HttpServletRequest; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.boot.web.servlet.error.ErrorController; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -9,15 +11,90 @@ import vip.jcfd.common.core.R; import java.util.Optional; +/** + * 自定义错误控制器 + * 重写 Spring MVC 默认的错误视图,返回 JSON 格式的错误响应 + */ @RestController public class CustomErrorController implements ErrorController { + private static final Logger log = LoggerFactory.getLogger(CustomErrorController.class); + + /** + * 处理错误请求 + * 根据 HTTP 状态码返回相应的错误信息 + */ @RequestMapping("/error") public R handleError(HttpServletRequest request) { + // 获取状态码 int status = Optional.ofNullable(request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE)) .map(Object::toString) .map(Integer::parseInt) .orElse(500); - return new R<>(status, "发生错误", false, null); + + // 获取请求 URI + String requestUri = Optional.ofNullable(request.getAttribute(RequestDispatcher.ERROR_REQUEST_URI)) + .map(Object::toString) + .orElse("unknown"); + + // 获取异常信息 + String exceptionMessage = Optional.ofNullable(request.getAttribute(RequestDispatcher.ERROR_MESSAGE)) + .map(Object::toString) + .orElse(null); + + // 获取异常类型 + String exceptionType = Optional.ofNullable(request.getAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE)) + .map(Object::toString) + .orElse(null); + + // 获取异常对象 + Throwable throwable = Optional.ofNullable(request.getAttribute(RequestDispatcher.ERROR_EXCEPTION)) + .filter(Throwable.class::isInstance) + .map(Throwable.class::cast) + .orElse(null); + + // 记录错误日志 + if (status >= 500) { + log.error("服务器错误 - 状态码: {}, 请求路径: {}, 异常类型: {}, 异常信息: {}", + status, requestUri, exceptionType, exceptionMessage, throwable); + } else if (status >= 400) { + log.warn("客户端错误 - 状态码: {}, 请求路径: {}, 异常信息: {}", + status, requestUri, exceptionMessage); + } + + // 根据状态码获取友好的错误消息 + String errorMessage = getErrorMessage(status, exceptionMessage); + + return new R<>(status, errorMessage, false, null); + } + + /** + * 根据状态码获取友好的错误消息 + */ + private String getErrorMessage(int status, String originalMessage) { + if (originalMessage != null && !originalMessage.isEmpty()) { + return originalMessage; + } + + return switch (status) { + case 400 -> "请求参数错误"; + case 401 -> "未授权,请先登录"; + case 403 -> "无权访问"; + case 404 -> "您访问的地址不存在"; + case 405 -> "请求方法不支持"; + case 500 -> "服务器内部错误"; + case 502 -> "网关错误"; + case 503 -> "服务暂时不可用"; + case 504 -> "网关超时"; + default -> "请求失败"; + }; + } + + /** + * 返回错误路径 + * 实现 ErrorController 接口要求 + */ + public String getErrorPath() { + return "/error"; } }