博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
SpringBoot 之全局异常处理
阅读量:2456 次
发布时间:2019-05-10

本文共 7944 字,大约阅读时间需要 26 分钟。

文章目录

异常返回案例

一个简单的异常请求接口。

在这里插入图片描述
浏览器请求接口返回。
在这里插入图片描述

手动捕获异常信息

第一种解决方案:直接在请求的接口中采用try-catch的方式,手动捕获异常信息,然后返回对应的结果集。

在这里插入图片描述

全局异常处理

但是推荐使用SpringBoot提供的全局异常处理解决方案。

1、自定义一个异常类

public class CustomException extends RuntimeException {
private static final long serialVersionUID = 4564124491192825748L; private int code; public CustomException() {
super(); } public CustomException(int code, String message) {
super(message); this.setCode(code); } public int getCode() {
return code; } public void setCode(int code) {
this.code = code; }}

2、异常信息模板

定义返回的异常信息的格式,这样异常信息风格更为统一。

@Getter@Setter@AllArgsConstructorpublic class ErrorResponseEntity {
private int code; private String message;}

3、全局异常处理

创建一个 GlobalExceptionHandler 类,并添加上 @RestControllerAdvice 注解就可以定义出异常通知类了,然后在定义的方法中添加上 @ExceptionHandler 即可实现异常的捕捉。

import org.springframework.http.HttpHeaders;import org.springframework.http.HttpStatus;import org.springframework.http.ResponseEntity;import org.springframework.web.bind.MethodArgumentNotValidException;import org.springframework.web.bind.annotation.ExceptionHandler;import org.springframework.web.bind.annotation.RestControllerAdvice;import org.springframework.web.context.request.WebRequest;import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;@RestControllerAdvicepublic class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
/** * 定义要捕获的异常 可以多个 @ExceptionHandler({}) * * @param request request * @param e exception * @param response response * @return 响应结果 */ @ExceptionHandler(CustomException.class) public ErrorResponseEntity customExceptionHandler(HttpServletRequest request, final Exception e, HttpServletResponse response) {
response.setStatus(HttpStatus.BAD_REQUEST.value()); CustomException exception = (CustomException) e; return new ErrorResponseEntity(exception.getCode(), exception.getMessage()); } /** * 捕获 RuntimeException 异常 * TODO 如果你觉得在一个 exceptionHandler 通过 if (e instanceof xxxException) 太麻烦 * TODO 那么你还可以自己写多个不同的 exceptionHandler 处理不同异常 * * @param request request * @param e exception * @param response response * @return 响应结果 */ @ExceptionHandler(RuntimeException.class) public ErrorResponseEntity runtimeExceptionHandler(HttpServletRequest request, final Exception e, HttpServletResponse response) {
response.setStatus(HttpStatus.BAD_REQUEST.value()); RuntimeException exception = (RuntimeException) e; return new ErrorResponseEntity(400, exception.getMessage()); } /** * 通用的接口映射异常处理方 */ @Override protected ResponseEntity handleExceptionInternal(Exception ex, Object body, HttpHeaders headers, HttpStatus status, WebRequest request) {
if (ex instanceof MethodArgumentNotValidException) {
MethodArgumentNotValidException exception = (MethodArgumentNotValidException) ex; return new ResponseEntity<>(new ErrorResponseEntity(status.value(), exception.getBindingResult().getAllErrors().get(0).getDefaultMessage()), status); } if (ex instanceof MethodArgumentTypeMismatchException) {
MethodArgumentTypeMismatchException exception = (MethodArgumentTypeMismatchException) ex; logger.error("参数转换失败,方法:" + exception.getParameter().getMethod().getName() + ",参数:" + exception.getName() + ",信息:" + exception.getLocalizedMessage()); return new ResponseEntity<>(new ErrorResponseEntity(status.value(), "参数转换失败"), status); } return new ResponseEntity<>(new ErrorResponseEntity(status.value(), "参数转换失败"), status); }}

注解概述:

  • @ControllerAdvice 捕获 Controller 层抛出的异常,如果添加 @ResponseBody 返回信息则为JSON 格式。
  • @RestControllerAdvice 相当于 @ControllerAdvice@ResponseBody 的结合体。
  • @ExceptionHandler 统一处理一种类的异常,减少代码重复率,降低复杂度。

4、控制器

@GetMapping("/demo")public String demo(Integer num){
String result = "success"; if(null == num){
throw new CustomException(-1, "num不能为空"); } return result;}

5、浏览器请求接口返回

在这里插入图片描述
异常信息被处理返回,不在是一大堆异常堆栈信息了。

