SpringMVC学习记录(三)--异常处理

springMVC提供的异常处理主要有两种方式,一种是直接实现自己的HandlerExceptionResolver,当然这也包括使用Spring已经为我们提供好的SimpleMappingExceptionResolver和DefaultHandlerExceptionResolver,另一种是使用注解的方式实现一个专门用于处理异常的Controller——ExceptionHandler。和之前一样,前者相当于全局管理的异常,后者只针对当前controller有效


1.全局异常

1.创建异常并配置

首先定义一个全局异常类,可以看出这个类会把异常打印在控制台,并且放入model中,以便可以在jsp页面上展示出来

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;

public class MyExceptionResolver implements HandlerExceptionResolver{

    public ModelAndView resolveException(HttpServletRequest request,
            HttpServletResponse response, Object handler, Exception ex) {

        System.out.println("==============异常开始=============");
        ex.printStackTrace();
        System.out.println("==============异常结束=============");
        //设置返回页面为error.jsp
        ModelAndView mv = new ModelAndView("error");
        mv.addObject("exception", ex.toString().replaceAll("\n", "<br/>"));
        return mv;
    }
}

 

然后在error.jsp中显示异常

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html lang="en">
  <head>
  <meta charset="utf-8" />
<title>应用程序异常 (500)</title> 
</head> 
<body> 
  <div> 
    <h1>应用程序异常</h1> 
    <p>抱歉!您访问的页面出现异常,请稍后重试或联系管理员。</p> 
    <p><a href="#">详 情</a> 
<a href="javascript:history.back(-1)">返 回</a> 
    </p> 
    <div style="display:none;text-align: left;" id="err">${exception }</div>
  </div>
</body> 
</html>

接着在springMVC.xml中配置这个异常

    <!--配置全局异常类-->
    <bean id="exceptionResolver" class="main.java.controller.MyExceptionResolver"/>

2.使用上面的异常

在控制器里面模拟调用

    @RequestMapping(value = "/hello",method = RequestMethod.GET)
    public String hello(Model model){
        String str = "asbd123";
        //这里会报NumberFormatException异常,然后spring会自动捕捉这个异常
        int a = Integer.parseInt(str);

        return "hello";
    }

 

然后访问localhost:8888/hello,页面就会显示如下 
这里写图片描述

同样的再控制台会输出我们的异常信息 
这里写图片描述

到此这就是一个全局异常.


2.局部异常处理

局部异常使用使用@ExceptionHandler进行处理,具体如下

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

   //创建处理异常的类,这个类会处理当前控制器下的Myexception这个异常
    @ExceptionHandler(Myexception.class)
    public String getError(Myexception myexception,Model model){
        System.out.println("==============异常开始=============");
        myexception.printStackTrace();
        System.out.println("==============异常结束=============");
        model.addAttribute("exception",myexception.getMessage());
        return "error";
    }
    //当前这个请求会抛出异常
    @RequestMapping(value = "/hello",method = RequestMethod.GET)
    public String hello(Model model) throws Myexception {
        if (true){
            throw new Myexception("出错了");
        }

        return "hello";
    }

 

对应的JSP视图中会显示出相应的错误信息

这里写图片描述

对应的控制台也会输出相应的信息

这里写图片描述


3.异常优先级

既然在SpringMVC中有两种处理异常的方式,那么就存在一个优先级的问题: 
当发生异常的时候,SpringMVC会如下处理:

  1. SpringMVC会先从配置文件找异常解析器HandlerExceptionResolver
  2. 如果找到了异常异常解析器,那么接下来就会判断该异常解析器能否处理当前发生的异常
  3. 如果可以处理的话,那么就进行处理,然后给前台返回对应的异常视图
  4. 如果没有找到对应的异常解析器或者是找到的异常解析器不能处理当前的异常的时候,就看当前的Controller中有没有提供对应的异常处理器,如果提供了就由Controller自己进行处理并返回对应的视图
  5. 如果配置文件里面没有定义对应的异常解析器,而当前Controller中也没有定义的话,那么该异常就会被抛出来。

4.spring提供的异常模板

