通用错误处理
在Spring Boot中,Controller中抛出的异常默认交给了/error来处理,应用程序可以将/error映射到一个特定的Controller中处理来代替Spring Boot的默认实现,应用可以继承AbstractErrorController来统一处理系统的各种异常。
pom
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.gcz</groupId> <artifactId>errorhandle</artifactId> <version>1.0-SNAPSHOT</version> <!-- springboot应用 --> <parent> <artifactId>spring-boot-starter-parent</artifactId> <groupId>org.springframework.boot</groupId> <version>2.3.0.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- 使用热部署 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> </dependency> <!-- hibernate验证框架 --> <dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> <version>6.0.17.Final</version> <scope>compile</scope> </dependency> <!-- lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <!-- hutool --> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.5.9</version> </dependency> <!--thymeleaf 模板依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> </dependencies> <!-- 指定springboot仓库位置 --> <repositories> <repository> <id>milestones</id> <name>Spring Milestones</name> <url>http://code.yhsperp.com:8081/nexus/repository/maven-public/</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories> </project>
error.html
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>error</title> </head> <body> status:<text th:text="${status}" id="userId"></text> <br> errorMessage:<text th:text="${errorMessage}" id="userId"></text> </body> </html>
controller
package com.gcz.controller; import cn.hutool.json.JSONUtil; import cn.hutool.log.Log; import cn.hutool.log.LogFactory; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.web.servlet.error.AbstractErrorController; import org.springframework.boot.web.servlet.error.DefaultErrorAttributes; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.*; /** * @author guocz * @date 20210707 * 通用错误处理 */ @Controller public class ErrorController extends AbstractErrorController { Log log = LogFactory.get(ErrorController.class); @Autowired ObjectMapper objectMapper; public ErrorController() { super(new DefaultErrorAttributes()); } @RequestMapping("/error") public ModelAndView getErrorPath(HttpServletRequest request, HttpServletResponse response) throws IOException { Map<String, Object> model = Collections.unmodifiableMap(getErrorAttributes(request, false)); // 获取异常,有可能为空 Throwable cause = getCause(request); // 对应于HTTP Status,如404 int status = (int) model.get("status"); // 错误信息 String message = (String) model.get("message"); // 友好提示 String errorMessage = getErrorMessage(cause); // 后台打印日志信息方便查错 log.info(status + "," + message, cause); response.setStatus(status); if (!isJsonRequest(request)) { // error.btl模板显示错误的详细信息 ModelAndView view = new ModelAndView("/error.html"); view.addAllObjects(model); view.addObject("errorMessage", errorMessage); view.addObject("status", status); view.addObject("cause", cause); return view; }else { Map<String, Object> error = new HashMap<>(16); error.put("success", false); error.put("errorMessage", errorMessage); error.put("message", message); response.getWriter().write(JSONUtil.toJsonStr(error)); response.setCharacterEncoding("utf-8"); return null; } } protected Throwable getCause(HttpServletRequest request) { Throwable error = (Throwable) request.getAttribute("javax.servlet.error.exception"); if (error != null) { // MVC有可能会封装异常成ServletException,需要调用getCause获取真正的异常 while (error instanceof ServletException && error.getCause() != null) { error = error.getCause(); } } return error; } protected String getErrorMessage(Throwable ex) { // 自定义异常 // if (ex instanceof YourApplicationException) { // return ex.getMessage(); // } return "服务器错误,请联系管理员"; } protected boolean isJsonRequest(HttpServletRequest request) { String requestUri = (String) request.getAttribute("javax.servlet.error.request_uri"); // 也可通过获取HTTP头,根据Accept字段是否包含JSON来进一步判断,比如 // return request.getHeader("Accept").contains("application/json"); return requestUri != null && requestUri.endsWith(".json"); } @Override public String getErrorPath() { return null; } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)