😀前言
在现代软件开发中,异常处理是不可或缺的一部分,它能够有效地提高系统的稳定性和健壮性。在Spring MVC框架中,异常处理机制起着至关重要的作用,它允许开发者在程序运行过程中捕获、处理和报告异常,从而保障用户体验和系统可靠性。本文将带您深入探索Spring MVC异常处理的核心概念、不同的处理策略以及如何构建一个稳固的异常处理机制。
🧑个人简介:大家好,我是尘觉,希望我的文章可以帮助到大家,您的满意是我的动力😉😉
🥰解密Spring MVC异常处理:从局部到全局,打造稳固系统的关键步骤
异常处理-基本介绍
- Spring MVC 通过 HandlerExceptionResolver 处理程序的异常,包括 Handler 映射、数据
绑定以及目标方法执行时发生的异常 - 主要处理 Handler 中用 -@ExceptionHandler 注解定义的方法。
- ExceptionHandlerMethodResolver 内部若找不到–@ExceptionHandler 注解的话,会找
@ControllerAdvice 类的@ExceptionHandler 注解方法,这样就相当于一个全局异常处理器
😀局部异常
演示局部异常处理机制
如果不处理异常, 非常的不友好
创建MyExceptionHandler
@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"; }
创建exception.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>异常信息</title> </head> <body> <h1>测试异常</h1> <a href="<%=request.getContextPath()%>/testException01?num=0">点击测试局部异常</a><br><br> </body> </html>
创建exception_mes.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>异常信息提示</title> </head> <body> <h1>朋友, 程序发生了异常...</h1> 异常信息- ${requestScope.reason} </body> </html>
测试(页面方式)
浏览器 http://localhost:8080/springmvc/exception.jsp
测试(Postman 方式)
😀全局异常
ExceptionHandlerMethodResolver 内部若找不到@ExceptionHandler 注解的话,会找
@ControllerAdvice 类的@ExceptionHandler 注解方法, 这样就相当于一个全局异常处理器
这个上面已经演示了这里只是补充说明
解读
- 这里我们模拟了一个异常 NumberFormatException
- 该异常没有在局部异常处理,按照异常处理机制,就会交给全局异常处理类处理
修改MyExceptionHandler增加方法
@RequestMapping(value = "/testGlobalException") public String global(){ //解读 //1. 这里我们模拟了一个异常 NumberFormatException //2. 该异常没有在局部异常处理,按照异常处理机制,就会交给全局异常处理类处理 int num = Integer.parseInt("hello"); return "success"; }
修改exception.jsp增加语句
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>异常信息</title> </head> <body> <h1>测试异常</h1> <a href="<%=request.getContextPath()%>/testException01?num=0">点击测试局部异常</a><br><br> <a href="<%=request.getContextPath()%>/testGlobalException">点击测试全局异常</a><br><br> </body> </html>
测试
如上面测试一样
😉异常优先级
异常处理时:局部异常 优先级高于 全局异常
需求
通过@ResponseStatus 注解, 可以自定义异常的说明
创建AgeException.java
@ResponseStatus(reason = "年龄需要在1-120之间", value = HttpStatus.BAD_REQUEST) public class AgeException extends RuntimeException { public AgeException() { } public AgeException(String message) { super(message); } }
修改MyExceptionHandler增加方法
@RequestMapping(value = "/testException02") public String test02(){ throw new AgeException("年龄必须在1-120之间~~~"); }
修改 exception.jsp, 增加超链
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>异常信息</title> </head> <body> <h1>测试异常</h1> <a href="<%=request.getContextPath()%>/testException01?num=0">点击测试局部异常</a><br><br> <a href="<%=request.getContextPath()%>/testGlobalException">点击测试全局异常</a><br><br> <a href="<%=request.getContextPath()%>/testException02">点击测试自定义异常</a><br/><br/> </body> </html>
完成测试(页面测是)
浏览器 http://localhost:8080/springmvc/exception.jsp
完成测试(postman)
😊SimpleMappingExceptionResolver
基本说明
- 如果希望对所有异常进行统一处理,可以使用 SimpleMappingExceptionResolver
- 它将异常类名映射为视图名,即发生异常时使用对应的视图报告异常
- 需要在 ioc容器中配置
代码演示
对数组越界异常进行统一处理,使用 SimpleMappingExceptionResolver处理
修改 MyExceptionHandler.java , 增加方法test03
@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
解释一下为什么只写arrEX因为我们前面配置了 prefix/WEB-INF/pages/和suffix .jsp所以默认会拼接
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <property name="exceptionMappings"> <props> <prop key="java.lang.ArrayIndexOutOfBoundsException">arrEx</prop> </props> </property> </bean>
创建arrEx.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>数组越界异常</title> </head> <body> <h1><异常></异常>信息: 数组越界异常</h1> </body> </html>
修改 exception.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>异常信息</title> </head> <body> <h1>测试异常</h1> <a href="<%=request.getContextPath()%>/testException01?num=0">点击测试局部异常</a><br><br> <a href="<%=request.getContextPath()%>/testGlobalException">点击测试全局异常</a><br><br> <a href="<%=request.getContextPath()%>/testException02">点击测试自定义异常</a><br/><br/> <a href="<%=request.getContextPath()%>/testException03">点击测试统一处理异常</a><br/><br/> </body> </html>
并完成测试
(页面测试), 浏览器 http://localhost:8080/springmvc/exception.jsp
(postman) 测 http://localhost:8080/springmvc/testException03
页面就不展示了
🤗对未知异常进行统一处理
对未知异常进行统一处理,使用 SimpleMappingExceptionResolver
<!--配置统一处理异常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>
修改 MyExceptionHandler.java , 增加方法test04
//如果发生了没有归类的异常, 可以给出统一提示页面 @RequestMapping(value = "/testException04") public String test04(){ String str = "hello"; //这里会抛出 StringIndexOutOfBoundsException char c = str.charAt(10); return "success"; }
创建allEx.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>未知异常信息</title> </head> <body> <h1>朋友,系统发生了未知异常~, 请联系网站管理员</h1> </body> </html>
修改 exception.jsp , 增加超链接
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>异常信息</title> </head> <body> <h1>测试异常</h1> <a href="<%=request.getContextPath()%>/testException01?num=0">点击测试局部异常</a><br><br> <a href="<%=request.getContextPath()%>/testGlobalException">点击测试全局异常</a><br><br> <a href="<%=request.getContextPath()%>/testException02">点击测试自定义异常</a><br/><br/> <a href="<%=request.getContextPath()%>/testException03">点击测试统一处理异常</a><br/><br/> <a href="<%=request.getContextPath()%>/testException04">点击测试未知异常</a><br/><br/> </body> </html>
并完成测试
(页面测试), 浏览器 http://localhost:8080/springmvc/exception.jsp
(postman) 测试http://localhost:8080/springmvc/testException04
异常处理的优先级梳理
● 异常处理的优先级
局部异常 > 全局异常 > SimpleMappingExceptionResolver > tomcat 默认机制
😘全部xml配置
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!--配置自动扫描包--> <context:component-scan base-package="com.wyxdu.web"/> <!--配置视图解析器[默认视图解析器]--> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!--配置属性suffix 和 prefix--> <property name="prefix" value="/WEB-INF/pages/"/> <property name="suffix" value=".jsp"/> <!--调整优先级--> <property name="order" value="10"/> </bean> <!-- 解读 1. 配置自定义视图解析器BeanNameViewResolver 2. BeanNameViewResolver可以去解析我们自定义的视图 3. 配置 属性 order, 表示视图解析器执行的顺序, 值越小, 优先级越高 4. 属性 order 的默认值是最低优先级 ,值为 Integer.MAX_VALUE int LOWEST_PRECEDENCE = 2147483647 --> <bean class="org.springframework.web.servlet.view.BeanNameViewResolver"> <property name="order" value="99"/> </bean> <!-- 配置国际化错误信息的资源处理bean --> <bean id="messageSource" class= "org.springframework.context.support.ResourceBundleMessageSource"> <!-- 配置国际化文件名字 如果你这样配的话,表示messageSource回到 src/i18nXXX.properties去读取错误信息 --> <property name="basename" value="i18n"></property> </bean> <!--配置文件上传需要的bean--> <bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver" id="multipartResolver"/> <!--配置自定义拦截器-spring配置文件--> <mvc:interceptors> <!-- 解读 1. 第一种配置方式 2. 使用ref 引用到对应的myInterceptor01 3. 这种方式,会拦截所有的目标方法 --> <!--<ref bean="myInterceptor01"/>--> <!--解读 1. 第二种配置方式 2. mvc:mapping path="/hi" 指定要拦截的路径 3. ref bean="myInterceptor01" 指定对哪个拦截器进行配置 --> <!-- <mvc:interceptor>--> <!-- <mvc:mapping path="/hi"/>--> <!-- <ref bean="myInterceptor01"/>--> <!-- </mvc:interceptor>--> <!--解读 1. 第3种配置方式 2. mvc:mapping path="/h*" 通配符方式 表示拦截 /h 打头的路径 3. mvc:exclude-mapping path="/hello" /hello不拦截 4. ref bean="myInterceptor01" 指定对哪个拦截器配置 --> <mvc:interceptor> <mvc:mapping path="/h*"/> <mvc:exclude-mapping path="/hello"/> <ref bean="myInterceptor01"/> </mvc:interceptor> <!--解读 1.配置的第二个拦截器 2.多个拦截器在执行时,是顺序执行 --> <mvc:interceptor> <mvc:mapping path="/h*"/> <ref bean="myInterceptor02"/> </mvc:interceptor> </mvc:interceptors> <!--配置统一处理异常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> <!--加入两个常规配置--> <!--支持SpringMVC的高级功能,比如JSR303校验, 映射动态请求--> <mvc:annotation-driven></mvc:annotation-driven> <!-- 将springmvc不能处理的请求,交给tomcat处理,比如css, js--> <mvc:default-servlet-handler/> </beans>
😄总结
在本文中,我们深入研究了Spring MVC的异常处理机制,从局部异常处理到全局异常处理,再到通过SimpleMappingExceptionResolver进行统一处理,我们详细介绍了每种方法的配置和使用。异常处理在软件开发中扮演着守护者的角色,它可以让我们更好地掌控程序在各种情况下的行为,提高系统的健壮性和可维护性。
无论是在局部还是全局,合适的异常处理都能帮助我们更好地处理潜在的问题,使用户能够获得友好的错误提示,同时也为开发者提供了定位和解决问题的线索。掌握Spring MVC异常处理的技巧,将为您的项目增添一层安全防护,让用户体验更加顺畅,系统更加可靠。希望本文对您理解异常处理的重要性,以及如何在Spring MVC中高效地应用异常处理策略提供了有益的指导。
文章到这里就结束了,如果有什么疑问的地方请指出,诸佬们一起来评论区一起讨论😁
希望能和诸佬们一起努力,今后我们一起观看感谢您的阅读🍻
如果帮助到您不妨3连支持一下,创造不易您们的支持是我的动力🤞