Spring MVC 使用介绍(九)—— 异常处理

一、概述

Spring MVC异常处理功能的作用为:捕捉处理器的异常,并映射到相应视图

有4种方式: 

  • SimpleMappingExceptionResolver:通过配置的方式实现异常处理,该方式简单、无侵入性,但仅能获取到异常信息
  • HandlerExceptionResolver:通过实现该接口并实例化为bean实现异常处理,该方式简单、无侵入性,并能够获取关于异常的更详细信息
  • @ExceptionHandler:通过在控制器类或控制器类的基类中添加异常处理方法,从而实现单个控制器范围的异常处理,该方法对已有代码有侵入性
  • web.xml的<error-page>标签:可通过异常类型或error-code指定异常页面

多种方式的并存会增大维护的成本,因此异常处理方式选择其中一种,推荐使用SimpleMappingExceptionResolver,再配合web.xml中的<error-page>即可

简单示例:

异常类

public class BusinessException extends RuntimeException {

    private String errorCode;
    
    public BusinessException(String errorCode, String msg) {
        super(msg);
        this.setErrorCode(errorCode);
    }

    public String getErrorCode() {
        return errorCode;
    }

    public void setErrorCode(String errorCode) {
        this.errorCode = errorCode;
    }
}
public class ParameterException extends RuntimeException {
    
    public ParameterException(String msg) {
        super(msg);
    }
}

控制器

@Controller  
public class TestController9 {  
      
    @RequestMapping(value = "/controller.do", method = RequestMethod.GET)  
    public void controller(HttpServletResponse response, Integer id) throws Exception {
        switch(id) {  
            case 1:  
                throw new BusinessException("10", "controller10");  
            case 2:  
                throw new BusinessException("20", "controller20");  
            default:  
                throw new ParameterException("Controller Parameter Error");  
        }  
    }   
}  

配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:mvc="http://www.springframework.org/schema/mvc" 
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
           http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
           http://www.springframework.org/schema/mvc 
           http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
           http://www.springframework.org/schema/context 
           http://www.springframework.org/schema/context/spring-context-4.2.xsd">
          

    <mvc:annotation-driven />
    
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">  
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>  
        <property name="prefix" value="/WEB-INF/jsp/"/>  
        <property name="suffix" value=".jsp"/>  
    </bean>  
    
    <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">  
        <!-- 定义默认的异常处理页面 -->  
        <property name="defaultErrorView" value="error"></property>  
        <!-- 定义异常处理页面用来获取异常信息的变量名,默认名为exception -->
        <property name="exceptionAttribute" value="ex"></property>  
        <!-- 定义需要特殊处理的异常,用类名或完全路径名作为key,异常页名作为值   -->
        <property name="exceptionMappings">  
            <props>  
                <prop key="cn.matt.exception.BusinessException">error-business</prop>  
                <prop key="cn.matt.exception.ParameterException">error-parameter</prop>  
            </props>  
        </property>  
    </bean>
    
    <context:component-scan base-package="cn.matt" use-default-filters="false">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
        <context:include-filter type="annotation" expression="org.springframework.web.bind.annotation.RestController" />
    </context:component-scan>
</beans>

error.jsp、error-business.jsp、error-parameter.jsp

<%@ page contentType="text/html; charset=UTF-8"%>
<html>
<head><title>Exception!</title></head>
<body>
<% Exception e = (Exception)request.getAttribute("ex"); %>
<H2>业务错误: <%= e.getClass().getSimpleName()%></H2>
<hr />
<P>错误描述:</P>
<%= e.getMessage()%>
<P>错误信息:</P>
<% e.printStackTrace(new java.io.PrintWriter(out)); %>
</body>
</html>

启动后,访问 http://localhost:8080/myweb/controller.do?id=1 即可验证

 

二、SimpleMappingExceptionResolver

<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">  
    <!-- 定义默认的异常处理页面,当该异常类型的注册时使用 -->  
    <property name="defaultErrorView" value="error"></property>  
    <!-- 定义异常处理页面用来获取异常信息的变量名,默认名为exception   -->
    <property name="exceptionAttribute" value="ex"></property>  
    <!-- 定义需要特殊处理的异常,用类名或完全路径名作为key,异常也页名作为值   -->
    <property name="exceptionMappings">  
        <props>  
            <prop key="cn.matt.exception.BusinessException">error-business</prop>  
            <prop key="cn.matt.exception.ParameterException">error-parameter</prop>  
  
            <!-- 这里还可以继续扩展对不同异常类型的处理   -->
        </props>  
    </property>  
