自定义异常(代码片段)

qiuwenli qiuwenli     2022-12-09     656

关键词:

在 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 有两种方式 :

  1. 直接实现 ErrorAttributes 接口
  2. 继承 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中的异常页面是这样的:我们从这个异常提示中,也能看出来,之... 查看详情

rubyminitest:断言自定义异常(error)(代码片段)

查看详情