把 @ExceptionHandler、HandlerExceptionResolver、@controlleradvice 三兄弟放在一起来写更有比较性。这三个东西都是用来处理异常的,但是它们使用的场景都不一样。看本文给你详细的讲解,再也不怕面试被问到了!

这三个注解都是来自于 SpringMVC 的,都能进行异常处理。

Java 程序员都非常的痛恨异常,很多人讨厌 Java 就是因为它的异常处理机制。到处的 try-catch-finally,再不是就是到处抛出异常。

所以 Spring 深知 Java 的疼点,推出了:@ExceptionHandler、HandlerExceptionResolver、@controlleradvice 来方便我们处理一些异常!

@ExceptionHandler 注解

用于局部方法捕获,与抛出异常的方法处于同一个 Controller 类。源码如下:

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

从源码中可以看出,@ExceptionHandler 注解只能作用为对象的方法上,并且在运行时有效,value() 可以指定异常类。由该注解注释的方法可以具有灵活的输入参数。

异常参数可以包括一般的异常或特定的异常(即自定义异常),如果注解没有指定异常类,会默认进行映射。

用法代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
@Controller
public class XttblogController {
    @ExceptionHandler({NullPointerException.class})
    public String exception(NullPointerException e) {
        System.out.println(e.getMessage());
        e.printStackTrace();
        return "null pointer exception";
    }
    @RequestMapping("test")
    public void test() {
        throw new NullPointerException("出错了!");
    }
}

上面这段代码只会捕获 XttblogController 类中的 NullPointerException 异常。

HandlerExceptionResolver 接口

HandlerExceptionResolver 是 Spring 提供的一个接口。它可以用来处理全局异常!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
@Component
public class GlobalExceptionResolver implements HandlerExceptionResolver{
    private ObjectMapper objectMapper;
    public CustomMvcExceptionHandler() {
        objectMapper = new ObjectMapper();
    }
    @Override
    public ModelAndView resolveException(HttpServletRequest request, 
        HttpServletResponse response,Object o, Exception ex) {
        response.setStatus(200);
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        response.setCharacterEncoding("UTF-8");
        response.setHeader("Cache-Control", "no-cache, must-revalidate");
        Map<String, Object> map = new HashMap<>();
        if (ex instanceof NullPointerException) {
            map.put("code", ResponseCode.NP_EXCEPTION);
        } else if (ex instanceof IndexOutOfBoundsException) {
            map.put("code", ResponseCode.INDEX_OUT_OF_BOUNDS_EXCEPTION);
        } else {
            map.put("code", ResponseCode.CATCH_EXCEPTION);
        }
        try {
            map.put("data", ex.getMessage());
            response.getWriter().write(objectMapper.writeValueAsString(map));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return new ModelAndView();
    }
}

在 Spring 源码中,我们可以看出它会获取一个实现了 HandlerExceptionResolver 接口的列表
List<HandlerExceptionResolver> resolvers; 如果这个列表不为空,则循环处理其中的异常。

HandlerExceptionResolve 虽然能够处理全局异常,但是 Spring 官方不推荐使用它。

@controlleradvice 注解

另外一个能够处理全局异常的就是 @controlleradvice 注解了。

@controlleradvice 注解根据它的源码,我们知道它也只能作用在类上,并且作用于运行时。下面我们来看一个例子。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@ControllerAdvice
public class ExceptionController {
    @ExceptionHandler(RuntimeException.class)
    public ModelAndView handlerRuntimeException(RuntimeException ex) {
        if (ex instanceof MaxUploadSizeExceededException) {
            return new ModelAndView("error").addObject("msg", "文件太大!");
        }
        return new ModelAndView("error").addObject("msg", "未知错误:" + ex);
    }
    @ExceptionHandler(Exception.class)
    public ModelAndView handlerMaxUploadSizeExceededException(Exception ex) {
        if (ex != null) {
            return new ModelAndView("error").addObject("msg", ex);
        }
        return new ModelAndView("error").addObject("msg", "未知错误:" + ex);
    }
}

需要注意的是,@ControllerAdvice 一般是和 @ExceptionHandler 组合在一起使用的。官方也推荐用这种方式处理统一全局异常。

一网打尽 @ExceptionHandler、HandlerExceptionResolver、@controlleradvice 三兄弟!的更多相关文章

  1. Nancy之Pipelines三兄弟(Before After OnError)

    一.简单描述 Before:如果返回null,拦截器将主动权转给路由:如果返回Response对象,则路由不起作用. After : 没有返回值,可以在这里修改或替换当前的Response. OnEr ...

  2. 好用的排名函数~ROW_NUMBER(),RANK(),DENSE_RANK() 三兄弟

    排名函数三兄弟,一看名字就知道,都是为了排名而生!但是各自有各自的特色!以下一个例子说明问题!(以下栗子没有使用Partition By 的关键字,整个结果集进行排序) RANK 每个值一个排名,同样 ...

