第三章(续)SpringBoot处理Error和Exception

  • Post author:
  • Post category:其他

        在互联网时代,开发的应用大多数是直面用户的,程序中的任何一点小疏忽都可能导致用户流失, 而程序出现错误和异常往往又是不可完全避免的。所以开发程序的过程中,需要设计和实施良好的 错误和异常处理机制。在 Web 开发中,我们知道可以针对错误或异常设计错误页面,以及使用 try…catch 等结构对异常进行捕获和处理。那么对于使用 Spring Boot 创建的 Web 应用程序,错误和 异常处理又要如何进行呢?

Spring Boot 的异常处理机制

        Spring Boot 针对错误和异常处理提供了自己的一套默认机制:SpringBoot 为提供一个默认的映射 /error,当处理中抛出异常之后,会转到该请求中处理,并且该请求有一个全局的错误页面来展示异常内容。此外,当应用程序中产生异常时,Spring Boot 根据发送的请求头中的 accept 是否包含 text/html 来分别返回不同的响应信息。当从浏览器地址栏或使用提交按钮提交表单访问应用接口时,请求头中的accept便会包含 text/html 信息,产生异常时,Spring Boot通过 org.springframework.web.servlet.ModelAndView 对象来装载异常信息,并以 HTML 的格式返回,显示默认的错误页面;而当从客户端(如 PostMan)或发送异步请求访问应用接口产生异常时(客户端或 异步请求访问时,请求头中的 accept 不包含 text/html),Spring Boot 则以 JSON 的格式返回异常信息。

        例如,我们在一个 Spring Boot Web 项目的Controller中制造一个算数异常,比如除数为0,代码如下:

@RestController
@RequestMapping("/json")
public class JsonController { 

   @GetMapping("/getOne")
    public User getOneUser(){
        int a = 2/0;
        return new User("admin",13456L,"admin@niit.com.cn","M");
    }

}

在浏览器的地址栏中访问  http://localhost:8088/json/getOne 将显示如下默认的错误页面:

 控制台提示算数异常

 这是SpringBoot提供的默认的错误处理页面。为了用户体验,我们可以自定义错误页面。

自定义错误页面

        Spring Boot 针对错误和异常处理提供自己的默认机制,并提供一个默认的映射/error,当处理中抛出异常之后,会转到该请求中处理,并且该请求有一个全局的错误页面来展示异常内容开发人员也可在此基础上定制化对错误和异常的处理。对于错误(如 404)和异常,Spring Boot 提供默认的错误页面, 并在错误页面显示错误消息和异常消息。

        默认的错误页面对用户来说并不友好,所以我们可以自定义错误页面。错误页面可以定义在以下位 置:

  1.  src/main/resources/static 目录下新建的 error 目录
  2.  src/main/resources/templates 目录下新建的 error 目录
  3.  src/main/resources/templates 目录下,但是页面名称必须是 error

        因为 Spring Boot 提供的 DefaultErrorViewResolver 定义了出现错误后跳转的视图,并按照特定顺序检 索以下目录,查找错误页面:

  1.  /templates/error/404.ftl       
  2.  /static/error/404.html
  3.  /templates/error/4xx.ftl
  4.  /static/error/4xx.html

        所以不管是在 static 目录下,还是 templates 目录下,需要新建 error 目录(或直接创建名为 error 的页 面作为错误页面),并将自定义错误页面放到 error 目录下,页面名称可以是具体的错误代码,如 404、405、500 等,这样发生对应类型的错误,将显示名称为该错误代码的页面作为错误页面,如发 生 404 错误,则显示 404.html、404.ftl(FreeMarker 模板页面)等页面。当然,我们也可以将页面命 名为 4xx.html、5xx.html、4xx.ftl、5xx.ftl,这样只要发生 4xx 类型的错误,如 400、404、405,则显 示名为 4xx 的页面,发生 5xx 类型错误,如 500、502 等,显示名称为 5xx 的页面作为错误页面。

        此外,如果同时定义了 404.html 和 4xx.html 页面,则发生 404 错误的时候,显示 404.html 页面,如 果发生除 404 之外的 4xx 错误,则显示 4xx.html 页面,也就是具体覆盖通用。如果同时在 static 目录 下和 templates 目录下为相同的错误代码定义了错误页面,则最终显示的是 templates 目录下的错误页 面,这是由其检索顺序决定的。

        至于将错误页面放在 static 目录下还是 templates 目录下,可根据需求决定,如果错误页面为静态页 面,放在 static 目录下即可,如果需要在错误页面上显示一些动态信息,可以将错误页面放在 templates 目录下。

        例如:这里5xx.html的代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <img th:src="@{/error/img.png}" width="100%" height="100%"/>
</body>
</html>

         运行后,刚才的错误页面就可以很优雅的显示了

 如果页面放在 templates 目录下,可以使用 Thymeleaf 的表达式在页面上显示异常信息,path、error、 message、timestamp 和 status 为发生异常时,添加的请求范围的属性:

         当然,如果不想使用固定目录 error,而是使用自定义的任意目录下的页面作为自定义错误页面,开 发 人 员 也 可 以 自 定 义 错 误 视 图 , 这 样 需 要 创 建 自 定 义 的 ErrorViewResolver 实 例 , 重 写 resolveErrorView()方法,使用返回的 ModelAndView 对象指定自定义错误页面所在的位置。 例如,如果在 src/main/resources/templates 目录下创建个目录 errpages,并新建一个 errorPage.html 页 面作为错误页面。则可以自定义 ErrorViewResolver 实现如下:

package com.alice.demo.config;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.springframework.boot.autoconfigure.web.servlet.error.ErrorViewResolver;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.ModelAndView;
@Component
public class MyErrorViewResolver implements ErrorViewResolver {
     @Override
     public ModelAndView resolveErrorView(HttpServletRequest request,
             HttpStatus status, Map<String, Object> model) {
         return new ModelAndView("/errpages/errorPage", model);
     }
}

        这里定义了一个 ErrorViewResolver 实现类 MyErrorViewResolver,并使用@Component 注册为 Spring 组件,这样该组件会被扫描并作为 ErrorViewResolver 替代默认的 DefaultErrorViewResolver 作为错误 视图解析器,当然如果想自定义错误属性,也可直接继承自 DefaultErrorViewResolver 类来创建自己 的 ErrorViewResolver 类。运行程序时,如果发生 4xx 错误或 5xx 错误,则显示 errpages 目录下的 errorPage.html 页面。

下一章:自定义异常处理器


版权声明:本文为shmily0300377原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。