• [六字真言]4.叭.SpringMVC异常痛苦


    “叭”,除畜生道劳役之苦;

    在学过的三阶段的时候,我们对SpringMVC的异常处理,一直可以算是简单中透着暴力,不要不重视异常!真的很重要,不要让它处在尴尬的位置!

    在二阶段或者说三阶段中,技术一方面其中我认为最关键的地方是MVC思想的理解,对MVC理解程度决定着你学习过程中的难易程度,虽然有点夸张!

    例如,当我们产生了一个 非业务异常 ,或者 非本业务可以处理的其他业务异常 ,那么我们一般会一直往 上层抛 (或者适当包装后继续抛出)直到 控制层 [我们就是这么解决问题,不知道你是否还记得],之后,控制层进行异常日志记录然后响应用户错误页面和信息。

    如果每个控制器都写一个异常处理未免也太多冗余了,好在强大的 Spring 给我们提供了很多种解决方案,这里介绍其中一种 @ControllerAdvice [个人认为目前最好的方案之一,XML方式的简单统一异常处理,这里就不说了]。

    1. 为什么现在我才告诉你呢?

    看该注解字面上的意思就是 控制器通知
    Advice 是AOP中的概念,这里简单介绍下。
    我们使用AOP切入某一目标方法,那么该方法在切面的角度看来可以有几个执行阶段:

    • 目标方法调用前(before)- 前置通知
    • 目标方法调用后(after)- 后置通知
    • 目标方法返回后(after return)- 返回通知
    • 目标方法调用前后(around)- 环绕通知
    • 目标方法抛出异常时(throw)- 异常通知

    是否还记得每种通知的特点呢?呵呵!忘记了吧!
    去看笔记或者PPT吧!!!
    当执行到某个阶段的时候都会有不同阶段类型 Advice 发出,然后你可以根据不同阶段类型的通知对切入点进行一些 增强处理 了。

    在不改动原来代码的基础上,增加新的功能!
    看看如何声明@ControllerAdvice

    1. /**
    2. * 全局异常处理器
    3. * @author 胖先生
    4. *
    5. */
    6. @ControllerAdvice
    7. public class GlobalExceptionHandler {
    8. }

    So Easy!标注完之后,该类就变成一个控制器通知处理器了,接着我们需要进行一些通知的处理。

    解除痛苦

    在该类中的方法上标注 @ExceptionHandler 可以将指定方法变成一个异常通知处理方法,处理的异常类型可使用参数指定。除了 @ExceptionHandler 之外还有其他的通知类型,具体可参阅官方文档,本文只以异常处理为例子,事实上运用最广泛的也就是异常处理而已了。

    新增以下代码可以处理 HttpRequestMethodNotSupportedException (HTTP方法不支持):

    1. @ExceptionHandler(value = HttpRequestMethodNotSupportedException.class)
    2. @ResponseBody
    3. public Result<String> httpRequestMethodNotSupportedExceptionHandler(HttpServletRequest req, Exception e) throws Exception{
    4. if (AnnotationUtils.findAnnotation(e.getClass(), ResponseStatus.class) != null)
    5. throw e;
    6. // Otherwise setup and send the user to a default error-view.
    7. // 这里你可以自由发挥,咱在这里给前端返回了一个错误提醒的Json
    8. Result<String> result = new Result<>(false);
    9. result.setError(HohistarExceptionReason.BIZ_10070);
    10. return result;
    11. }

    新增以下代码可以处理 MethodArgumentNotValidException(Validator字段校验失败异常处理):

    1. @ExceptionHandler(MethodArgumentNotValidException.class)
    2. @ResponseBody
    3. public Result<String> methodArgumentNotValidExceptionHandler(HttpServletRequest req, MethodArgumentNotValidException e) throws Exception{
    4. if (AnnotationUtils.findAnnotation(e.getClass(), ResponseStatus.class) != null)
    5. throw e;
    6. BindingResult bindingResult = e.getBindingResult();
    7. // Otherwise setup and send the user to a default error-view.
    8. Result<String> result = new Result<>(false);
    9. FieldError firstError = bindingResult.getFieldErrors().get(0);
    10. result.setError(HohistarExceptionReason.BIZ_10074, firstError.getField(), firstError.getDefaultMessage());
    11. return result;
    12. }

    如果要成功捕获 MethodArgumentNotValidException ,在控制器方法上就不能定义 BindingResult 参数接收校验结果,不然如果校验失败 Spring 是不会抛出 MethodArgumentNotValidException 异常的,自然而然在我们的 GlobalExceptionHandler 就无法处理了。

    一个都不放过

    如果你要捕获任何漏网之异常,你可以新增以下暴力的代码:

    1. @ExceptionHandler(value = Exception.class)
    2. @ResponseBody
    3. public Result<String> defaultExceptionHandler(HttpServletRequest req, Exception e) throws Exception {
    4. // If the exception is annotated with @ResponseStatus rethrow it and let
    5. // the framework handle it - like the OrderNotFoundException example
    6. // at the start of this post.
    7. // AnnotationUtils is a Spring Framework utility class.
    8. if (AnnotationUtils.findAnnotation(e.getClass(), ResponseStatus.class) != null)
    9. throw e;
    10. String throwClassName = e.getStackTrace()[0].getClassName();
    11. Logger logger = getLogger(throwClassName);
    12. logger.error("GlobalExceptionHandler catch a Server Exception: ", e);
    13. // Otherwise setup and send the user to a default error-view.
    14. Result<String> result = new Result<>(false);
    15. if(BeanUtils.isNotEmpty(this.defaultExceptionReason)){
    16. result.setError(HohistarExceptionReason.valueOf(this.defaultExceptionReason));
    17. } else {
    18. result.setError(HohistarExceptionReason.INTL_20001);
    19. }
    20. return result;
    21. }

    GlobalExceptionHandler 中可以有多个 @ExceptionHandler 标注的方法,如果控制器中抛出了一个异常,而且没有匹配任何其他类型的异常处理方法,那么上方的方法将会被通知执行, 保证从控制器抛出的异常一定会受到处理

    大部分代码来自官方文档:这里大部分摘抄Spring官方手册





  • 相关阅读:
    亿级流量架构服务降级,写得太好了!
    面试官:什么是对象池?有什么用?别说你还不会!
    最新数据库排行榜出炉!MySQL 稳了~
    别再写满屏的 get & set 了,太 Low!试试 MapStruct 高级玩法!
    vista 中php4, php5 共存
    dotnet framework 3.5 installed issues on nonenglish os
    web service notes
    msn web status
    db notes
    wikipedia的mysql utf8中文在.net中的处理
  • 原文地址:https://www.cnblogs.com/pangxiansheng/p/588d4141d36399ffb9a03ace262a24e2.html
Copyright © 2020-2023  润新知