前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring 全家桶之 Spring Web MVC(九)- Exception

Spring 全家桶之 Spring Web MVC(九)- Exception

作者头像
RiemannHypothesis
发布2022-08-19 16:28:05
4360
发布2022-08-19 16:28:05
举报
文章被收录于专栏:Elixir

一、Spring MVC 的异常处理流程

Spring MVC 中通过HandlerExceptionResolver处理程序的异常,包括Handler映射数据绑定以及木币方法执行时发生的异常

Spring MVC 提供了HandlerExceptionResolver的实现类

image.png
image.png

默认提供了三个HandlerExceptionResolver

image.png
image.png

在controller包中新增一个HandlerExceptionController

代码语言:javascript
复制
@Controller
public class HandlerExceptionController {

    @RequestMapping("/handler")
    public String handler(Integer x){
        int res = 10 / x;
        System.out.println(x);
        return "success";
    }
}

启动应用,在浏览器输入http://localhost:8080/handler?x=0

image.png
image.png

这个报错页面是由Tomcat提供的,并不是Spring MVC提供的。

在DispatcherServlet的doDispatch()方法的1067行打上断点,开启Debug模式,在浏览器输入http://localhost:8080/handler?x=0

image.png
image.png

1067行代码就是执行目标方法,并且此时dispatchException=null,此时没有异常,待目标方法执行后就是出现异常,点击Step Over进入异常处理

image.png
image.png

目标方法中的异常出现,并赋值各个dispatchException,继续点击Step Over,并Step Into 到processDispatchResult方法中

image.png
image.png

此时异常不为空,并且异常类型不是if条件中的异常类型所以会直接进入esle代码块中,继续Step Over 到processHandlerException方法执行的这一行,并且Step Into 到processHandlerException方法中,该方法返回一个ModelAndView类

image.png
image.png

进入Step Over,进入到for循环中

image.png
image.png

此时就出现了前面说的Spring MVC 默认配置的三个HandlerExceptionResolver,在这个for循环中3个异常解析器会逐个解析 by zero这个异常,继续Step Over

image.png
image.png

多次点击Step Over,可以确定默认配置的三个异常解析器都无法解析 by zero 这个异常,也就是说Spring MVC最终不会返回任何的页面,我们看到的页面是Tomcat提供的错误页面

Spring MVC 默认配置的三个异常解析器的使用场景

  • ExceptionHandlerExceptionResolver:解析@ExceptionHandler注解标注的异常
  • ResponseStatusExceptionResolver:解析@ResponseStatus注解标注的异常
  • DEfaultHandlerExceptionResolver:判断是否是Spring MVC自带的异常

二、ExceptionHandlerExceptionResolver

ExceptionHandlerExceptionResolver异常处理器用于处理@ExceptionHandler注解指定的异常,在HandlerExceptionController中handler()方法中增加可能会出现异常的代码

代码语言:javascript
复制
@RequestMapping("/handler")
public String handler(Integer x){
    int res = 10 / x;
    System.out.println(x);
    return "success";
}

在HandlerExceptionController中增加异常处理方法,使用@ExceptionHandler注解指定能处理的异常类型

代码语言:javascript
复制
// 专门处理异常的方法,指定类型
@ExceptionHandler(Exception.class)
public String handlerExceptionAlpha(){
    System.out.println("handlerExceptionAlpha()方法运行了");
    // 返回自定义的错误页面
    return "error";
}

在pages目录下新增一个错误页面error.jsp

代码语言:javascript
复制
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h2>这是自定义的错误页面</h2>
</body>
</html>

重新启动应用,浏览器输入 localhost:8080/handler?x=0

image.png
image.png

能够返回自定义的页面,但是没有显示异常信息。想要获取异常信息可以在方法中返回ModelAndView,将错误信息放在ModelAndView中,再从页面中取出

代码语言:javascript
复制
// 专门处理异常的方法,指定类型
// 直接返回ModelAndView,将异常信息方法封装在类中
@ExceptionHandler(Exception.class)
public ModelAndView handlerException(Exception e){
    System.out.println("handlerException()方法运行了");
    ModelAndView mv = new ModelAndView("error");
    mv.addObject("e", e);
    return mv;
}

在页面中取出异常信息

代码语言:javascript
复制
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h2>这是自定义的错误页面</h2>
    <h3>错误信息为以下内容</h3>
    <p>${e}</p>
</body>
</html>

重新启动应用,再次输入 localhost:8080/handler?x=0

image.png
image.png

页面中成功显示出异常信息

全局处理异常

显然在Controller类中书写异常处理方法很不优雅,可以新建一个exception包,新建一个GlobalExceptionResolver全局异常处理类,该类需要添加一个@ControllerAdvice类,告诉Spring MVC这是一个异常处理类,将HandlerExceptionController中的异常处理方法移到该类中,HandlerExceptionController中只保留handler()方法

代码语言:javascript
复制
@ControllerAdvice
public class GlobalExceptionResolver {

    // 专门处理异常的方法,指定类型
    // 直接返回ModelAndView,将异常信息方法封装到对象中
    @ExceptionHandler(Exception.class)
    public ModelAndView handlerException(Exception e){
        System.out.println("全局handlerException()方法运行了");

        ModelAndView mv = new ModelAndView("error");
        mv.addObject("e", e);
        return mv;
    }

    @ExceptionHandler(ArithmeticException.class)
    public ModelAndView handlerArithmeticException(Exception e){
        System.out.println("全局handlerArithmeticException()方法运行了");

        ModelAndView mv = new ModelAndView("error");
        mv.addObject("e", e);
        return mv;
    }
}

