1. 异常处理概述

  • Spring MVC 通过 HandlerExceptionResolver 处理程序的异常,包括 Handler 映射、数据绑定以及目标方法执行时发生的异常。
  • SpringMVC 提供的 HandlerExceptionResolver 的实现类

image.png

2. HandlerExceptionResolver

DispatcherServlet 默认装配的 HandlerExceptionResolver

没有使用 < mvc:annotation-driven /> 配置:
image.png

使用了< mvc:annotation-driven /> 配置
image.png

image.png

3. 实验代码

①页面链接

  1. <a href="testExceptionHandlerExceptionResolver?i=1">testExceptionHandlerExceptionResolver</a>

②控制器方法

@Controller
public class ExceptionHandler {
@RequestMapping("/testExceptionHandlerExceptionResolver")
    public String testExceptionHandlerExceptionResolver(@RequestParam("i") int i){
    System.out.println("10/"+i+"="+(10/i));
    return "success";
    }
}

③测试,出现异常情况
image.png
处理异常,跳转到error.jsp

④在控制器中增加处理异常的方法

@ExceptionHandler(value={java.lang.ArithmeticException.class})
public String handleException(Exception ex){
System.out.println("出现异常啦"+ex);
return "error";
}

⑤增加error.jsp

<h3>Error Page</h3>

4. 如何将异常对象从控制器携带给页面,做异常信息的获取

① 异常对象不能通过Map集合方式传递给成功页面。(Map不可以)

// @ExceptionHandler(value={java.lang.ArithmeticException.class})
public String handleException(Exception ex,Map<String,Object> map){
System.out.println("出现异常啦:"+ex);
map.put("exception",ex);
return "error";
}

image.png
②可以通过ModelAndView将异常对象传递给成功页面上

@ExceptionHandler(value={java.lang.ArithmeticException.class})
public ModelAndView handleException(Exception ex){
System.out.println("出现异常啦:"+ex);
ModelAndView mv = new ModelAndView("error");
mv.addObject("exception", ex);
//视图解析器拼串
return mv;
}

5. 匹配异常类型,执行顺序问题

@ExceptionHandler(value={java.lang.ArithmeticException.class})
public ModelAndView handleException(Exception ex){
    System.out.println("出现异常啦:"+ex);
    ModelAndView mv = new ModelAndView("error");
    mv.addObject("exception", ex);
    return mv;
}

@ExceptionHandler(value={java.lang.RuntimeException.class})
public ModelAndView handleException2(Exception ex){
    System.out.println("RuntimeException-出现异常啦:"+ex);
    ModelAndView mv = new ModelAndView("error");
    mv.addObject("exception", ex);
    return mv;
}

6. 公共的处理异常的类@ControllerAdvice

定义公共的处理异常的类

@ControllerAdvice
public class ExceptionAdviceHandler {

    /*        
    @ExceptionHandler(value={java.lang.ArithmeticException.class})
    public ModelAndView handleException(Exception ex){

    System.out.println("出现异常啦:"+ex);
    ModelAndView mv = new ModelAndView("error");
    mv.addObject("exception", ex);

    return mv; 
    }*/

    @ExceptionHandler(value={java.lang.RuntimeException.class})
    public ModelAndView handleException2(Exception ex){

    System.out.println("RuntimeException-出现异常啦:"+ex);
    ModelAndView mv = new ModelAndView("error");
    mv.addObject("exception", ex);

    return mv;
    }
}

7. ExceptionHandlerExceptionResolver

  • 主要处理 Handler 中用 @ExceptionHandler 注解定义的方法。

  • @ExceptionHandler 注解定义的方法优先级问题:例如发生的是NullPointerException,但是声明的异常有 RuntimeException 和 Exception,此候会根据异常的最近继承关系找到继承深度最浅的那个 @ExceptionHandler 注解方法,即标记了 RuntimeException 的方法

  • ExceptionHandlerMethodResolver 内部若找不到@ExceptionHandler 注解的话,会找 @ControllerAdvice 中的@ExceptionHandler 注解方法

8. 异常处理_ResponseStatusExceptionResolver

  • 在异常及异常父类中找到 @ResponseStatus 注解,然后使用这个注解的属性进行处理。

  • 定义一个 @ResponseStatus 注解修饰的异常类

  • 若在处理器方法中抛出了上述异常:若ExceptionHandlerExceptionResolver 不解析上述异常。由于触发的异常 UnauthorizedException 带有@ResponseStatus 注解。因此会被ResponseStatusExceptionResolver 解析到。最后响应HttpStatus.UNAUTHORIZED 代码给客户端。HttpStatus.UNAUTHORIZED 代表响应码401,无权限。 关于其他的响应码请参考 HttpStatus 枚举类型源码。

    ① 页面链接 ```html testResponseStatusExceptionResolver

② 自定义异常类
```java
/**
 * 自定义异常类
HttpStatus.FORBIDDEN 不允许的,禁用的
 */
