SpringMVC-7—SpringMVC异常处理

目录

一、异常处理思路

二、异常处理结构体系

三、异常处理方案

1、DefaultHandlerExceptionResolver——根据状态码配置

2、SimpleMappingExceptionResolver——根据异常类型配置

3、AnnotationMethodHandlerExceptionResolver —— 注解配置异常

4、@ControllerAdvice——注解全局异常处理


我们知道,系统中异常包括:编译时异常和运行时异常RuntimeException,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发、测试通过手段减少运行时异常的发生。

在开发中,不管是dao层、service层还是controller层,都有可能抛出异常,在springmvc中,能将所有类型的异常处理从各处理过程解耦出来,既保证了相关处理过程的功能较单一,也实现了异常信息的统一处理和维护。

一、异常处理思路

springmvc中,异常处理的思路

上图所示,系统的daoservicecontroller出现异常都通过throws Exception向上抛出,最后由springmvc前端控制器交由异常处理器进行异常处理。

springmvc提供全局异常处理器(一个系统只有一个异常处理器)进行统一异常处理。明白了springmvc中的异常处理机制,下面就开始分析springmvc中的异常处理。

二、异常处理结构体系

Spring MVC通过HandlerExceptionResolver处理程序的异常,包括处理映射,数据绑定及处理器执行时发生异常。HandlerExceptionResolver仅有一个接口方法:

public interface HandlerExceptionResolver {

    ModelAndView resolveException(HttpServletRequest var1, HttpServletResponse var2, Object var3, Exception var4);

}

当发生异常时,Spring MVC将调用 resolveException()方法,并转到ModelAndView对应视图中,作为一个异常报告页面,反馈给用户!

HandlerExceptionResolver拥有几个以下常见实现类:

三、异常处理方案

1、DefaultHandlerExceptionResolver——根据状态码配置

Spring MVC默认装配了DefaultHandlerExceptionResolver,它会将Spring MVC框架的异常转换为相应的相应状态码!

自定义404 html页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
  <h1>404,资源找不到了!</h1>
</body>
</html>

在springmvc.xml中放开指定的静态资源拦截

静态资源注意会被DispatcherServlet拦截!

<mvc:resources location="/static/" mapping="/static/**"/>

web.xml响应状态码配置一个对应页面

    <error-page>
        <error-code>404</error-code>
        <location>/static/404.html</location>
    </error-page>

执行结果:

在Controller中并没有test404这个方法,在没有设置自定义页面之前,报错信息如下

在设置自定义页面之后,跳转到自定义页面

2、SimpleMappingExceptionResolver——根据异常类型配置

如果希望对所有的异常进行统一的处理,比如当指定的异常发生时,把它映射到要显示的错误的网页中,此时用SimpleMappingExceptionResolver进行解析。

DispatcherServlet中没有实现SimpleMappingExceptionResolverBean,所有需要在springmvc的配置文件中进行配置。

示例如下:

Controller方法:抛出数组下标越界异常

    @RequestMapping("/testSimpleMappingExceptionResolver")
    public String testSimpleMappingExceptionResolver() {
        String[] values = new String[10];
        // 下标越界了
        System.out.println(values[11]);
        return "success";
    }

发送Http请求,控制器捕获请求后处理控制器逻辑,由于在逻辑中, 数组越界,会抛出ArrayIndexOutOfBoundsException异常。

配置使用SimpleMappingExceptionResolver来映射异常

    <!--注解驱动 -->
    <mvc:annotation-driven/> 
    <!-- 配置使用SimpleMappingExceptionResolver来映射异常 -->
    <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> 
        <!-- 给异常命名一个别名 -->
        <property name="exceptionAttribute" value="exception"></property>
        <property name="exceptionMappings">
            <props> 
                <!-- 一定要异常的全类名。 表示出现 ArrayIndexOutOfBoundsException异常,就跳转到error.jsp视图 -->
                <prop key="java.lang.ArrayIndexOutOfBoundsException">error</prop>
            </props>
        </property>
    </bean>

另外在/WEB-INF/jsp下新建一个error.jsp视图。因为上面配置的InternalResourceViewResolver视图解析器默认把error字符串解析为error.jsp视图。

error.jsp内容为:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" isELIgnored="false" %>
<!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>
<h1>Error Page</h1>
${requestScope.exception}
</body>
</html>

下面发送Http请求后,控制器截获请求并处理请求时,数组越界抛出一个ArrayIndexOutOfBoundsException一个异常,此时由SimpleMappingExceptionResolver异常解析!

3、AnnotationMethodHandlerExceptionResolver —— 注解配置异常

Spring MVC 默认注册了 AnnotationMethodHandlerExceptionResolver,它允许通过@ExceptionHandler注解指定处理特定异常的方法!

    // 使用注解捕获指定异常
    @ExceptionHandler(value = {RuntimeException.class})
    public ModelAndView handleArithmeticException2(Exception exception) {
        System.out.println("[出异常了]:" + exception);
        ModelAndView mv = new ModelAndView("error");
        mv.addObject("exception", exception);
        return mv;
    }

    // 使用注解捕获指定异常
    @ExceptionHandler(value = {ArithmeticException.class})
    public ModelAndView handleArithmeticException(Exception exception) {
        System.out.println("出异常了,算术异常:" + exception);
        ModelAndView mv = new ModelAndView("error");
        mv.addObject("exception", exception);
        return mv;
    }

    // 测试异常的方法
    @RequestMapping("/testExceptionHandler")
    public String test2() {
        int i = 100 / 0;
        return "success";
    }

目标方法内抛出了一个ArithmeticException异常,将由继承关系最近的异常处理捕捉到,即由handleArithmeticException捕捉到。 若将handleArithmeticException方法注释掉,则发生ArithmeticException异常将由handleArithmeticException2进行处理。

缺点:

使用该注解有一个不好的地方就是:进行异常处理的方法必须与出错的方法在同一个Controller里面

不能全局控制异常。每个类都要写一遍。

4、@ControllerAdvice——注解全局异常处理

上文说到 @ ExceptionHandler 需要进行异常处理的方法必须与出错的方法在同一个 Controller里面。那么当代码加入了 @ControllerAdvice,则不需要必须在同一个controller 中了。

这也是 Spring 3.2 带来的新特性。从名字上可以看出大体意思是控制器增强。

也就是说,@controlleradvice + @ ExceptionHandler 也可以实现全局的异常捕捉。 请确保此WebExceptionHandle 类能被扫描到并装载进 Spring 容器中。

/**
 * @author swadian
 * @date 2021/2/7
 * @Version 1.0
 * @describetion
 */
@Controller
@ControllerAdvice
public class WebExceptionHandle {

    @ExceptionHandler(Exception.class)
    public ModelAndView handleException(Exception ex) {
        System.out.println("全局异常:ex = " + ex);
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("error");
        modelAndView.addObject("exception", ex);
        return modelAndView;
    }

}

开启注解扫描

    <!--扫描控制层的包-->
    <context:component-scan base-package="com.test.controller"/>
    <!--注解驱动 -->
    <mvc:annotation-driven/>

若在其他的由@Controller标记的Handler类中的Handle方法抛出异常,且没有在Handler类中定义@ExceptionHandler方法,则会去由@ControllerAdvice标记的类中去找,若也找不到,则在页面抛出异常。

猜你喜欢

转载自blog.csdn.net/swadian2008/article/details/113746405