SpringMVC之异常处理器的使用
开发过程中是不可避免地会出现各种异常情况的,例如网络连接异常、数据格式异常、空指针异常等等。异常的出现可能导致程序的运行出现问题,甚至直接导致程序崩溃。因此,在开发过程中,合理处理异常、避免异常产生、以及对异常进行有效的调试是非常重要的。
对于异常的处理,一般分为两种方式:
- 编程式异常处理:是指在代码中显式地编写处理异常的逻辑。它通常涉及到对异常类型的检测及其处理,例如使用 try-catch 块来捕获异常,然后在 catch 块中编写特定的处理代码,或者在 finally 块中执行一些清理操作。在编程式异常处理中,开发人员需要显式地进行异常处理,异常处理代码混杂在业务代码中,导致代码可读性较差。
- 声明式异常处理:则是将异常处理的逻辑从具体的业务逻辑中分离出来,通过配置等方式进行统一的管理和处理。在声明式异常处理中,开发人员只需要为方法或类标注相应的注解(如
@Throws
或@ExceptionHandler
),就可以处理特定类型的异常。相较于编程式异常处理,声明式异常处理可以使代码更加简洁、易于维护和扩展。
站在宏观角度来看待声明式事务处理:
整个项目从架构这个层面设计的异常处理的统一机制和规范。
一个项目中会包含很多个模块,各个模块需要分工完成。如果张三负责的模块按照 A 方案处理异常,李四负责的模块按照 B 方案处理异常……各个模块处理异常的思路、代码、命名细节都不一样,那么就会让整个项目非常混乱。
使用声明式异常处理,可以统一项目处理异常思路,项目更加清晰明了!
- SpringMVC的异常处理器是处理控制器方法执行过程出现的异常。
- SpringMVC提供了一个处理异常的接口
HandlerExceptionResolver
。 HandlerExceptionResolver
接口有两个实现类:
DefaultHandlerExceptionResolver
实现类和SimpleMappingExceptionResolver
实现类。
DefaultHandlerExceptionResolver
实现类是SpringMVC默认异常处理器。
SimpleMappingExceptionResolver
实现类是简易异常处理器,我们一般自定义配置异常处理策略就是使用该异常处理器。
基于xml文件配置异常处理器
<!-- 配置异常处理器 -->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<!-- 配置异常视图的优先级 -->
<property name="order" value="1"/>
<!-- 配置异常逻辑视图映射:出现指定异常跳转到指定错误页面 -->
<property name="exceptionMappings">
<props>
<!--
key设置要处理的异常,全类名
value设置出现该异常时要跳转的页面所对应的逻辑视图
-->
<prop key="java.lang.Exception">error</prop>
<prop key="java.lang.NullPointerException">error</prop>
<prop key="java.lang.ArithmeticException">error</prop>
</props>
</property>
<!-- 设置默认错误视图 -->
<property name="defaultErrorView" value="error"/>
<!-- 设置异常属性:将异常信息共享到请求域中,浏览器可以获取请求域中的异常信息 -->
<property name="exceptionAttribute" value="ex"/>
<!-- 异常状态码 -->
<!--<property name="statusCodes" value="404,500"/>-->
<!-- 默认异常状态码 -->
<!--<property name="defaultStatusCode" value="500"/>-->
<!-- 排除指定异常 -->
<!--<property name="excludedExceptions" value="java.lang.ArithmeticException"/>-->
</bean>
基于注解配置异常处理器
@ControllerAdvice //将当前类标识为异常处理的组件
public class GlobalHandlerException {
//@ExceptionHandler用于设置所标识方法处理的异常
//ex表示当前请求处理中出现的异常对象
@ExceptionHandler(NullPointerException.class)
public Object handleException(NullPointerException e, Model model) {
String message = e.getMessage();
System.out.println(message);
model.addAttribute("message", message);
return "error";
}
@ExceptionHandler(ArithmeticException.class)
public Object handleException(ArithmeticException e,Model model) {
String message = e.getMessage();
System.out.println(message);
model.addAttribute("message",message);
return "error";
}
/**
* 所有异常都会触发此方法!但是如果有具体的异常处理Handler!
* 具体异常处理Handler优先级更高!
* 例如: 发生NullPointerException异常!
* 会触发handlerNullException方法,不会触发handlerException方法!
* @param e,model
* @return
*/
@ExceptionHandler(Exception.class)
public Object handleException(Exception e,Model model) {
String message = e.getMessage();
System.out.println(message);
model.addAttribute("meaages",message);
return "error";
}
}
创建视图
<a th:href="@{/test/get1}">测试异常处理器</a><br/>
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>错误</title>
</head>
<body>
<h2>error.html</h2>
<h4 style="color: green">系统内部出现故障,请联系管理员!</h4>
<p th:text="${message}">注解方式获取域中异常信息</p>
<!--<p th:text="${ex}">Xml配置方式获取域中的异常信息</p>-->
</body>
</html>
编写控制器方法
@RestController
@RequestMapping("/user")
public class UserController {
@GetMapping("/get1")
public String getUser() {
String name = null;
name.toString();
System.out.println(name);
return "ok";
}
@GetMapping("/get2")
public String getAdmin() {
Integer i = 10 / 0;
System.out.println(i);
return "ok";
}
}
测试
发送访问/user/get1
控制器方法的请求,控制器方法执行过程中出现异常处理器中配置的异常策略,跳转到指定异常视图。