SpringBoot 统一异常处理(附核心工具类-ErrorInfoBuilder) 2

简介: SpringBoot 统一异常处理(附核心工具类-ErrorInfoBuilder)

5. 页面代码(Thymeleaf)


代码完成之后,我们需要编写一个异常信息页面。为了方便演示,我们在resources目录下创建templates目录,并新建文件exception.html。页面代码如下:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>GlobalError</title>
</head>
<h1>统一祖国 振兴中华</h1>
<h2>服务异常,请稍后再试。</h2>
<div th:object="${errorInfo}">
    <h3 th:text="*{'发生时间:'+time}"></h3>
    <h3 th:text="*{'访问地址:'+url}"></h3>
    <h3 th:text="*{'问题类型:'+error}"></h3>
    <h3 th:text="*{'通信状态:'+statusCode+','+reasonPhrase}"></h3>
    <h3 th:text="*{'堆栈信息:'+stackTrace}"></h3>
</div>
</body>
</html>


注:SpringBoot默认支持很多种模板引擎(如Thymeleaf、FreeMarker),并提供了相应的自动配置,做到开箱即用。默认的页面加载路径是 src/main/resources/templates ,如果放到其它目录需在配置文件指定。(举例:spring.thymeleaf.prefix=classpath:/views/  )


6. 引入依赖(POM文件)


以前操作之前,不要忘了在pom.xml 引入相关依赖:

<?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.hehe</groupId>
    <artifactId>springboot-error-handler</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>
    <name>spring-boot-error-handler</name>
    <description>SpringBoot 统一异常处理</description>
    <!--继承信息 -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.0.M4</version>
        <relativePath/>
    </parent>
    <!--依赖管理 -->
    <dependencies>
        <dependency> <!--添加Web依赖 -->
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency> <!--添加Thymeleaf依赖 -->
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency><!--添加Test依赖 -->
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <!--指定远程仓库(含插件)-->
    <repositories>
        <repository>
            <id>spring-snapshots</id>
            <url>http://repo.spring.io/snapshot</url>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </repository>
        <repository>
            <id>spring-milestones</id>
            <url>http://repo.spring.io/milestone</url>
        </repository>
    </repositories>
    <pluginRepositories>
        <pluginRepository>
            <id>spring-snapshots</id>
            <url>http://repo.spring.io/snapshot</url>
        </pluginRepository>
        <pluginRepository>
            <id>spring-milestones</id>
            <url>http://repo.spring.io/milestone</url>
        </pluginRepository>
    </pluginRepositories>
    <!--构建插件 -->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>


7. 开始测试


上述步骤完成之后,打开启动类GlobalExceptionApplication,启动项目然后进行测试。本案例-项目结构图如下:



测试效果:在浏览器输入 http://localhost:8080  多次按F5刷新,然后查看页面效果。截图如下:


三. 使用@ExceptionHandler的不足之处


关于实现Web应用统一异常处理的两种方法比较:


特性 @ExceptionHandler ErrorController
获取异常 通过方法参数注入 通过ErrorInfoBuilder获取
返回类型 若请求的类型为Ajax则返回JSON,否则返回页面. 若请求的媒介类型为HTML 则返回页面 ,否则返回JSON.
缺点 无法处理404类异常 很强大,可处理全部错误/异常


1. 使用@ExceptionHandler 为什么无法处理404错误/异常?


  • 答:因为SpringMVC优先处理(Try Catch)掉了资源映射不存在的404类错误/异常,虽然在响应信息注入了404的HttpStatus通信信息,但木有了异常,肯定不会进入@ExceptionHandler 的处理逻辑。


2. 使用@ExceptionHandler  + 抛出异常 是否可取?


  • 答:由上图可知@ExceptionHanlder的最大不足之处是无法直接捕获404背后的异常,网上流传通过取消资源目录映射来解决无404问题是不可取的,属于越俎代庖的做法。
spring.mvc.throw-exception-if-no-handler-found=true
spring.resources.add-mappings=false


3. 为什么推荐ErrorController 替代 @ExceptionHandler  ?


  • 使用ErrorController可以处理 全部错误/异常 。
  • 使用ErrorController+ErrorInfoBuilder 在单个方法里面可以针对不同的Exception来添加详细的错误信息,具体做法:拓展ErrorInfoBuilder的getErrorInfo方法来添加错误信息(例如:ex instanceof NullPointerException Set xxx)。

注意:实际上,目前SpringBoot官方就是通过ErrorController来做的统一错误/异常处理,但遗憾的是,关于这方面的官方文档并没有给出详细示例,仅仅是一笔带过,大概官方认为@ExceptionHandler  够用??而网上也甚少人具体提及ErrorController和ErrorAttribute 背后一整套的实现逻辑,也正是如此,促使楼主决心写下这篇文章,希望给大家带来帮助,少走一些弯路!!


四. 使用ErrorController替代@ExceptionHandler


4. 如何快速使用 ErrorController ?