Spring实现了一个SimpleMappingExceptionResolver,这两者都是继承自抽象类AbstractHandlerExceptionResolver,而AbstractHandlerExceptionResolver是实现了HandlerExceptionResolver接口的resolveException方法的,并由此抽取出两个抽象方法,一个是在进行异常处理之前执行的方法prepareResponse(exception, response),一个是进行异常解析的doResolveException(request, response, handler, exception)方法。 
SimpleMappingExceptionResolver,顾名思义就是通过简单的映射关系来决定由哪个视图来处理当前的错误信息。SimpleMappingExceptionResolver提供了通过异常类型exceptionMappings来进行异常与视图之间的映射关系,提供了在发生异常时通过statusCodes来映射异常返回的视图名称和对应的HttpServletResponse的返回码。而且可以通过defaultErrorView和defaultErrorCode来指定默认值,defaultErrorView表示当没有在exceptionMappings里面找到对应的异常类型时就返回defaultErrorView定义的视图,defaultErrorCode表示在发生异常时当没有在视图与返回码的映射关系statusCodes里面找到对应的映射时默认返回的返回码。在使用SimpleMappingExceptionResolver时,当发生异常的时候,SimpleMappingExceptionResolver将会把当前的异常对象放到自身属性exceptionAttribute中,当没有指定exceptionAttribute时,exceptionAttribute就是用默认值exception。

下面试一个其xml代码的简单配置

    <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
        <property name="exceptionMappings">
            <props>
                <prop key="NumberFormatException">number</prop><!-- 表示当抛出NumberFormatException的时候就返回名叫number的视图 -->
                <prop key="NullPointerException">null</prop>
            </props>
        </property>
        <property name="defaultErrorView" value="exception"/><!-- 表示当抛出异常但没有在exceptionMappings里面找到对应的异常时 返回名叫exception的视图-->
        <property name="statusCodes"><!-- 定义在发生异常时视图跟返回码的对应关系 -->
            <props>
                <prop key="number">500</prop><!-- 表示在发生NumberFormatException时返回视图number,然后这里定义发生异常时视图number对应的HttpServletResponse的返回码是500 -->
                <prop key="null">503</prop>
            </props>
        </property>
        <property name="defaultStatusCode" value="404"/><!-- 表示在发生异常时默认的HttpServletResponse的返回码是多少,默认是200 -->
    </bean>

 

下面是引发这些异常的测试代码

@Controller
@RequestMapping("/test")
public class TestController {

    @RequestMapping("/null")
    public void testNullPointerException() {
        Blog blog = null;
        //这里就会发生空指针异常,然后就会返回定义在SpringMVC配置文件中的null视图
        System.out.println(blog.getId());
    }

    @RequestMapping("/number")
    public void testNumberFormatException() {
        //这里就会发生NumberFormatException,然后就会返回定义在SpringMVC配置文件中的number视图
        Integer.parseInt("abc");
    }

    @RequestMapping("/default")
    public void testDefaultException() {
        if (1==1)
            //由于该异常类型在SpringMVC的配置文件中没有指定,所以就会返回默认的exception视图
            throw new RuntimeException("Error!");
    }

}

 

最后在jsp页面中可以访问这些异常

<%@ page language="java" import="java.util.*" pageEncoding="GB18030" isErrorPage="true"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <base href="<%=basePath%>">

    <title>My JSP 'number.jsp' starting page</title>

    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    <meta http-equiv="description" content="This is my page">
    <!--
    <link rel="stylesheet" type="text/css" href="styles.css">
    -->

  </head>

  <body>
    NumberFormatException. <br>
    <%=exception.getMessage() %><br/>
    <%=exception %><br/><span style="color: #3366ff;"><!-- 这是JSP中的内置对象exception --></span>



    <%=request.getAttribute("ex") %><br><span style="color: #3366ff;"><!-- 这是SpringMVC放在返回的Model中的异常对象 --></span>



    <%=request.getAttribute("javax.servlet.error.status_code") %><span style="color: #3366ff;"><!-- HttpServletResponse返回的错误码信息,因为前面已经配置了NumberFormatException的错误码返回值为888,所以这里应该显示888 --></span>

  </body>
</html>

参考资料:http://www.makeru.com.cn/                 

posted @ 2018-04-24 10:47  慧心的眼眸  阅读(292)  评论(0编辑  收藏  举报