一、背景

在我们编写程序的过程中,程序中可能随时发生各种异常,那么我们如何优雅的处理各种异常呢?

二、需求

1、拦截系统中部分异常,返回自定义的响应。

比如:

系统发生HttpRequestMethodNotSupportedException异常,我们需要返回如下信息。

http的状态码:返回 405

{
code: 自定义异常码,
message: 错误消息
}

2、实现自定义异常的拦截

拦截我们自己写的 BizException

三、编写一些异常基础代码

1、引入jar包

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
</dependencies>

注意:

引入spring-boot-starter-validation是为了验证请求的中的参数,然后当参数不满足时抛出异常。

2、定义一个自定义异常

public class BizException extends RuntimeException {
public BizException() {
}
public BizException(String message) {
super(message);
}
public BizException(String message, Throwable cause) {
super(message, cause);
}
public BizException(Throwable cause) {
super(cause);
}
public BizException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}

3、编写一个简单的控制层

@RestController
@RequestMapping("exception")
public class ExceptionTestController { static class Req {
@NotBlank
public String password;
} @PostMapping("password")
public String checkPassword(@Validated @RequestBody Req req) { if (Objects.equals(req.password, "exception")) {
throw new BizException("密码传递的是exception字符串");
} return "当前密码,password: " + req.password;
}
}

解释

提供一个 /exception/password api,需要传递一个password参数

1、当不传递 password 参数时将抛出MethodArgumentNotValidException异常。

2、当password传递exception参数时,则抛出BizException异常。

4、测试

1、不传递password参数响应是什么

1、使用默认的DefaultHandlerExceptionResolver处理

这个类DefaultHandlerExceptionResolver是默认自动配置的。



从上图中可以看出有一个默认字段的返回值

2、使用ResponseEntityExceptionHandler处理

1、编写异常处理代码-使用默认的逻辑
@RestControllerAdvice
public class RestExceptionHandler extends ResponseEntityExceptionHandler { @Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
// 此处自定义返回值
return super.handleMethodArgumentNotValid(ex, headers, status, request);
}
}

可以看到handleMethodArgumentNotValid方法直接调用父类的方法,即使用默认的处理方式。

从上图中可以看出返回值是空

2、编写异常处理代码-返回值返回自定义内容
@Component
@RestControllerAdvice
public class RestExceptionHandler extends ResponseEntityExceptionHandler {
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
// 此处自定义返回值
return super.handleMethodArgumentNotValid(ex, headers, status, request);
} @Override
protected ResponseEntity<Object> handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
Set<HttpMethod> supportedMethods = ex.getSupportedHttpMethods(); // 自定义请求返回值
Map<String, Object> body = new HashMap<>(4);
body.put("code", "错误码");
body.put("message", "当前请求的方法不支持,支持的请求方法为:" + supportedMethods); return new ResponseEntity<>(body, headers, status);
}
}

由上面的代码可知handleHttpRequestMethodNotSupported方法返回了自定义的body。



从上图中可以看出,返回了我们自己定义的返回值。

2、password参数传递exception

1、使用ResponseEntityExceptionHandler或DefaultHandlerExceptionResolver处理



由上图可知返回结果不对,我们需要自定义返回结果。

2、返回自定义异常

