最近学习Spring时,认识到Spring异常处理的强大。之前处理工程异常,代码中最常见的就是try-catch-finally,有时一个try,多个catch,覆盖了核心业务逻辑:

1 try{
2 ..........
3 }catch(Exception1 e){
4 ..........
5 }catch(Exception2 e){
6 ...........
7 }catch(Exception3 e){
8 ...........
9 }

Spring能够较好的处理这种问题,核心如下,文章主要关注前两个:

  • @ExceptionHandler:统一处理某一类异常,从而能够减少代码重复率和复杂度
  • @ControllerAdvice:异常集中处理,更好的使业务逻辑与异常处理剥离开
  • @ResponseStatus:可以将某种异常映射为HTTP状态码

@ExceptionHandler

源码如下:

1 @Target({ElementType.METHOD})
2 @Retention(RetentionPolicy.RUNTIME)
3 @Documented
4 public @interface ExceptionHandler {
5 Class<? extends Throwable>[] value() default {};
6 }

该注解作用对象为方法,并且在运行时有效,value()可以指定异常类。由该注解注释的方法可以具有灵活的输入参数(详细参见Spring API):

  • 异常参数:包括一般的异常或特定的异常(即自定义异常),如果注解没有指定异常类,会默认进行映射。
  • 请求或响应对象 (Servlet API or Portlet API): 你可以选择不同的类型,如ServletRequest/HttpServletRequest或PortleRequest/ActionRequest/RenderRequest
  • Session对象(Servlet API or Portlet API): HttpSession或PortletSession。
  • WebRequest或NativeWebRequest
  • Locale
  • InputStream/Reader
  • OutputStream/Writer
  • Model

方法返回值可以为:

  • ModelAndView对象
  • Model对象
  • Map对象
  • View对象
  • String对象
  • 还有@ResponseBody、HttpEntity<?>或ResponseEntity<?>,以及void

@ControllerAdvice

源码如下:

 1 @Target({ElementType.TYPE})
2 @Retention(RetentionPolicy.RUNTIME)
3 @Documented
4 @Component
5 public @interface ControllerAdvice {
6 @AliasFor("basePackages")
7 String[] value() default {};
8
9 @AliasFor("value")
10 String[] basePackages() default {};
11
12 Class<?>[] basePackageClasses() default {};
13
14 Class<?>[] assignableTypes() default {};
15
16 Class<? extends Annotation>[] annotations() default {};
17 }

该注解作用对象为TYPE,包括类、接口和枚举等,在运行时有效,并且可以通过Spring扫描为bean组件。其可以包含由@ExceptionHandler、@InitBinder 和@ModelAttribute标注的方法,可以处理多个Controller类,这样所有控制器的异常可以在一个地方进行处理。

实例

异常类:

 1 public class CustomGenericException extends RuntimeException{
2 private static final long serialVersionUID = 1L;
3
4 private String errCode;
5 private String errMsg;
6
7 public String getErrCode() {
8 return errCode;
9 }
10
11 public void setErrCode(String errCode) {
12 this.errCode = errCode;
13 }
14
15 public String getErrMsg() {
16 return errMsg;
17 }
18
19 public void setErrMsg(String errMsg) {
20 this.errMsg = errMsg;
21 }
22
23 public CustomGenericException(String errCode, String errMsg) {
24 this.errCode = errCode;
25 this.errMsg = errMsg;
26 }
27 }

控制器:

 1 @Controller
2 @RequestMapping("/exception")
3 public class ExceptionController {
4
5 @RequestMapping(value = "/{type}", method = RequestMethod.GET)
6 public ModelAndView getPages(@PathVariable(value = "type") String type) throws Exception{
7 if ("error".equals(type)) {
8 // 由handleCustomException处理
9 throw new CustomGenericException("E888", "This is custom message");
10 } else if ("io-error".equals(type)) {
11 // 由handleAllException处理
12 throw new IOException();
13 } else {
14 return new ModelAndView("index").addObject("msg", type);
15 }
16 }
17 }

异常处理类:

 1 @ControllerAdvice
2 public class ExceptionsHandler {
3
4 @ExceptionHandler(CustomGenericException.class)//可以直接写@ExceptionHandler,不指明异常类,会自动映射
5 public ModelAndView customGenericExceptionHnadler(CustomGenericException exception){ //还可以声明接收其他任意参数
6 ModelAndView modelAndView = new ModelAndView("generic_error");
7 modelAndView.addObject("errCode",exception.getErrCode());
8 modelAndView.addObject("errMsg",exception.getErrMsg());
9 return modelAndView;
10 }
11
12 @ExceptionHandler(Exception.class)//可以直接写@EceptionHandler,IOExeption继承于Exception
13 public ModelAndView allExceptionHandler(Exception exception){
14 ModelAndView modelAndView = new ModelAndView("generic_error");
15 modelAndView.addObject("errMsg", "this is Exception.class");
16 return modelAndView;
17 }
18 }

JSP页面:

正常页面index.jsp:

 1 <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
2 <html>
3 <body>
4 <h2>Spring MVC @ExceptionHandler Example</h2>
5
6 <c:if test="${not empty msg}">
7 <h2>${msg}</h2>
8 </c:if>
9
10 </body>
11 </html>

