异常处理
2023年11月15日大约 6 分钟约 1269 字
基本介绍
- Spring MVC 通过 HandlerExceptionResolver 处理程序的异常,包括 Handler 映射、数据绑定以及目标方法执行时发生的异常。
- 主要处理 Handler 中用 @ExceptionHandler 注解定义的方法。
- ExceptionHandlerMethodResolver 内部若找不到@ExceptionHandler 注解的话,会找 @ControllerAdvice 类的 @ExceptionHandler 注解方法,这样就相当于一个全局异常处理器。
局部异常
不处理异常,显示的非常不友好。

应用实例
创建 MyExceptionHandler.java
package com.lzw.web.exception;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
/**
* @author LiAng
*/
@Controller
public class MyExceptionHandler {
/**
* 1. localException 方法处理局部异常
* 2. 这里处理ArithmeticException.class,NullPointerException.class
* 3. Exception ex: 生成的异常对象,会传递给ex, 通过ex可以得到相关的信息
* , 这里程序员可以加入自己的业务逻辑
*/
@ExceptionHandler({ArithmeticException.class,NullPointerException.class})
public String localException(Exception ex, HttpServletRequest request){
System.out.println("局部异常信息是-" + ex.getMessage());
//如何将异常的信息带到下一个页面.
request.setAttribute("reason", ex.getMessage());
return "exception_mes";
}
/**
* 1. 编写方法,模拟异常, 算术异常
* 2. 如果我们不做异常处理,是由tomcat默认页面显示
*/
@RequestMapping(value = "/testException01")
public String test01(Integer num) {
int i = 9 / num;
return "success";
}
}
创建 web\exception.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>异常信息</title>
</head>
<body>
<h1>测试异常</h1>
<a href="<%=request.getContextPath()%>/testException01">点击测试异常</a><br><br>
</body>
</html>
创建 web\WEB-INF\pages\exception_mes.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>异常信息提示</title>
</head>
<body>
<h1>程序发生异常了...</h1>
异常信息:${requestScope.reason}
</body>
</html>
完成测试

Debug

全局异常
ExceptionHandlerMethodResolver 内部若找不到 @ExceptionHandler 注解的话,会找 @ControllerAdvice 类的@ExceptionHandler 注解方法,这样就相当于一个全局异常处理器。
应用实例
创建 MyGlobalException.java
package com.lzw.web.exception;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import javax.servlet.http.HttpServletRequest;
/**
* @author LiAng
* 如果类上标注了@ControllerAdvice,就是一个全局异常处理类
*/
@ControllerAdvice
public class MyGlobalException {
/**
* 1. 全局异常就不管是哪个Handler抛出的异常,都可以捕获 , @ExceptionHandler({异常类型})
* 2. 这里处理的全局异常是NumberFormatException.class,ClassCastException.class
* 3. Exception ex 接收抛出的异常对象
*/
@ExceptionHandler({NumberFormatException.class, ClassCastException.class})
public String globalException(Exception ex, HttpServletRequest request) {
System.out.println("全局异常处理-" + ex.getMessage());
//将异常的信息带到下一个页面.
request.setAttribute("reason", ex.getMessage());
return "exception_mes";
}
}
修改 MyExceptionHandler.java
@RequestMapping(value = "/testGlobalException")
public String global(){
//1. 这里我们模拟了一个异常 NumberFormatException
//2. 该异常没有在局部异常处理,按照异常处理机制,就会交给全局异常处理类处理
int num = Integer.parseInt("hello");
return "success";
}
修改 web\exception.jsp
<a href="<%=request.getContextPath()%>/testGlobalException">点击测试异常</a><br><br>
完成测试

Debug




注意
局部异常 优先级高于 全局异常。
自定义异常
通过@ResponseStatus 注解,可以自定义异常的说明。
应用实例
创建 AgeException.java
package com.lzw.web.exception;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
/**
* @author LiAng
*/
@ResponseStatus(reason = "年龄需要在1-120之间", value = HttpStatus.BAD_REQUEST)
public class AgeException extends RuntimeException {
}
修改 MyExceptionHandler.java
@RequestMapping("/testException02")
public String test02(){
throw new AgeException();
}
修改 exception.jsp
<a href="<%=request.getContextPath()%>/testException02">点击测试自定义异常</a><br><br>
完成测试

Debug

统一处理异常
说明
- 如果希望对所有异常进行统一处理,可以使用 SimpleMappingExceptionResolver。
- 它将异常类名映射为视图名,即发生异常时使用对应的视图报告异常。
- 需要在 ioc 容器中配置。
应用实例
对数组越界异常进行统一处理,使用 SimpleMappingExceptionResolver。
修改 MyExceptionHandler.java
@RequestMapping(value = "/testException03")
public String test03(){
int[] arr = new int[]{3,9,10,190};
//抛出一个数组越界的异常 ArrayIndexOutOfBoundsException
System.out.println(arr[90]);
return "success";
}
修改 springDispatcherServlet-servlet.xml
<!--配置统一处理异常bean-->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<prop key="java.lang.ArrayIndexOutOfBoundsException">arrEx</prop>
</props>
</property>
</bean>
创建 web\WEB-INF\pages\arrEx.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>数组越界异常</title>
</head>
<body>
<h1>数组越界异常</h1>
</body>
</html>
修改 exception.jsp
<a href="<%=request.getContextPath()%>/testException03">点击测试统一处理异常</a><br><br>
完成测试

对未知异常进行统一处理
对未知异常进行统一处理,使用 SimpleMappingExceptionResolver。
修改 MyExceptionHandler.java
//如果发生了没有归类的异常, 可以给出统一提示页面
@RequestMapping(value = "/testException04")
public String test04(){
String str = "hello";
//这里会抛出 StringIndexOutOfBoundsException
char c = str.charAt(10);
return "success";
}
修改 springDispatcherServlet-servlet.xml
<!--配置统一处理异常bean-->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<prop key="java.lang.ArrayIndexOutOfBoundsException">arrEx</prop>
<prop key="java.lang.Exception">allEx</prop>
</props>
</property>
</bean>
创建 web\WEB-INF\pages\allEx.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>未知异常信息</title>
</head>
<body>
<h1>系统发生了未知异常</h1>
</body>
</html>
修改 exception.jsp
<a href="<%=request.getContextPath()%>/testException04">点击测试未知异常</a><br><br>
完成测试

异常处理的优先级
局部异常 > 全局异常 > SimpleMappingExceptionResolver > tomcat 默认机制