springboot 项目之默认全局异常拦截
在web项目中,不可避免地会出现系统异常,例如资源找不到的404错误,服务器异常的5**错误,如果对这些异常不进行任何处理,则是非常不友好的。今天就对springboot项目中的异常拦截处理进行一个简单的使用说明。这里我使用的是springboot默认的异常拦截,也就是新建一个BasicErrorController类继承BasicErrorController。
默认异常拦截
在springboot项目中,不管是404错误还是其他错误,浏览器访问的时候,都会抛出一个非常不友好的异常,如下

默认ajax异常
如果在客户端(非ajax)请求,则会返回一个json对象,如下

默认非ajax异常
这样的异常是非常不友好的,接下来我们需要来对异常进行加工处理。
thymeleaf定制化页面
这里使用thymeleaf模板来新建页面。在pom中添加依赖即可。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> <version>2.4.1</version> </dependency>
新建一个继承BaseErrorController的类
在项目下新建一个error(可任意)包,新建一个继承BaseErrorController的类。如下

BaseErrorController目录

自定义BaseErrorController继承代码
BaseErrorController里面有对异常进行拦截,我们可以进入到该类的源码中查看

BaseErrorController 源码 errorHtml

BaseErrorController 源码 error
可以看到在errorHtml()中返回了异常页面,在error()中返回了postman(非ajax)请求。
那么我们自定义的类继承该类写这两个方法,就可以实现异常的自定义拦截
package meicius.ori.error; import org.springframework.boot.autoconfigure.web.ErrorProperties; import org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController; import org.springframework.boot.web.servlet.error.DefaultErrorAttributes; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.HashMap; import java.util.Map; @Controller public class MyBasicErrorController extends BasicErrorController { public MyBasicErrorController() { super(new DefaultErrorAttributes(), new ErrorProperties()); } @Override protected Map<String, Object> getErrorAttributes(HttpServletRequest request, boolean includeStackTrace) { return super.getErrorAttributes(request, includeStackTrace); } @Override public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) { ModelAndView modelAndView = super.errorHtml(request, response); String httpStatus = modelAndView.getModel().get("status").toString(); if(httpStatus.equals("404")){ modelAndView.setViewName("/error/404"); return modelAndView; } Map<String, Object> stringObjectMap = getErrorAttributes(request, true); modelAndView.addObject("stackTrace", stringObjectMap.get("trace").toString()); modelAndView.setViewName("/error/error"); return modelAndView; } @Override public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) { Map<String, Object> body = getErrorAttributes(request,isIncludeStackTrace(request, MediaType.TEXT_HTML)); Map<String, Object> bodyRes = new HashMap<String, Object>(); bodyRes.put("message", "异常拦截"); bodyRes.put("data", body); HttpStatus status = getStatus(request); return new ResponseEntity<Map<String, Object>>(bodyRes, status); } }
代码中重写了errorHtml() 和 error()
errorHtml()方法
在该方法中,我做了一个404错误和非404错误的判断,如果是404错误,则会返回一个定制化的页面,只有一张图片。如果是非404错误,则会返回相关的错误信息。在templates中建立error文件夹,在该文件夹下面放抛出异常的页面
error.html
<!DOCTYPE HTML> <html xmlns:th="http://www.thymeleaf.org" layout:decorator="layout"> <head> <title>Spring Boot ori统一异常拦截</title> <script type="text/javascript"> </script> <style> *{ margin: 0; padding: 0; } html, body, .container, .navbar{ height: 100%; width: 100%; overflow: hidden; } .navbar{ margin-left: 20px; } h1{ height: 60px; } h3{ height: 40px; } .debugDiv{ display: flex; margin-left: 20px; align-content: center; margin-bottom: 20px; } .linkDiv{ width: 140px; height: 60px; margin-left: 10px; line-height: 60px; text-align: center; } .linkDiv:nth-child(1){ background-color: cornflowerblue; } .linkDiv:nth-child(2){ background-color: aquamarine; } .linkDiv:nth-child(3){ background-color: chocolate; } .trace{ width: 80%; height: calc(100% - 400px); overflow: auto !important; border: 2px solid cornflowerblue; padding: 5px; } .trace::-webkit-scrollbar{ width: 10px; } .trace::-webkit-scrollbar-track{ background-color: cornflowerblue; /*-webkit-border-radius: 2em;*/ /*-moz-border-radius: 2em;*/ /*border-radius: 2em;*/ } .trace::-webkit-scrollbar-thumb{ background-color: chocolate; /*-webkit-border-radius: 2em;*/ /*-moz-border-radius: 2em;*/ /*border-radius: 2em;*/ } </style> </head> <body> <div class="container" layout:fragment="content" th:remove="tag"> <div class="navbar"> <h1 th:text="'ori 系统异常统一处理'"></h1> <h3 th:text="'时间:'+${timestamp}"></h3> <h3 th:text="'状态码:'+${status}"></h3> <h3 th:text="'错误状态:'+${error}"></h3> <h3 th:text="'地址:'+${path}"></h3> <h3>调试</h3> <div class="debugDiv"> <div class="linkDiv"> <a th:href="@{'https://www.google.com/webhp?hl=zh-CN#safe=strict&hl=zh-CN&q='+${error}}" class="btn btn-default btn-lg" target="_blank" id="Google">Google</a> </div> <div class="linkDiv"> <a th:href="@{'https://www.baidu.com/s?wd='+${error}}" class="btn btn-default btn-lg" target="_blank" id="Baidu">Baidu</a> </div> <div class="linkDiv"> <a th:href="@{'http://stackoverflow.com/search?q='+${error}}" class="btn btn-default btn-lg" target="_blank" id="StackOverFlow">StackOverFlow</a> </div> </div> <h3>异常堆栈跟踪日志StackTrace</h3> <div class="trace" th:each="line:${stackTrace}"> <div th:text="${line}"></div> </div> </div> </div> </body> </html>
404页面
<!DOCTYPE HTML> <html xmlns:th="http://www.thymeleaf.org" layout:decorator="layout"> <head> <title>Spring Boot ori统一异常拦截</title> <script type="text/javascript"> </script> <style> *{ margin: 0; padding: 0; } html, body, .container{ height: 100%; width: 100%; overflow: hidden; } img{ height: 100%; width: 100%; } </style> </head> <body> <div class="container"> <img src="/404.png"/> </div> </body> </html>
其中404.html页面引入了一张图片,图片放在static下面。整个目录如下

页面目录
这样就完成了ajax请求的异常拦截

自定义ajax拦截

自定义ajax拦截
error()
error()方法里面是对非ajax请求的处理,例如使用postman请求

自定义非ajax请求
至此,springboot默认全局异常处理就完成了。这种方式不仅可以获取到异常的接口路径、错误状态、错误代码、还可以获取到堆栈日志等信息。