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)); }
参考: