关键词:
在 SpringBoot 项目中 ,异常统一处理,可以使用 Spring 中 @ControllerAdvice 来统一处理,也可以自己来定义异常处理方案。SpringBoot 中,对异常的处理有一些默认的策略,我们分别来看。
默认情况下,SpringBoot 中的异常页面 是这样的:
我们从这个异常提示中,也能看出来,之所以用户看到这个页面,是因为开发者没有明确提供一个
/error 路径,如果开发者提供了 /error 路径 ,这个页面就不会展示出来,不过在 Spring Boot 中,提供 /error路径实际上是下下策,Spring Boot 本身在处理异常时,也是当所有条件都不满足时,才会去找 /error 路径。那么我们就先来看看,在 SpringBoot 中,如何自定义 error 页面,整体上来说,可以分为两种,一种是静态页面,另一种是动态页面。
静态异常页面
自定义静态异常页面,又分为两种,第一种 是使用 HTTP 响应码来命名页面,例如 404.html、405.html、500.html ….,
另一种就是直接定义一个4xx.html,表示400-499 的状态都显示这个异常页面,5xx.html 表示 500-599 的状态显示这个异常页面。
默认是在classpath:/static/error/ 路径下定义相关页面:
此时,启动项目,如果项目抛出 500 请求错误,就会自动展示 500.html 这个页面,发生 404 就会展示 404.html 页面。如果异常展示页面既存在 5xx.html,也存在 500.html ,此时,发生500异常时,优先展示 500.html 页面。
动态异常页面
动态的异常页面定义方式和静态的基本一致,可以采用的页面模板有 jsp、freemarker、thymeleaf。动态异常页面,也支持 404.html 或者 4xx.html,但是一般来说,由于动态异常页面可以直接展示异常详细信息,所以就没有必要挨个枚举错误了 ,直接定义 4xx.html(这里使用thymeleaf模板)或者
5xx.html 即可。
注意,动态页面模板,不需要开发者自己去定义控制器,直接定义异常页面即可 ,Spring Boot
中自带的异常处理器会自动查找到异常页面。
页面定义如下:
页面内容如下:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>5xx</h1>
<table border="1">
<tr>
<td>path</td>
<td th:text="$path"></td>
</tr>
<tr>
<td>error</td>
<td th:text="$error"></td>
</tr>
<tr>
<td>message</td>
<td th:text="$message"></td>
</tr>
<tr>
<td>timestamp</td>
<td th:text="$timestamp"></td>
</tr>
<tr>
<td>status</td>
<td th:text="$status"></td>
</tr>
</table>
</body>
</html>
默认情况下,完整的异常信息就是这5条,展示效果如下:
如果动态页面和静态页面同时定义了异常处理页面,例如
classpath:/static/error/404.html 和 classpath:/templates/error/404.html
同时存在时,默认使用动态页面。即完整的错误页面查找方式应该是这样:
发生了500错误–>查找动态500.html 页面–>查找静态 500.html –> 查找动态 5xx.html–>查找静态 5xx.html。
自定义异常数据
默认情况下,在Spring Boot 中,所有的异常数据其实就是上文所展示出来的5条数据,这5条数据定义在 org.springframework.boot.web.reactive.error.DefaultErrorAttributes 类中,具体定义在 getErrorAttributes 方法中 :
@Override
public Map<String, Object> getErrorAttributes(ServerRequest request,
boolean includeStackTrace)
Map<String, Object> errorAttributes = new LinkedHashMap<>();
errorAttributes.put("timestamp", new Date());
errorAttributes.put("path", request.path());
Throwable error = getError(request);
HttpStatus errorStatus = determineHttpStatus(error);
errorAttributes.put("status", errorStatus.value());
errorAttributes.put("error", errorStatus.getReasonPhrase());
errorAttributes.put("message", determineMessage(error));
handleException(errorAttributes, determineException(error), includeStackTrace);
return errorAttributes;
DefaultErrorAttributes
类本身则是在org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration
异常自动配置类中定义的,如果开发者没有自己提供一个 ErrorAttributes 的实例的话,那么
Spring Boot 将自动提供一个ErrorAttributes 的实例,也就是 DefaultErrorAttributes 。
基于此 ,开发者自定义 ErrorAttributes 有两种方式 :
- 直接实现 ErrorAttributes 接口
- 继承 DefaultErrorAttributes(推荐),因为 DefaultErrorAttributes 中对异常数据的处理已经完成,开发者可以直接使用。
具体定义如下:
@Component
public class MyErrorAttributes extends DefaultErrorAttributes
@Override
public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace)
Map<String, Object> map = super.getErrorAttributes(webRequest, includeStackTrace);
if ((Integer)map.get("status") == 500)
map.put("message", "服务器内部错误!");
return map;
定义好的 ErrorAttributes 一定要注册成一个 Bean ,这样,Spring Boot 就不会使用默认的 DefaultErrorAttributes 了,运行效果如下图:
自定义异常视图
异常视图默认就是前面所说的静态或者动态页面,这个也是可以自定义的,首先 ,默认的异常视图加载逻辑在 org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController 类的 errorHtml 方法中,这个方法用来返回异常页面+数据,还有另外一个 error 方法,这个方法用来返回异常数据(如果是 ajax 请求,则该方法会被触发)。
@RequestMapping(produces = MediaType.TEXT_HTML_VALUE)
public ModelAndView errorHtml(HttpServletRequest request,
HttpServletResponse response)
HttpStatus status = getStatus(request);
Map<String, Object> model = Collections.unmodifiableMap(getErrorAttributes(
request, isIncludeStackTrace(request, MediaType.TEXT_HTML)));
response.setStatus(status.value());
ModelAndView modelAndView = resolveErrorView(request, response, status, model);
return (modelAndView != null) ? modelAndView : new ModelAndView("error", model);
在该方法中,首先会通过 getErrorAttributes 方法去获取异常数据(实际上会调用到 ErrorAttributes 的实例 的getErrorAttributes 方法),然后调用 resolveErrorView 去创建一个 ModelAndView
,如果这里创建失败,那么用户将会看到默认的错误提示页面。正常情况下,resolveErrorView 方法会来到 DefaultErrorViewResolver 类的 resolveErrorView 方法中:
@Override
public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status,
Map<String, Object> model)
ModelAndView modelAndView = resolve(String.valueOf(status.value()), model);
if (modelAndView == null && SERIES_VIEWS.containsKey(status.series()))
modelAndView = resolve(SERIES_VIEWS.get(status.series()), model);
return modelAndView;
在这里,首先以异常响应码作为视图名分别去查找动态页面和静态页面,如果没有查找到,则再以
4xx 或者 5xx 作为视图名再去分别查找动态或者静态页面。要自定义异常视图解析,也很容易
,由于 DefaultErrorViewResolver 是在 ErrorMvcAutoConfiguration类中提供的实例,即开发者没有提供相关实例时,会使用默认的 DefaultErrorViewResolver ,开发者提供了自己的
ErrorViewResolver 实例后,默认的配置就会失效,因此,自定义异常视图,只需要提供 一个 ErrorViewResolver 的实例即可:
@Component
public class MyErrorViewResolver extends DefaultErrorViewResolver
public MyErrorViewResolver(ApplicationContext applicationContext, ResourceProperties resourceProperties)
super(applicationContext, resourceProperties);
@Override
public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model)
return new ModelAndView("/aaa/123", model);
实际上,开发者也可以在这里定义异常数据(直接在 resolveErrorView 方法重新定义一个 model ,将参数中的model 数据拷贝过去并修改,注意参数中的 model 类型为 UnmodifiableMap,即不可以直接修改),而不需要自定义MyErrorAttributes。定义完成后,提供一个名为123的视图,如下图:
如此之后,错误试图就算定义成功了。
rubyruby自定义异常(代码片段)
自定义异常(代码片段)
1packagedemo2;23/**4*自定义异常5*@author6*7*/8publicclassMyExceptionextendsException910publicMyException()11super();121314publicMyException(Stringmessage)15super(message);1617181packagedemo2;23import 查看详情
python编写自定义异常。(代码片段)
rubyruby自定义异常类(代码片段)
python自定义异常类(代码片段)
自定义异常(代码片段)
定义一个类publicclassAgeOutOfBoundsExceptionextendsException根据父类的构造方法生成一个构造方法一般情况下只要无参和String通过throw抛出一个异常对象throw所在的方法通过throw声明改异常在调用方法的时候捕获处理 查看详情
自定义异常(代码片段)
自定义异常自定义异常概述当java里面的异常无法满足开发者的需求时,可以自定义异常。packagecom.monkey1024.exception;publicclassUserService//注册的方法publicvoidregister(Stringname)if(name.length()<6)//需要在这里面一个抛出非法注册名的异常,... 查看详情
封装自定义异常(代码片段)
...能通过写博客来让自己走的更远。一般在web项目中都需要定义一个全局异常来处理一些业务方面的异常,下面是自定义异常的一些代码。1.自定义一个异常,然后继承RuntimeException/***@authorzhuwenwen*@date2018/8/1620:18*/@Getter 查看详情
自定义异常(代码片段)
自定义异常在程序运行的时候,有的时候执行完一段代码的时候你发现程序代码不符合逻辑,所以我们想要return结束这段代码,但是这段代码所在的方法的返回值类型又是void,因此我们没办法return,所以这个... 查看详情
自定义异常(代码片段)
自定义异常在程序运行的时候,有的时候执行完一段代码的时候你发现程序代码不符合逻辑,所以我们想要return结束这段代码,但是这段代码所在的方法的返回值类型又是void,因此我们没办法return,所以这个... 查看详情
java学习笔记3.10.5异常处理-自定义异常(代码片段)
文章目录零、本讲学习目标一、为何要自定义异常(一)存在问题(二)解决方法二、使用自定义异常(一)语法格式(二)案例演示1、创建三角形类2、创建计算三角形面积类3、创建三角形异常类4、方法抛出自定义异常5、进... 查看详情
自定义异常结合项目实战的测试(代码片段)
-----------------------------引用部分-----------------------------------------------------Java异常之自定义异常 转自https://www.cnblogs.com/AlanLee/p/6104492.htmlJava如何抛出异常、自定义异常 转自https://blog.csdn.net/qq_1 查看详情
drf自定义异常与封装response对象(代码片段)
1异常处理RESTframework提供了异常处理,我们可以自定义异常处理函数。#统一接口返回#自定义异常方法,替换掉全局#写一个方法#自定义异常处理的方法fromrest_framework.viewsimportexception_handlerfromrest_framework.responseimportResponsefromrest_frame... 查看详情
自定义runtimeexception工具类(代码片段)
文章目录自定义异常MyInfoException,将异常提示传递给前端1.定义一个异常的工具类extendsRuntimeException2.封装统一的响应工具类自定义异常MyInfoException,将异常提示传递给前端1.定义一个异常的工具类extendsRuntimeExceptionpackagecom.monkey;public... 查看详情
自定义异常处理(代码片段)
classMyExcept(Exception):def__init__(self,msg):self.message=msgdef__str__(self):returnself.messagetry:raiseMyExcept("我的异常")exceptMyExceptase:print(e) 查看详情
[2]异常链自定义异常(代码片段)
...调用的上层处理,使用throws关键字 1.1throw1.2throws2、自定义异常 查看详情
自定义异常(代码片段)
...可以使用Spring中@ControllerAdvice来统一处理,也可以自己来定义异常处理方案。SpringBoot中,对异常的处理有一些默认的策略,我们分别来看。默认情况下,SpringBoot中的异常页面是这样的:我们从这个异常提示中,也能看出来,之... 查看详情