关于SpringMVC中异常处理机制的简单介绍
在Spring中,可以通过三中方式实现异常的统一处理:
- 第一种是使用SpringMVC提供的简单异常处理器SimoleMappingExceptionHResolver,实现异常的统一处理
- 第二种是通过实现异常处理器接口HandlerExceptionResolver自定义异常处理器。实现异常的统一处理
- 第三种是使用@Exception注解实现异常的统一处理 我们将会对这三种方法进行统一的介绍和使用演示
简单异常处理器
HandleMappingExceptionResolve是一个接口,而我们可以使用这个接口的具体实现类:SimpleMappingExceptionResolver来对异常进行处理 这个类对异常的处理原理非常简单:它通过对不同的异常设置不同的页面,当我们的程序中有异常出现时,我们的异常处理类会开始捕捉并识别这些异常 通过SimpleMappingExceptionResolver可以将不同类型的异常映射到不同的页面中显示异常的处理信息,并提示我们可以如何去修复这个异常 除了自定义异常处理页面,SimpleMappingExceptionResolver还可以为所有的异常指定一个默认的处理页面。 而我们需要学习的,就是如何配置SimpleMappingExceptionResolver,为不同类型的异常指定不同的处理页面
代码实现
首先,我们需要一个异常类,这个类的作用是抛出几种不同类型的异常
package SpringMVC.Exception_handling;
//这个类的作用是创建异常
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.ArrayList;
@Controller
public class createException {
@RequestMapping("/NullPointException")
// 抛出空指针异常
private String NullPointException(){
ArrayList<Integer> al = null;
System.out.println(al.get(1));
return "E_Null_pointer_exception_in";
}
// 抛出IO异常
@RequestMapping("/IOException")
public String IOException() throws FileNotFoundException {
// 如果方法中包含在编译阶段就需要处理的异常,这里选择抛出
FileInputStream f = new FileInputStream("index.hj");
return "E_IO_exception";
}
// 抛出算数异常
@RequestMapping("/ArithmeticException")
public String ArithmeticException(){
System.out.println(1/0);
return "E_Arithmetic_anomalies";
}
// 抛出自定义异常
@RequestMapping("/addData")
public void addData() throws MyException {
throw new MyException("嵌套异常");
}
}
然后就是需要去创建不同的页面去根据不同的异常显示这些不同的页面
<%--
Created by IntelliJ IDEA.
User: 33680
Date: 2023/3/28
Time: 11:07
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>算数异常显示页面</title>
</head>
<body>
<h1>我是算数异常————${exp}</h1>
</body>
</html>
<%--
Created by IntelliJ IDEA.
User: 33680
Date: 2023/3/28
Time: 13:01
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>这是默认的异常处理页面</title>
</head>
<body>
<h1>默认的异常处理页面---------报错信息是:${msg}${exp}</h1>
</body>
</html>
<%--
Created by IntelliJ IDEA.
User: 33680
Date: 2023/3/28
Time: 11:07
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>IO异常显示页面</title>
</head>
<body>
<h1>我是IO异常————${exp}</h1>
</body>
</html>
<%--
Created by IntelliJ IDEA.
User: 33680
Date: 2023/3/28
Time: 11:07
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>空指针异常显示页面</title>
</head>
<body>
<h1>我是空指针异常————${exp}</h1>
</body>
</html>
然后,我们就需要在Spring-mvc.xml中配置我们的SimpleMappingExceptionResolver来对不同类型的异常去指定不同的处理页面
<!-- 配置异常处理器-->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<prop key="java.lang.NullPointerException">Exception_handling_page/E_Null_pointer_exception</prop>
<prop key="IOException">Exception_handling_page/E_IO_exception</prop>
</props>
</property>
<!-- 配置默认的异常处理页面-->
<property name="defaultErrorView" value="Exception_handling_page/E_defaultErrorView"/>
<!-- 配置异常信息的参数传递,我们可以在异常显示页面中使用插值语法获取到这个变量-->
<!-- 这个变量中存储的就是异常的基本信息-->
<property name="exceptionAttribute" value="exp"/>
</bean>
完成这些操作之后,我们就可以去访问我们异常类的路径,查看是否跳转到了我们之前配置的异常处理页面
运行结果
当我们访问异常类的路径的时候,控制器方法就会抛出异常,而异常抛出的时候,就会被异常处理器捕捉到,并匹配我们之前配置的规则,如果匹配到了合适的规则,就会跳转到相应的页面中,如果找不到合适的规则,则会跳转到默认的异常处理页面中
自定义异常处理类
除了使用SpringMVC内置的异常处理类对异常进行统一的处理,我们还可以自定义异常处理类对程序中的异常进行统一的处理
实现原理
自定义异常处理类可以处理我们自己创建的异常类,更加的灵活,但是配置稍微麻烦一点,它的实现原理是通过实现HandelExceptionResolver接口的方式,通过重写接口中的resolverException方法来实现对异常的自定义处理, 这个方法的返回值是一个ModelAndView类型,也就是可以直接在方法中将报错信息传递到页面中进行显示。
代码实现
首先,我们需要一个自定义异常类,这个类要继承Exception类,并重写方法,创建一个我们自定义的异常
package SpringMVC.Exception_handling;
public class MyException extends Exception {
// 存放异常信息的变量
private String message;
public MyException() {
}
public MyException(String message) {
super(message);
this.message = message;
}
@Override
public String toString() {
return "MyException{" +
"massage='" + message + '\'' +
'}';
}
@Override
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
然后,就是创建我们的控制器方法,这个方法可以什么都不做,只是抛出一个我们之前创建的自定义异常对象
// 抛出自定义异常
@RequestMapping("/addData")
public void addData() throws MyException {
throw new MyException("嵌套异常");
}
然后我们需要创建一个异常显示页面,用于显示我们的异常提示页面
<%--
Created by IntelliJ IDEA.
User: 33680
Date: 2023/3/28
Time: 13:01
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>这是默认的异常处理页面</title>
</head>
<body>
<h1>默认的异常处理页面---------报错信息是:${msg}${exp}</h1>
</body>
</html>
最后就是创建我们的自定义异常处理类,这个类需要实现HandlerExceptionResolver接口,并重写接口中的resolveException方法, 这个方法这个方法就是用来处理我们的异常类与页面之间的关系的. 在创建完自定义异常处理类之后,一定一定不要忘记把他注册到IoC容器中,否则我们所做的所有的操作全部都无法生效.
package SpringMVC.Exception_handling;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
//这里一定要注意将我们自己编写好的类注册到IoC中,我们使用注解的方式进行注册
@Component
public class CustomExceptionHandling implements HandlerExceptionResolver {
/**
*
* @param httpServletRequest 当前请求
* @param httpServletResponse 当前响应
* @param o 当前的异常处理类
* @param e 抛出的异常
* @return 返回异常信息展示页面
*/
@Override
public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
// 存储异常信息的变量
String msg;
// 做判断,如果这个异常是我们自己创建的异常类的对象,则将报错显示在页面中
// 如果不是我们自己创建的异常类,那么就说明这是Java内置的异常类,则走另一个分支
if(e instanceof MyException){
msg = e.getMessage();
}else {
// 因为Java的报错信息一般人看不明白,所以一般不展示给一班用户,替换成比简单的提示
Writer out = new StringWriter();
PrintWriter s = new PrintWriter(out);
e.printStackTrace(s);
String sysMsg = out.toString();
msg = "网络异常";
}
// 将信息和页面都封装在一起,然后返回一个页面即可
// 返回的对象
System.out.println(msg);
ModelAndView mv = new ModelAndView();
mv.addObject("msg",msg);
mv.setViewName("Exception_handling_page/E_defaultErrorView");
return mv;
}
}
最后,如果我们配置无误的话,我们访问我们的控制器类的异常,他就会自动的跳转到我们在自定义异常处理类中配置的 异常信息和页面中了.
使用注解的方式进行异常处理
在Spring2.3之后,Spring提供了一个新的注解:@ControllerAdvice这个注解的作用有两个
- 注解作用在类上时可以增强Controller,为Contriller中被@RequestMapping注解标注的方法加一些逻辑处理
- @ColltrollerAdvice注解结合方法型注解@ExceptionHandle,可以捕获Controller中抛出指定类型的异常,从而实现不同类型的异常统一处理
简单来说,通过注解的方式实现异常的统一处理的步骤有两个
- 首先,我们需要在类上使用@ControllerAdvice注解,对类进行强化
- 然后,我们在异常处理方法中使用@ExceptionHandle注解,这个注解有一个值就是异常类的class文件,他会自动的识别抛出的类是不是参数中类的对象或子类,如果是,则会自动的捕获异常并进行处理
代码实现
我们的异常类和异常显示界面还是使用之前的,我们只需要创建一个包含异常处理方法的类即可
package SpringMVC.Exception_handling;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;
//@ControllerAdvice
public class ExceptionAdvice {
@ExceptionHandler(MyException.class)
// 首先,异常处理器类需要一个返回值是ModelAndView,并且形参我们想要捕捉的异常类的对象
public ModelAndView MyException(MyException myException){
ModelAndView mv = new ModelAndView();
// 我们将异常的信息传递到页面中,使用ModelAndView将数据和页面封装到一起
mv.addObject("msg",myException.getMessage());
mv.setViewName("Exception_handling_page/E_defaultErrorView");
// 最后返回对象即可
return mv;
}
// 定义Java内置的异常的处理方法
@ExceptionHandler(Exception.class)
public ModelAndView Exception(Exception e){
ModelAndView mv = new ModelAndView();
mv.addObject("msg",e.getMessage());
mv.setViewName("Exception_handling_page/E_defaultErrorView");
return mv;
}
}
我们完成了配置之后,就可以来到浏览器,访问我们刚才配置的两个异常类,然后观察我们配置的基于注解的异常处理器类是否能正常捕获,并且是否能区分异常是我们自己创建的还是Java内置的异常类
注意点
在自定义异常处理器中,我们需要注意的就是我们在创建了处理器类之后,一定不要忘记将类注册进IoC容器, 建议使用注解式开发,比较的方便快捷.