Java异常的统一返回处理

一,异常分类

            java异常分为"检查"和"非检查"两类,"检查"二字的意思是,代码编译时,编译器会去Check一下有没有进行异常处理(捕获或向上抛),对于归类为需要检查的异常,若没处理,编译就过不去。
            初学的时候,常常想为啥异常要这样分类处理? 后来明白了些,异常不过两种:主观和客观,一个大多数情况下可以避免,一个大多数情况下无法避免。
            像NullPointerException这类异常,大多跟程序员素质挂钩(开发好,测试好, 基本不会在系统运行后蹦出来), 基本是可以避免的,java语法当初把它们对类为‘非检查异常',也算给程序员和编译器省了不少事;
            而像IOException这类跟外在环境有关的异常,几乎是不可避免的(指不定哪一天那一秒网络就挂了),但是当不期而遇时,程序还是要有所作为,所以编译器有必要督促一下程序员,Check一下,看看是是否对这些可能不期而至的异常进行了处理。当Exception对象传递到某个节点后,程序就可以执行一些措施了,比如:给用户返回一个提示("系统繁忙,请重试"),给监控平台推送一个异常消息等等。

二,异常的统一返回处理

1,容器处理

下面列举Tomcat的处理方式,在web.xml下配置,按http返回码或Exception类型来处理:

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

缺点:无法处理不需要返回html的请求,比如ajax;

2,框架处理

下面列举Spring MVC的处理方式

(1)使用Spring MVC自带的简单异常处理器SimpleMappingExceptionResolver; 
(2)实现接口HandlerExceptionResolver 自定义异常处理器; (建议使用,可支持ajax等扩展)
(3)使用@ExceptionHandler注解实现异常处理; 

(1)种,在spring-mvc.xml下配置

 <!-- 将Controller抛出的异常转到特定视图 -->
    <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
        <property name="exceptionMappings">
            <props>
             <!-- 不同异常分开跳转-->    
             <!-- 可以自定义不同的异常-->              
                <prop key="com.test.MyException1">/error/e1</prop>
                <prop key="com.test.MyException2">/error/e2</prop>
                <!-- 如果不想自定义异常,只配置下面的即可--> 
                <prop key="java.lang.Throwable">/error/500</prop>
            </props>
        </property>
    </bean>

缺点:无法处理不需要返回html的请求;

 

 第(2)种,自定义HandlerExceptionResolver接口的实现类

/**
 * 自定义异常处理器:支持ajax
 * @author wangxu
 *
 */
public class MyExceptionHandler implements HandlerExceptionResolver {
 
 public ModelAndView resolveException(HttpServletRequest request,
   HttpServletResponse response, Object handler, Exception ex) {
  
  /* 区分ajax */
  boolean isAjax = request.getHeader("X-Requested-With") != null
    && "XMLHttpRequest".equals(request
      .getHeader("X-Requested-With").toString());
  if (!isAjax) {
   if (ex instanceof com.test.MyException1) {
    return new ModelAndView("/error/e1");
   } else if (ex instanceof com.test.MyException1) {
    return new ModelAndView("/error/e2");
   } else {
    return new ModelAndView("/error/500");
   }
  }
  String jsonRes = "{\"message\":\"" + "系统异常" + "\"}";// 自定义结构和前台对接
  PrintWriter out = null;
  try {
   out = response.getWriter();
   request.setCharacterEncoding("utf-8");
   response.setContentType("text/plain;charset=utf-8");
   out.print(jsonRes);
   out.flush();
  } catch (IOException e) {
   e.printStackTrace();
  } finally {
   out.close();
  }
  return null;
 }
}

 并在spring-mvc.xml下注册处理器

<bean id="exceptionHandler" class="com.test.MyExceptionHandler"/>

优点可以处理ajax请求,也方便编码实现功能扩展,比如异常的监控等。

 

第(3)种,@ExceptionHandler注解

@Controller
public class TestExceptionHandlerController {
 
 @ExceptionHandler({ MyException1.class })
 public String exception(MyException1 e) {
  return "/error/e1";
 }
 @RequestMapping("/marry")
 public void test() {
  throw new MyException1("没钱!");
 }
}

缺点:@ExceptionHandler的方法,必须和可能抛异常的方法在一同个Controller下。(不建议使用)

3,结合 

实际项目中,往往会将http返回码的映射交给容器,将一些自定义的业务异常或者扩展交给框架。

因为框架是运行在容器之下,所以框架会优先拿到异常,如果框架做了返回处理,容器就不会再进行映射。

你可能感兴趣的:(web.xml配置异常)