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的代码,十分方便。


五. 源码和文档


源码下载:



相关文章
|
4月前
|
Java 数据格式 Spring
SpringBoot统一功能处理(统⼀⽤户登录权限验证、统⼀异常处理、统⼀数据格式封装)
SpringBoot统一功能处理(统⼀⽤户登录权限验证、统⼀异常处理、统⼀数据格式封装)
|
9月前
|
存储 运维 Java
SpringBoot 统一异常处理(附核心工具类-ErrorInfoBuilder) 1
SpringBoot 统一异常处理(附核心工具类-ErrorInfoBuilder)
|
9月前
|
前端开发 JavaScript Java
SpringBoot 统一功能处理:用户登录权限校验-拦截器、异常处理、数据格式返回
本篇将要学习 Spring Boot 统一功能处理模块,这也是 AOP 的实战环节 用户登录权限的校验实现接口 HandlerInterceptor + WebMvcConfigurer 异常处理使用注解 @RestControllerAdvice + @ExceptionHandler 数据格式返回使用注解 @ControllerAdvice 并且实现接口 @ResponseBodyAdvice
333 0
|
9月前
|
JSON 前端开发 JavaScript
SpringBoot整合【全局异常处理+错误码枚举+JSR303校验】
本文介绍了如何使用Spring Boot整合全局异常处理、错误码枚举和JSR 303校验。全局异常处理通过@ControllerAdvice和@ExceptionHandler注解实现,提供了统一处理异常的机制。错误码枚举用于管理和传递错误信息,将错误信息与错误码进行映射,提高异常情况的定义和管理。JSR 303校验通过注解定义验证规则,并使用@Valid注解进行数据校验,确保请求数据的有效性。通过这些技术的应用,能够提升应用程序的异常处理和数据验证能力,提高应用程序的健壮性和用户体验。
439 2
|
11月前
|
消息中间件 JavaScript 小程序
SpringBoot 统一功能处理:用户登录权限校验-拦截器、异常处理、数据格式返回 下
SpringBoot 统一功能处理:用户登录权限校验-拦截器、异常处理、数据格式返回 下
SpringBoot 统一功能处理:用户登录权限校验-拦截器、异常处理、数据格式返回 下
|
11月前
|
JavaScript 前端开发 小程序
SpringBoot 统一功能处理:用户登录权限校验-拦截器、异常处理、数据格式返回 上
SpringBoot 统一功能处理:用户登录权限校验-拦截器、异常处理、数据格式返回 上
|
JSON 数据安全/隐私保护 数据格式
SpringBoot中的异常处理与参数校验_2
  兄弟们好,这次来跟老铁交流两个问题,异常和参数校验,在说参数校验之前我们先来说异常处理吧,因为后面参数的校验会牵扯到异常处理这块的内容。   说到异常处理,我不知道大家有没有写过或者遇到过如下的写法。
207 0
|
JSON Java 应用服务中间件
【SpringBoot 2】(九)异常处理 web原生组件的注入
【SpringBoot 2】(九)异常处理 web原生组件的注入
109 0
【SpringBoot 2】(九)异常处理 web原生组件的注入
|
Java 计算机视觉 前端开发
Springboot三部曲之Controller统一异常处理
SpringBoot整理的最后一块内容,Controller统一异常处理。 Controller的异常处理应该由开发组长来定义,这样再遇到问题的时候,不需要再使用if或者try等模块来对代码进行返回规范和日志记录,这类公共内容和经常进行CV编程的代码,应该统一起来,让开发人员随时随地,遇到业务无法执行的时候抛出业务异常即可,无需再次编写返回实体,这里就体现出Controller统一返回的好处了,要是不统一返回,那么异常处理的时候也没办法保证返回的内容是前端同事可以看懂的。
6833 0
|
Java
SpringBoot 统一异常处理\统一响应报文\自定义异常
SpringBoot 统一异常处理\统一响应报文\自定义异常
286 0