</bean>

使用SimpleMappingExceptionResolver进行异常处理,具有集成简单、有良好的扩展性、对已有代码没有入侵性等优点,但该方法仅能获取到异常信息,若在出现异常时,对需要获取除异常以外的数据的情况不适用

具体如上例

 

三、HandlerExceptionResolver

@Component
public class MyExceptionHandler implements HandlerExceptionResolver {  
      
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {  
        Map<String, Object> model = new HashMap<String, Object>();  
        model.put("ex", ex);  
          
        // 根据不同错误转向不同页面  
        if(ex instanceof BusinessException) {  
            return new ModelAndView("error-business", model);  
        }else if(ex instanceof ParameterException) {  
            return new ModelAndView("error-parameter", model);  
        } else {  
            return new ModelAndView("error", model);  
        }  
    } 
}  

使用实现HandlerExceptionResolver接口的异常处理器进行异常处理,具有集成简单、有良好的扩展性、对已有代码没有入侵性等优点,同时,在异常处理时能获取导致出现异常的对象,有利于提供更详细的异常处理信息。

测试方式为:在上例配置文件中注释掉SimpleMappingExceptionResolver的配置,并添加HandlerExceptionResolver的上述代码即可

 

四、@ExceptionHandler

@Controller  
public class TestController9 {  
      
    @RequestMapping(value = "/controller.do", method = RequestMethod.GET)  
    public void controller(HttpServletResponse response, Integer id) throws Exception {
        switch(id) {  
            case 1:  
                throw new BusinessException("10", "controller10");  
            case 2:  
                throw new BusinessException("20", "controller20");  
            default:  
                throw new ParameterException("Controller Parameter Error");  
        }  
    }   
    
    @ExceptionHandler  
    public String exp(HttpServletRequest request, Exception ex) {  
          
        request.setAttribute("ex", ex);  
          
        // 根据不同错误转向不同页面  
        if(ex instanceof BusinessException) {  
            return "error-business";  
        }else if(ex instanceof ParameterException) {  
            return "error-parameter";  
        } else {  
            return "error";  
        }  
    }  
}

使用@ExceptionHandler注解实现异常处理,具有集成简单、扩展性好、不需要附加Spring配置等优点,但该方法对已有代码存在入侵性,在异常处理时不能获取除异常以外的数据。

测试方式为:在上例配置文件中注释掉SimpleMappingExceptionResolver的配置,并将控制器修改为上述代码即可

 

五、web.xml的<error-page>标签

对于非控制器产生的异常,如404,spring mvc的异常机制无法捕获,此类异常可在web.xml中通过<error-page>节点配置显示页面

<error-page>  
    <exception-type>java.lang.Throwable</exception-type>  
    <location>/500.jsp</location>  
</error-page>  
<error-page>  
    <error-code>500</error-code>  
    <location>/500.jsp</location>  
</error-page>  
<error-page>  
    <error-code>404</error-code>  
    <location>/404.jsp</location>  
</error-page> 

 

补充:

异常输出为json字符串(而非页面)的方式如下:

@ExceptionHandler  
public void exp(HttpServletRequest request, HttpServletResponse response, Exception ex) throws IOException {  
      
    response.setContentType("text/plain;charset=UTF-8");
    response.setHeader("Pragma", "No-cache");
    response.setHeader("Cache-Control", "no-cache");
    response.setDateHeader("Expires", 0);
    
    Map<String, Object> map = new HashMap<String, Object>();
    map.put("errorCode", 200);
    map.put("errorMsg", ex.getMessage());
    response.getWriter().write(JSON.toJSONString(map));
}  

 

参考:

使用Spring MVC统一异常处理实战

springmvc处理异常的4种方式

Spring MVC 异常处理详解

posted @ 2018-06-20 14:58  Matt_Cheng  阅读(367)  评论(0编辑  收藏  举报