@ResponseStatus(value=HttpStatus.FORBIDDEN,reason="用户名称和密码不匹配")
public class UsernameNotMatchPasswordException extends RuntimeException{
}

[

](https://blog.csdn.net/qq_43284469/article/details/111205605)
③控制器方法

@RequestMapping(value="/testResponseStatusExceptionResolver")
public String testResponseStatusExceptionResolver(@RequestParam("i") int i){
    if(i==13){
        throw new UsernameNotMatchPasswordException();
    }
    System.out.println("testResponseStatusExceptionResolver...");
    return "success";
}

④ 出现的错误消息

  • 没使用注解时:@ResponseStatus(value=HttpStatus.FORBIDDEN,reason=“用户名称和密码不匹配”)

image.png

  • 用注解时:@ResponseStatus(value=HttpStatus.FORBIDDEN,reason=“用户名称和密码不匹配”

image.png

  • 测试在方法上使用注解 ```java @ResponseStatus(value=HttpStatus.NOT_FOUND,reason=”测试方法上设置响应状态码”) @RequestMapping(value=”/testResponseStatusExceptionResolver”) public String testResponseStatusExceptionResolver(@RequestParam(“i”) int i){ if(i==13){
      throw new UsernameNotMatchPasswordException();
    
    } System.out.println(“testResponseStatusExceptionResolver…”); return “success”; }
![image.png](https://cdn.nlark.com/yuque/0/2021/png/2963105/1630809381645-0661006a-565b-4e12-ac30-e24f3647caa4.png#clientId=u701e5fc4-0bff-4&from=paste&height=344&id=u5af53e88&margin=%5Bobject%20Object%5D&name=image.png&originHeight=344&originWidth=1024&originalType=binary&ratio=1&size=100061&status=done&style=none&taskId=u981e9559-89fa-42bc-b924-c2e4d772ee9&width=1024)

<a name="u96kn"></a>
## 9. 异常处理_DefaultHandlerExceptionResolver

- 对一些特殊的异常进行处理,比如:
   - NoSuchRequestHandlingMethodException、
   - HttpRequestMethodNotSupportedException、
   - HttpMediaTypeNotSupportedException、
   - HttpMediaTypeNotAcceptableException等。
<a name="SAokt"></a>
## 
① 增加页面链接:GET请求
```html
<a href="testDefaultHandlerExceptionResolver">testDefaultHandlerExceptionResolver</a>

增加处理器方法

//@RequestMapping(value="/testDefaultHandlerExceptionResolver")
@RequestMapping(value="/testDefaultHandlerExceptionResolver",method=RequestMethod.POST)  //不支持GET请求
public String testDefaultHandlerExceptionResolver(){
    System.out.println("testDefaultHandlerExceptionResolver...");
    return "success";
}

② 出现异常错误
image.png

10. 异常处理_SimpleMappingExceptionResolver

  • 如果希望对所有异常进行统一处理,可以使用 SimpleMappingExceptionResolver,它将异常类名映射为视图名,即发生异常时使用对应的视图报告异常

image.png
① 增加页面链接

<a href="testSimpleMappingExceptionResolver?i=1">testSimpleMappingExceptionResolver</a>

② 增加控制器方法

@RequestMapping("/testSimpleMappingExceptionResolver")
public String testSimpleMappingExceptionResolver(@RequestParam("i") int i){
    System.out.println("testSimpleMappingExceptionResolver..."); 
    String[] s = new String[10]; 
    System.out.println(s[i]); 
    return "success";
}

③ 出现异常情况:参数i的值大于10
image.png
④ 配置异常解析器:自动将异常对象信息,存放到request范围内

<!-- 配置SimpleMappingExceptionResolver异常解析器 -->
<bean id="simpleMappingExceptionResolver"
 class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<!-- exceptionAttribute默认值(通过ModelAndView传递给页面):
exception   ->  ${requestScope.exception}
public static final String DEFAULT_EXCEPTION_ATTRIBUTE = "exception";
-->
<property name="exceptionAttribute" value="exception"></property>
    <property name="exceptionMappings">
        <props>
            <prop key="java.lang.ArrayIndexOutOfBoundsException">error</prop>
        </props>
    </property>
</bean>

error.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
 "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body> 
<h3>Error Page</h3> 
${exception }
${requestScope.exception } 
</body>
</html>