静态异常页面

自定义静态异常页面,又分为两种,第一种 是使用 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 中自带的异常处理器会自动查找到异常页面。

页面定义如下:

在这里插入图片描述
页面内容如下:

    
Title

5xx

path
error
message
timestamp
status

效果如下:

在这里插入图片描述
如果动态页面和静态页面同时定义了异常处理页面,例如 classpath:/static/error/404.htmlclasspath:/templates/error/404.html 同时存在时,默认使用动态页面。即完整的错误页面查找方式应该是这样:发生了500错误–>查找动态 500.html 页面–>查找静态 500.html –> 查找动态 5xx.html–>查找静态 5xx.html。

自定义异常数据

默认情况下,在Spring Boot 中,所有的异常数据定义在 org.springframework.boot.web.reactive.error.DefaultErrorAttributes 类中,具体定义在 getErrorAttributes 方法中 :

@Overridepublic Map
getErrorAttributes(ServerRequest request, boolean includeStackTrace) {
Map
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:

@Componentpublic class MyErrorAttributes  extends DefaultErrorAttributes {
@Override public Map
getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
Map
map = super.getErrorAttributes(webRequest, includeStackTrace); if ((Integer)map.get("status") == 500) {
map.put("message", "服务器内部错误!"); } return map; }}

效果如下:

在这里插入图片描述

自定义异常视图

默认异常视图就是前面所说的静态或者动态页面,这个异常视图是可以自定义的,默认的异常视图加载逻辑在 org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController 类的 errorHtml 方法中,这个方法用来返回异常页面+数据,还有另外一个 error 方法,这个方法用来返回异常数据(如果是 ajax 请求,则该方法会被触发)。

在这里插入图片描述
方法中通过 getErrorAttributes 方法去获取异常数据(实际上会调用到 ErrorAttributes 的实例的 getErrorAttributes 方法,默认实例是:DefaultErrorAttributes),然后调用 resolveErrorView 去创建一个 ModelAndView ,如果这里创建失败,那么用户将会看到默认的错误提示页面。

正常情况下, resolveErrorView 方法会来到 DefaultErrorViewResolver 类的 resolveErrorView 方法中:

在这里插入图片描述
在这里,首先以异常响应码作为视图名分别去查找动态页面和静态页面,如果没有查找到,则再以 4xx 或者 5xx 作为视图名再去分别查找动态或者静态页面。

要自定义异常视图解析,也很容易 ,由于 DefaultErrorViewResolver 是在 ErrorMvcAutoConfiguration 类中提供的实例,即开发者没有提供相关实例时,会使用默认的 DefaultErrorViewResolver ,开发者提供了自己的 ErrorViewResolver 实例后,默认的配置就会失效,因此,自定义异常视图,只需要提供 一个 ErrorViewResolver 的实例即可:

@Componentpublic class MyErrorViewResolver extends DefaultErrorViewResolver {
public MyErrorViewResolver(ApplicationContext applicationContext, ResourceProperties resourceProperties) {
super(applicationContext, resourceProperties); } @Override public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map
model) {
return new ModelAndView("/aaa/123", model); }}

转载地址:http://bgdhb.baihongyu.com/

你可能感兴趣的文章
初学者应该学c++与c#_面向初学者的完整C#课程
查看>>
vue.js快速入门_Vue.js快速介绍
查看>>
web前端的发展简史_前端框架简史
查看>>
bug探索_探索一流功能的力量
查看>>
如何避免您的网站在Twitter和Facebook上的可耻外观
查看>>
导入样机_如何开始构建Android应用程序:创建样机,UI和XML布局
查看>>
最先进的深度学习:Mask R-CNN简介
查看>>
如何快速设置您的ES6环境
查看>>
深圳哪个区的it工作多_如何创建虚拟IT工作区
查看>>
组件和高阶组件区别_高阶组件:终极指南
查看>>
如何知道Kubernetes是否适合您的SaaS
查看>>
apollo调试工具_GraphQL工具包Apollo的完整介绍
查看>>
函数编程代码例子_使用函数式编程使代码更易于阅读
查看>>
文件从头开始读函数_这是您可以从头开始编写的一些函数修饰符
查看>>
JavaScript中的pipe()和compose()快速介绍
查看>>
react中的状态机_使用状态机增强您的React
查看>>
ruby 数组删除部分数组_您需要了解的六个Ruby数组方法
查看>>
roro cam_现代JavaScript中的优雅图案:RORO
查看>>
React Router v4简介及其对路由的哲学
查看>>
程序自动化 linux_自动化Windows子系统Linux安装程序
查看>>