回答:经过楼主的精心设计,ErrorInfoBuilder 可以无缝对接ErrorController (即上述两种错误/异常处理均共用此工具类),你只需要做的是:将本案例的ErrorInfo和ErrorInfoBuilder 拷贝进项目,简单编写ErrorController 跳转页面和返回JSON即可。具体如下:


  • @RequestMapping(produces = MediaType.TEXT_HTML_VALUE)


说明:produces属性作为匹配规则:表示Request请求的Accept头部需含有text/html。

用途:text/html 主要用于响应普通的页面请求,与AJAX请求作为区分。

package com.hehe.error;
@Controller
@RequestMapping("${server.error.path:/error}")
public class GlobalErrorController implements ErrorController {
@Autowired
    private ErrorInfoBuilder errorInfoBuilder;//错误信息的构建工具.
    private final static String DEFAULT_ERROR_VIEW = "error";//错误信息页
    /**
     * 情况1:若预期返回类型为text/html,则返回错误信息页(View).
     */
    @RequestMapping(produces = MediaType.TEXT_HTML_VALUE)
    public ModelAndView errorHtml(HttpServletRequest request) {
        return new ModelAndView(DEFAULT_ERROR_VIEW, "errorInfo", errorInfoBuilder.getErrorInfo(request));
    }
    /**
     * 情况2:其它预期类型 则返回详细的错误信息(JSON).
     */
    @RequestMapping
    @ResponseBody
    public ErrorInfo error(HttpServletRequest request) {
        return errorInfoBuilder.getErrorInfo(request);
    }
    @Override
    public String getErrorPath() {//获取映射路径
        return errorInfoBuilder.getErrorProperties().getPath();
    }
}


注:是不是非常简单,相信这个工具类可以改变你对ErrorController复杂难用的看法。如果后续想拓展不同种类的错误/异常信息,只需修改ErrorInfoBuilder#getError方法即可,无需修改ErrorController的代码,十分方便。


五. 源码和文档


源码下载:



相关文章
|
7月前
|
Java 开发者 UED
Spring Boot的全局异常处理机制
【2月更文挑战第13天】
409 0
|
存储 JSON 前端开发
SpringBoot + Vue前后端分离开发:全局异常处理及统一结果封装
SpringBoot + Vue前后端分离开发:全局异常处理及统一结果封装的实现
1110 0
SpringBoot + Vue前后端分离开发:全局异常处理及统一结果封装
|
7月前
|
前端开发 Java 程序员
Spring Boot统一功能处理(拦截器, 统一数据返回格式, 统一异常处理)
Spring Boot统一功能处理(拦截器, 统一数据返回格式, 统一异常处理)
132 1
|
存储 运维 Java
SpringBoot 统一异常处理(附核心工具类-ErrorInfoBuilder) 1
SpringBoot 统一异常处理(附核心工具类-ErrorInfoBuilder)
|
7月前
|
Java 数据格式 Spring
SpringBoot统一功能处理(统⼀⽤户登录权限验证、统⼀异常处理、统⼀数据格式封装)
SpringBoot统一功能处理(统⼀⽤户登录权限验证、统⼀异常处理、统⼀数据格式封装)
|
前端开发 JavaScript Java
SpringBoot 统一功能处理:用户登录权限校验-拦截器、异常处理、数据格式返回
本篇将要学习 Spring Boot 统一功能处理模块,这也是 AOP 的实战环节 用户登录权限的校验实现接口 HandlerInterceptor + WebMvcConfigurer 异常处理使用注解 @RestControllerAdvice + @ExceptionHandler 数据格式返回使用注解 @ControllerAdvice 并且实现接口 @ResponseBodyAdvice
800 0
|
消息中间件 JavaScript 小程序
SpringBoot 统一功能处理:用户登录权限校验-拦截器、异常处理、数据格式返回 下
SpringBoot 统一功能处理:用户登录权限校验-拦截器、异常处理、数据格式返回 下
SpringBoot 统一功能处理:用户登录权限校验-拦截器、异常处理、数据格式返回 下
|
安全 Java 微服务
SpringBoot 中如何优雅地处理异常,包括异常处理机制、全局异常处理器、自定义异常?
SpringBoot 中如何优雅地处理异常,包括异常处理机制、全局异常处理器、自定义异常?
317 0
|
JavaScript 前端开发 小程序
SpringBoot 统一功能处理:用户登录权限校验-拦截器、异常处理、数据格式返回 上
SpringBoot 统一功能处理:用户登录权限校验-拦截器、异常处理、数据格式返回 上
|
Java 计算机视觉 前端开发
Springboot三部曲之Controller统一异常处理
SpringBoot整理的最后一块内容,Controller统一异常处理。 Controller的异常处理应该由开发组长来定义,这样再遇到问题的时候,不需要再使用if或者try等模块来对代码进行返回规范和日志记录,这类公共内容和经常进行CV编程的代码,应该统一起来,让开发人员随时随地,遇到业务无法执行的时候抛出业务异常即可,无需再次编写返回实体,这里就体现出Controller统一返回的好处了,要是不统一返回,那么异常处理的时候也没办法保证返回的内容是前端同事可以看懂的。
6973 0