1、编写BizException处理代码
@RestControllerAdvice
public class BizExceptionHandler { @ExceptionHandler(BizException.class)
public ResponseEntity<Object> handleBizException(BizException exception) {
// 自定义请求返回值
Map<String, Object> body = new HashMap<>(4);
body.put("code", "错误码");
body.put("message", "异常信息为:" + exception.getMessage());
return new ResponseEntity<>(body, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
2、测试返回结果



从上图可知返回了自定义信息

四、注意事项

1、如果实现自定义异常处理

  1. 类上使用@RestControllerAdvice注解
  2. 方法上使用@ExceptionHandler来处理特定的异常

2、ResponseEntityExceptionHandler默认处理那些异常

3、使用了ResponseEntityExceptionHandler后,为什么发生了异常后返回体为空



默认情况下,实现了 ResponseEntityExceptionHandler这个类后,这个类处理的所有异常的响应结果都是 null,如果想返回别的值需要我们自己去处理。

五、总结

1、如果我们想处理自定义异常,则可以使用 @RestControllerAdvice || @ControllerAdvice 配置@ExceptionHandler来使用。

2、如果我们实现了ResponseEntityExceptionHandler来处理异常,那么默认的异常的响应结果为空,如果想不为空,则需要我们自己处理。

3、默认情况下,标准的Spring MVC异常会通过DefaultHandlerExceptionResolver来处理。

六、代码实现

https://gitee.com/huan1993/spring-cloud-parent/tree/master/springboot/springboot-exception-handler

七、参考文档

SpringBoot中异常处理的更多相关文章

  1. SpringBoot学习笔记(5)----SpringBoot中异常处理的三种方法

    对于异常的处理,Spring Boot中提供默认的一个异常处理界面,如下图: 但是在实际的运用开发中,这样的页面显然是不友好的,Spring Boot也提供了自定义异常处理的方式,如下总结三种一场处理 ...

  2. SpringBoot中对于异常处理的提供的五种处理方式

    1.自定义错误页面 SpringBoot 默认的处理异常机制:SpringBoot默认的已经提供了一套处理异常的机制.一旦程序中出现了异常,SpringBoot会向/error的url发送请求.在Sp ...

  3. SpringBoot中的全局异常处理

    SpringBoot中的全局异常处理 本篇要点 介绍SpringBoot默认的异常处理机制. 如何定义错误页面. 如何自定义异常数据. 如何自定义视图解析. 介绍@ControllerAdvice注解 ...

  4. SpringBoot中的异常处理方式

    SpringBoot中有五种处理异常的方式: 一.自定义错误页面 SpringBoot默认的处理异常机制:SpringBoot默认的已经提供了一套处理异常的机制.一旦程序出现了异常SpringBoot ...

  5. SpringBoot(四)SpringBoot中lombok使用

    lombok概述 lombok简介 Lombok想要解决了的是在我们实体Bean中大量的Getter/Setter方法,以及toString, hashCode等可能不会用到,但是某些时候仍然需要复写 ...

  6. Springboot的异常处理与自定义异常

    园友们好,元旦很快就到来了,提前祝各位园友们元旦快乐,今天给大家分享一个工作中必用一个知识点,就是使用枚举构建自定义异常并应用于springboot的异常处理器.开始之前我先把这个案例的结构大致说明一 ...

  7. SpringBoot 统一异常处理

    统一异常处理: @ControllerAdvice public class GlobalExceptionHandler { private Logger logger = LoggerFactor ...

  8. spring 或 springboot统一异常处理

    spring 或 springboot统一异常处理https://blog.csdn.net/xzmeasy/article/details/76150370 一,本文介绍spring MVC的自定义 ...

  9. SpringBoot exception异常处理机制源码解析

    一.Spring Boot默认的异常处理机制 1:浏览器默认返回效果 2:原理解析 为了便于源码跟踪解析,在·Controller中手动设置异常. @RequestMapping(value=&quo ...

随机推荐

  1. 文档类型声明<!DOCTYPE html>

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/ ...

  2. Linux用户身份与文件权限学习笔记

    用户身份 管理员UID为0:系统的管理员用户 系统用户UID为1~999:服务程序会有独立的系统用户负责运行:防止被黑客入侵进行提权,并有效控制被破坏的范围 普通用户UID从1000开始:是由管理员创 ...

  3. PRODUCER配置加载

    1.入口 Kafka通过new一个KafkaProducer将配置项进行加载.将用户定义的properties作为参数,构造成一个ProducerConfig对象. public KafkaProdu ...

  4. “a==b”和”a.equals(b)”有什么区别?

    如果 a 和 b 都是对象,则 a==b 是比较两个对象的引用,只有当 a 和 b 指 向的是堆中的同一个对象才会返回 true,而 a.equals(b) 是进行逻辑比较,所以 通常需要重写该方法来 ...

  5. 线程 B 怎么知道线程 A 修改了变量?

    1.volatile 修饰变量 2.synchronized 修饰修改变量的方法 3.wait/notify 4.while 轮询

  6. 让弹幕给 PPD 生个孩子

    怎样才能跑起来我写的弹幕程序 资源下载 申请野狗后端云账号注册 创建应用: 复制appId到index.html的 var ref = new Wilddog("https://<ap ...

  7. Episode 3:我们想要更好的社交网络

    我们为什么爱看评论?怎样的人类文字最有效率?更「好」的手机设计.APP 设计?APP Store 已经十年了?这是 WEB VIEW 的第三期节目<我们想要更好的社交网络>. 链接描述 s ...

  8. python-查找鞍点

    [题目描述]对于给定5X5的整数矩阵,设计算法查找出所有的鞍点的信息(包括鞍点的值和行.列坐标,坐标从1开始). 提示:鞍点的特点:列上最小,行上最大.   [练习要求]请给出源代码程序和运行测试结果 ...

  9. 记住用户名和登录密码+虚拟机没有root权限解决办法

    今日所学: 记住用户名和登录密码 用adb查看保存文件内容 如何使用adb 如何安装adb-百度经验 遇到的问题: 用adb查看文件时,没有权限访问data文件 出现原因:google play虚拟机 ...

  10. Django实现统一包装接口返回值数据格式

    前言 最近实在太忙了,开始了一个新的项目,为了快速形成产品,我选择了Django来实现后端,然后又拿起了之前我封装了项目脚手架「DjangoStarter」. 由于前段时间我写了不少.NetCore的 ...