当咱们的后端应用出现异常时,一般会将异常情况包装以后再返回给调用方或者前端,在实际的项目中,不可能对每个地方都作好异常处理,再优雅的代码也可能抛出异常,那么在 Spring 项目中,能够怎样优雅的处理这些异常呢?前端
本文将介绍一种全局异常处理方式,主要包括如下知识点java
右键查看原文: SpringBoot系列教程web篇之全局异常处理git
<!-- more -->github
首先得搭建一个 web 应用才有可能继续后续的测试,借助 SpringBoot 搭建一个 web 应用属于比较简单的活;web
建立一个 maven 项目,pom 文件以下spring
<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 依赖搞定以后,写一个程序入口json
/** * Created by @author yihui in 15:26 19/9/13. */ @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class); } }
咱们一般利用@ControllerAdvice
配合注解@ExceptionHandler
来实现全局异常捕获处理后端
@ControllerAdvice
为全部的 Controller 织入加强方法@ExceptionHandler
标记在方法上,表示当出现对应的异常抛出到上层时(即没有被业务捕获),这个方法会被触发下面咱们经过实例进行功能演示数组
咱们定义两个异常捕获的 case,一个是除 0,一个是数组越界异常websocket
@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); } }
在上面的测试中,咱们将异常堆栈返回调用方
增长几个测试方法
@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]; } }
实例测试以下,上面咱们声明捕获的两种异常被拦截并输出对应的堆栈信息;
可是须要注意
上面的 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); }
经过@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 被咱们捕获并返回堆栈信息
尽信书则不如,以上内容,纯属一家之言,因我的能力有限,不免有疏漏和错误之处,如发现 bug 或者有更好的建议,欢迎批评指正,不吝感激
下面一灰灰的我的博客,记录全部学习和工做中的博文,欢迎你们前去逛逛