异常处理页面generic_error.jsp

<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<body> <c:if test="${not empty errCode}">
<h1>${errCode} : System Errors</h1>
</c:if> <c:if test="${empty errCode}">
<h1>System Errors</h1>
</c:if> <c:if test="${not empty errMsg}">
<h2>${errMsg}</h2>
</c:if> </body>
</html>

测试运行如下:

正常情况:

CustomGenericException异常情况:

IOException异常情况:

总结

  • @ExceptionHandler和@ControllerAdvice能够集中异常,使异常处理与业务逻辑分离
  • 本文重点理解两种注解方式的使用

参考:

Spring全局异常处理的更多相关文章

  1. Spring 全局异常处理

    [参考文章]:Spring全局异常处理的三种方式 [参考文章]:Spring Boot 系列(八)@ControllerAdvice 拦截异常并统一处理 [参考文章]:@ControllerAdvic ...

  2. 《Spring全局异常处理》从零掌握@ControllerAdvice注解

    一.开门见山 在前后端分离框架的大趋势下,前后端基本的职责已经确定. 前端主要负责界面的处理以及基本的判空检验.数据来源则通过vue调用后端发布的接口. 后端的原型还是mvc的模式: controll ...

  3. Spring全局异常处理的三种方式

    在J2EE项目的开发中,不管是对底层的数据库操作过程,还是业务层的处理过程,还是控制层的处理过程,都不可避免会遇到各种可预知的.不可预知的异常需要处理.每个过程都单独处理异常,系统的代码耦合度高,工作 ...

  4. spring全局异常处理 自定义返回数据结构

    在写api接口中,正常返回和异常错误返回我们都希望很清楚的将这些信息清楚的返回给用户,出现异常情况下需要清楚的知道是参数异常还是未知异常,而不是返回一个不正确的数据结构. 所以此处只针对写api接口时 ...

  5. Spring MVC 解决无法访问静态文件和"全局异常处理"

    我们都知道,Spring MVC的请求都会去找controller控制器,若果我们页面中引入了一个外部样式,这样是没效果的, 我们引入样式的时候是通过<like href="...&q ...

  6. Spring Boot 2.x 系列教程:WebFlux REST API 全局异常处理 Error Handling

    摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘要,谢谢! 本文内容 为什么要全局异常处理? WebFlux REST 全 ...

  7. Spring Boot 全局异常处理

    Spring Boot版本 1.5 @ControllerAdvice public class GlobalExceptionHandler extends ResponseEntityExcept ...

  8. Spring中通过java的@Valid注解和@ControllerAdvice实现全局异常处理。

    通过java原生的@Valid注解和spring的@ControllerAdvice和@ExceptionHandler实现全局异常处理的方法: controller中加入@Valid注解: @Req ...

  9. Spring Boot 2.X(十一):全局异常处理

    前言 在 Java Web 系统开发中,不管是 Controller 层.Service 层还是 Dao 层,都有可能抛出异常.如果在每个方法中加上各种 try catch 的异常处理代码,那样会使代 ...

随机推荐

  1. 添加APP右上角数字提醒标识

    mui.plusReady(function() { plus.nativeUI.closeWaiting(); mui.currentWebview.show(); //1.设置app右上角数字提醒 ...

  2. java web 程序---内置对象application的log方法的使用

    application的主要方法里,有log方法,是日志文件里可以查看到信息的. 当老师写好代码后,他发现在tomact里的log目录下找不到信息,原因是:我们用myeclipse这个客户端软件,应该 ...

  3. umount时目标忙解决办法

    标签(空格分隔): ceph ceph运维 osd 在删除osd后umount时,始终无法umonut,可以通过fuser查看设备被哪个进程占用,之后杀死进程,就可以顺利umount了. [root@ ...

  4. java io之管道流

    一.java.io中存在一中流叫管道流,类似管道的功能.PipedOutputStream和PipedInputStream分别是管道输出流和管道输入流.这个两个流必须同时使用. 二.作用:进行两个线 ...

  5. Oracle 11g 新特性 -- Oracle Restart 说明(转载)

    转载:http://blog.csdn.net/tianlesoftware/article/details/8435670 一.  OHASD 说明 Oracle 的Restart 特性是Oracl ...

  6. Oracle 和 MySQL的区别(不完整)

    1. Oracle对单双引号要求的很死,一般不准用双引号,不然会报错.MySQL 单双引号都可以. 2. 事务提交方式:Oracle 默认手动提交,MySQL 默认自动提交. 3. 分页:MySQL有 ...

  7. 5_python之路之员工管理系统

    python之路之员工管理系统 1.程序说明:Readme.cmd 1.程序文件:info_management.py user_info 2.程序文件说明:info_management.py-主程 ...

  8. git备忘

    git checkout . 放弃本地修改

  9. SpringMvc配置拦截器

    SpringMVC可以通过配置拦截器,进行url过滤等处理. 在spring-mvc.xml的配置文件中,如下示: 其中,在<mvc:interceptors>中可以配置多个拦截器< ...

  10. 第七章 二叉搜索树(b1)BST:查找