  3. sql语句中----删除表数据的"三兄弟"

    说到删除表数据的关键字,大家记得最多的可能就是delete了 然而我们做数据库开发,读取数据库数据.对另外的两兄弟用得就比较少了 现在来介绍另外两个兄弟,都是删除表数据的,其实也是很容易理解的 老大- ...

  4. @ExceptionHandler和@ControllerAdvice统一处理异常

    //@ExceptionHandler和@ControllerAdvice统一处理异常//统一处理异常的controller需要放在和普通controller同级的包下,或者在ComponentSca ...

  5. Promise的三兄弟:all(), race()以及allSettled()

    摘要: 玩转Promise. 原文:Promise 中的三兄弟 .all(), .race(), .allSettled() 译者:前端小智 Fundebug经授权转载,版权归原作者所有. 从ES6 ...

  6. 设计模式系列之工厂模式三兄弟(Factory Pattern)

    说明:设计模式系列文章是读刘伟所著<设计模式的艺术之道(软件开发人员内功修炼之道)>一书的阅读笔记.个人感觉这本书讲的不错,有兴趣推荐读一读.详细内容也可以看看此书作者的博客https:/ ...

  7. Mysql 中写操作时保驾护航的三兄弟!

    这期的文章主要是讲述写操作过程中涉及到的三个日志文件,看过前几期的话可能你或多或少已经有些了解了(或者从别的地方也了解过).比如整个写操作过程中用到的两阶段提交,又或者是操作过程中涉及到的日志文件,但 ...

  8. 站长管理服务器必读:Ftp、Ftps与Sftp三兄弟的不同与区别以及部署全指引

    文章标题: 站长管理服务器必读:Ftp.Ftps与Sftp三兄弟的不同与区别以及部署全指引 关键字 : ftp,sftp,freesshd,ftps 文章分类: 教程 创建时间: 2020年3月23日 ...

  9. SPRING IN ACTION 第4版笔记-第七章Advanced Spring MVC-005- 异常处理@ResponseStatus、@ExceptionHandler、@ControllerAdvice

    No matter what happens, good or bad, the outcome of a servlet request is a servlet response. If an e ...

随机推荐

  1. 打开pycharm提示python已停止工作

    今天遇到一个棘手的问题: 现象:打开pycharm,立刻提示python已停止工作,关掉后还会弹出一个新的,就是永远维持至少一个提醒框在界面的状态 解决过程: 方法一:然后在网上搜解决办法,有一个主流 ...

  2. 前端面试题:不使用loop循环,创建一个长度为100的数组,并且每个元素的值等于它的下标,,怎么实现好?

    昨天,看这道题,脑子锈住了,就是没有思路,没看明白是什么意思?⊙﹏⊙|∣今天早上起床,想到需要思考一下这个问题. 当然,我没想明白为什么要这样做?(创建一个长度为100的数组,并且每个元素的值等于它的 ...

  3. hdu 5963:朋友

    刚看到这题时感觉是树上博弈,然后我开始用一维的数据找规律.发现在一维的树上,如果把各边的值合在一起当成一个二进制数,那么,ans只与奇偶性有关,于是,我提出了一个比较大胆的假设:若连接在root上的所 ...

  4. Flask学习笔记02之配置文件

    1. Flask默认的配置 Flask实例中包含了它的配置信息 #实例化一个Flask对象 app = Flask(__name__) # 打印默认配置信息 print(app.config) 打印结 ...

  5. 打印XX提交的svn版本信息

    打印出匹配uliuchao或--结尾的行 svn log | sed -n '/uliuchao/,/--$/p'

  6. jpa remove

    直接使用em.remove会报错,IllegalArgumentException: Removing a detached instance 即对象处于脱管的状态,使用merge使之被session ...

  7. 初步学习jQuery之事件

    事件 页面加载 在DOM中提供了load事件用于页面加载完毕之后执行机制,jQuery提供了ready()方法实现相似的功能,但是存在以下的区别.1.DOM中的load事件没有任何的简写形式,但是在j ...

  8. php Closure类 闭包 匿名函数

    php匿名函数 匿名函数就是没有名称的函数.匿名函数可以赋值给变量,还能像其他任何PHP对象那样传递.不过匿名函数仍是函数,因此可以调用,还可以传入参数.匿名函数特别适合作为函数或方法的回调. 如: ...

  9. nas请求响应示意图

    curl nginx(proxy_connect) nginx(NAS) | | | | | | (1) |-- CONNECT 443 -> | | | | | | |---- [ TCP c ...

  10. 20150909—Win10系统80端口被System占用

    安装了Windows10系统后,首先是查看80端口是不是被占用, 运行netstat -aon | findstr :80 ,发现pid是4的进程占用着80端口,这还是一个系统进程,kill不掉. 所 ...