SpringBoot系列教程web篇之全局异常处理
2019-10-11 18:36
429 查看
当我们的后端应用出现异常时,通常会将异常状况包装之后再返回给调用方或者前端,在实际的项目中,不可能对每一个地方都做好异常处理,再优雅的代码也可能抛出异常,那么在 Spring 项目中,可以怎样优雅的处理这些异常呢?
本文将介绍一种全局异常处理方式,主要包括以下知识点
- @ControllerAdvice Controller 增强
- @ExceptionHandler 异常捕获
- @ResponseStatus 返回状态码
- NoHandlerFoundException 处理(404 异常捕获)
右键查看原文: SpringBoot系列教程web篇之全局异常处理
I. 环境搭建
首先得搭建一个 web 应用才有可能继续后续的测试,借助 SpringBoot 搭建一个 web 应用属于比较简单的活;
创建一个 maven 项目,pom 文件如下
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.7</version> <relativePath/> <!-- lookup parent from update --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <spring-cloud.version>Finchley.RELEASE</spring-cloud.version> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.45</version> </dependency> </dependencies> <build> <pluginManagement> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </pluginManagement> </build> <repositories> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories>
依然是一般的流程,pom 依赖搞定之后,写一个程序入口
/** * Created by @author yihui in 15:26 19/9/13. */ @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class); } }
II. 异常处理
1. @ControllerAdvice
我们通常利用
@ControllerAdvice配合注解
@ExceptionHandler来实现全局异常捕获处理
@ControllerAdvice
为所有的 Controller 织入增强方法@ExceptionHandler
标记在方法上,表示当出现对应的异常抛出到上层时(即没有被业务捕获),这个方法会被触发
下面我们通过实例进行功能演示
a. 异常捕获
我们定义两个异常捕获的 case,一个是除 0,一个是数组越界异常
@Slf4j @ControllerAdvice public class GlobalExceptionHandler { public static String getThrowableStackInfo(Throwable e) { ByteArrayOutputStream buf = new ByteArrayOutputStream(); e.printStackTrace(new java.io.PrintWriter(buf, true)); String msg = buf.toString(); try { buf.close(); } catch (Exception t) { return e.getMessage(); } return msg; } @ResponseBody @ExceptionHandler(value = ArithmeticException.class) public String handleArithmetic(HttpServletRequest request, HttpServletResponse response, ArithmeticException e) throws IOException { log.info("divide error!"); return "divide 0: " + getThrowableStackInfo(e); } @ResponseBody @ExceptionHandler(value = ArrayIndexOutOfBoundsException.class) public String handleArrayIndexOutBounds(HttpServletRequest request, HttpServletResponse response, ArrayIndexOutOfBoundsException e) throws IOException { log.info("array index out error!"); return "aryIndexOutOfBounds: " + getThrowableStackInfo(e); } }
在上面的测试中,我们将异常堆栈返回调用方
b. 示例服务
增加几个测试方法
@Controller @RequestMapping(path = "page") public class ErrorPageRest { @ResponseBody @GetMapping(path = "divide") public int divide(int sub) { return 1000 / sub; } private int[] ans = new int[]{1, 2, 3, 4}; @ResponseBody @GetMapping(path = "ary") public int ary(int index) { return ans[index]; } }
c. 测试说明
实例测试如下,上面我们声明捕获的两种异常被拦截并输出对应的堆栈信息;
但是需要注意
- 404 和未捕获的 500 异常则显示的 SpringBoot 默认的错误页面;
- 此外我们捕获返回的 http 状态码是 200
2. @ResponseStatus
上面的 case 中捕获的异常返回的状态码是 200,但是在某些 case 中,可能更希望返回更合适的 http 状态码,此时可以使用
ResponseStatus来指定
使用方式比较简单,加一个注解即可
@ResponseBody @ExceptionHandler(value = ArithmeticException.class) @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public String handleArithmetic(HttpServletRequest request, HttpServletResponse response, ArithmeticException e) throws IOException { log.info("divide error!"); return "divide 0: " + getThrowableStackInfo(e); }
3. 404 处理
通过
@ControllerAdvice配合
@ExceptionHandler可以拦截 500 异常,如果我希望 404 异常也可以拦截,可以如何处理?
首先修改配置文件
application.properties,将
NoHandlerFoundException抛出来
# 出现错误时, 直接抛出异常 spring.mvc.throw-exception-if-no-handler-found=true # 设置静态资源映射访问路径,下面两个二选一, spring.mvc.static-path-pattern=/statics/** # spring.resources.add-mappings=false
其次是定义异常捕获
@ResponseBody @ExceptionHandler(value = NoHandlerFoundException.class) @ResponseStatus(HttpStatus.NOT_FOUND) public String handleNoHandlerError(NoHandlerFoundException e, HttpServletResponse response) { return "noHandlerFound: " + getThrowableStackInfo(e); }
再次测试如下,404 被我们捕获并返回堆栈信息
II. 其他
0. 项目
web 系列博文
- 190930-SpringBoot 系列教程 web 篇之 404、500 异常页面配置
- 190929-SpringBoot 系列教程 web 篇之重定向
- 190913-SpringBoot 系列教程 web 篇之返回文本、网页、图片的操作姿势
- 190905-SpringBoot 系列教程 web 篇之中文乱码问题解决
- 190831-SpringBoot 系列教程 web 篇之如何自定义参数解析器
- 190828-SpringBoot 系列教程 web 篇之 Post 请求参数解析姿势汇总
- 190824-SpringBoot 系列教程 web 篇之 Get 请求参数解析姿势汇总
- 190822-SpringBoot 系列教程 web 篇之 Beetl 环境搭建
- 190820-SpringBoot 系列教程 web 篇之 Thymeleaf 环境搭建
- 190816-SpringBoot 系列教程 web 篇之 Freemaker 环境搭建
- 190421-SpringBoot 高级篇 WEB 之 websocket 的使用说明
- 190327-Spring-RestTemplate 之 urlencode 参数解析异常全程分析
- 190317-Spring MVC 之基于 java config 无 xml 配置的 web 应用构建
- 190316-Spring MVC 之基于 xml 配置的 web 应用构建
- 190213-SpringBoot 文件上传异常之提示 The temporary upload location xxx is not valid
项目源码
- 工程:https://github.com/liuyueyi/spring-boot-demo
- 项目:https://github.com/liuyueyi/spring-boot-demo/tree/master/spring-boot/209-web-error
1. 一灰灰 Blog
尽信书则不如,以上内容,纯属一家之言,因个人能力有限,难免有疏漏和错误之处,如发现 bug 或者有更好的建议,欢迎批评指正,不吝感激
下面一灰灰的个人博客,记录所有学习和工作中的博文,欢迎大家前去逛逛
- 一灰灰 Blog 个人博客 https://blog.hhui.top
- 一灰灰 Blog-Spring 专题博客 http://spring.hhui.top
相关文章推荐
- SpringBoot系列教程web篇之自定义异常处理HandlerExceptionResolver
- SpringBoot2.0系列教程(五)Springboot框架添加全局异常处理
- spring boot教程之全局处理异常封装
- SpringBoot系列五:SpringBoot错误处理(数据验证、处理错误页、全局异常)
- SpringBoot2.x系列第七章 (全局异常处理)
- spring boot学习教程(4):全局异常处理代码demo
- SpringBoot系列之三全局异常的捕获处理
- Spring Boot干货系列:(十三)Spring Boot全局异常处理整理
- SpringBoot系列教程web篇之过滤器Filter使用指南扩展篇
- spring boot 教程(四) 统一异常处理
- SpringBoot2.0 基础案例(03):配置系统全局异常映射处理
- Spring Boot教程九:捕获全局异常(二)
- Spring-Boot--日志操作【全局异常捕获消息处理☞日志控制台输出+日志文件记录】
- SpringBoot之全局异常处理
- Spring Boot - 全局异常处理
- spring boot 全局异常处理方法汇总
- Spring Boot 系列@ControllerAdvice 拦截异常并统一处理
- spring boot之全局异常处理代码demo
- Spring Boot @ControllerAdvice 处理全局异常,返回固定格式Json
- springboot结合全局异常处理之登录注册验证