再次启动应用

image.png
image.png

控制台输出是由lhandlerArithmeticException处理的这个异常

image.png
image.png

如果有多个异常的情况下可以写多个异常处理的方法,指定处理的异常可以是具体的异常也可以是Exception类,当同时出现时精确匹配优先

在HandlerExceptionController中增异常处理方法,处理Exception类异常

代码语言:javascript
复制
// 专门处理异常的方法,指定类型
// 直接返回ModelAndView,将异常信息方法封装到对象中
@ExceptionHandler(Exception.class)
public ModelAndView handlerException(Exception e){
    System.out.println(this.getClass().getName() + "类中的handlerException()方法运行了");

    ModelAndView mv = new ModelAndView("error");
    mv.addObject("e", e);
    return mv;
}

重新启动该应用

image.png
image.png

根据控制台的输出,可以确定不管是否是精确匹配,优先使用同一个类下的异常处理方法来处理异常

三、ResponseStatusExceptionResolver

如果想要处理自定义的异常,则需要用到@ResponseStatus注解来标注,该注解不能标在方法上。在handler()方法上标注@ResponseStatus注解,看看会发生什么

image.png
image.png

这会导致正常页面也出现报错

该注解需要标在自定义异常类上,HandlerExceptionController中新增一个方法handlerAlpha()

代码语言:javascript
复制
@RequestMapping("/alpha")
public String handlerAlpha(@RequestParam("username") String username){
    if (!"admin".equals(username)){
        System.out.println("不是Admin,登录失败");
        throw new NonAdminException();
    }
    return "success";
}

定义一个异常类,当非管理员登录时抛出该异常

代码语言:javascript
复制
@ResponseStatus(value = HttpStatus.CONFLICT, reason = "不是管理员不能登录,走吧走吧.....")
public class NonAdminException extends RuntimeException {


}

重启应用,当username为admin时,输出sucess页面

image.png
image.png

不是admin时,输出了指定的错误页面,并输出了异常信息

image.png
image.png
image.png
image.png

根据控制台的输出,可以确定该异常是被同一类下的异常处理方法处理的;注释HandlerExceptionController中的异常处理方法,将GlobalEXception中的Exception异常处理也注释掉;再次重启,浏览器中输入http://localhost:8080/alpha?username=admin111

image.png
image.png

四、DefaultHandlerExceptionResolver

HandlerExceptionController中新增一个方法

代码语言:javascript
复制
@PostMapping(value = "/bravo")
public String handlerBravo(){
    return "success";
}

该方法是POST方法,重启应用,浏览器中输入localhost:8080/bravo

image.png
image.png

页面中的这段异常信息就是Spring MVC自定义的异常中的信息。开启GlobalException中的Exception处理方法

image.png
image.png

当GlobalException中的Exception处理方法被注释掉时,就是默认的DefaultHandlerExceptionResolver进行的处理

启动DEBUG模式,点击首页的bravo超链接

image.png
image.png

进入循环异常处理器列表的代码块中

image.png
image.png

多次Step Over后,只有DefaultHandlerExceptionResolver,可以处理这类异常

image.png
image.png

Step Into 到resolveException()这个方法中

image.png
image.png

继续Step Over

image.png
image.png

进入这个doResolveException()方法中

image.png
image.png

这里就包含了请求方法不支持的异常,也就是我们出现的异常

五、SimpleMappingExceptionResolver

SimpleMappingExceptionResolver是通过配置来进行异常处理的,在Spring MVC 配置文件中配置这个异常处理器

代码语言:javascript
复制
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
    <property name="exceptionMappings">
        <props>
            <prop key="java.lang.NullPointerException">error</prop>
        </props>
    </property>
</bean>

注释掉异常处理中的Exception异常处理方法,在HandlerExceptionController 新增一个方法模拟空指针异常

代码语言:javascript
复制
@RequestMapping("/charlie")
public String handleCharlie(){
    System.out.println("NullPointException.....");
    // 模拟空指针异常的情况
    String name = null;
    System.out.println(name.length());
    return "success";
}

index页面增加超链接

代码语言:javascript
复制
<a href="/charlie">charlie</a>

重新启动应用,点击index页面的超链接

image.png
image.png

没有出现错误信息,需要将错误信息保存,并修改Spring MVC配置文件才可以

代码语言:javascript
复制
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
    <!-- exceptionMappings:配置哪些异常去哪些页面 -->
    <property name="exceptionMappings">
        <props>
            <!-- key:异常全类名;value:要去的页面视图名; -->
            <prop key="java.lang.NullPointerException">error</prop>
        </props>
    </property>
    <!--指定错误信息取出时使用的key  -->
    <property name="exceptionAttribute" value="e"></property>
</bean>

error页面通过配置的e或者默认的exception来去除错误信息

{e} - {exception}

image.png
image.png

如果全局异常处理存在处理空指针的方法

image.png
image.png

会优先使用全局的异常处理来处理,如果全部不能处理,在使用配置的方式处理

开启Debug模式

image.png
image.png

现在有四个全局异常处理器,SimpleMapping排在最后,第一个异常处理器就可以将这类异常处理掉,处理完成之后就不会使用其余3个异常处理器处理异常了。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-04-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、Spring MVC 的异常处理流程
  • 二、ExceptionHandlerExceptionResolver
    • 全局处理异常
    • 三、ResponseStatusExceptionResolver
    • 四、DefaultHandlerExceptionResolver
    • 五、SimpleMappingExceptionResolver
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档