中国领先的IT技术网站
|
|

真实项目实践:快速定位 Spring MVC异常实战(附源码下载)

Spring MVC处理异常有3种方式: (1)使用@ExceptionHandler注解实现异常处理; (2)使用Spring MVC提供的简单异常处理器SimpleMappingExceptionResolver; (3)实现Spring的异常处理接口HandlerExceptionResolver 自定义自己的异常处理器。

作者:两只蜗牛来源:两只蜗牛的博客|2015-01-09 10:01

沙龙活动 | 去哪儿、陌陌、ThoughtWorks在自动化运维中的实践!10.28不见不散!


一、使用@ExceptionHandler进行处理

1.创建异常基类,使用@ExceptionHandler声明异常处理

BusinessException和SystemException为自定义异常类,代码如下:

  1. package com.twosnail.exception;  
  2.    
  3. import javax.servlet.http.HttpServletRequest;  
  4. import org.springframework.stereotype.Controller;  
  5. import org.springframework.web.bind.annotation.ExceptionHandler;  
  6.    
  7. @Controller 
  8. public class BasicExController {  
  9.     /**  
  10.      * 基于@ExceptionHandler异常处理基类  
  11.      * @return  
  12.      */ 
  13.     @ExceptionHandler 
  14.     public String exception( HttpServletRequest request , Exception ex ) {  
  15.            
  16.     // 根据不同错误转向不同页面    
  17.         if( ex instanceof BusinessException ) {  
  18.             return "business-error";    
  19.         }else if( ex instanceof SystemException ) {   
  20.             return "system-error";  
  21.         } else {  
  22.             return "error";    
  23.         }  
  24.     }  

2、使所有需要异常处理的Controller都继承该类,如下所示:

  1. public class DemoController extends BasicExController {} 

然而,Dao层、Service层、Controller层抛出的异常(BusinessException、SystemException和其它异常)都能准确显示定义的异常处理页面,达到了统一异常处理的目标。

总结:使用@ExceptionHandler注解实现异常处理,具有集成简单、有扩展性好(只需要将要异常处理的Controller类继承于BasicExController即可)、不需要附加Spring配置等优点,但该方法对已有代码存在入侵性(需要修改已有代码,使继承于BasicExController),在异常处理时不能获取除异常以外的数据。

二、SimpleMappingExceptionResolver简单异常处理器

SimpleMappingExceptionResolver有两种配置方式,可以按自己需求而定,配置代码如下:

1、第一种,在Spring的配置文件中,增加以下内容:

在这里,可以设置跳转相应页面。

  1. <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">  
  2.     <!-- 定义默认的异常处理页面,当该异常类型的注册时使用 -->  
  3.     <property name="defaultErrorView" value="error"></property>  
  4.     <!-- 定义异常处理页面用来获取异常信息的变量名,默认名为exception -->  
  5.     <property name="exceptionAttribute" value="ex"></property>  
  6.     <!-- 定义需要特殊处理的异常,用类名或完全路径名作为key,异常也页名作为值 -->  
  7.     <property name="exceptionMappings">  
  8.         <props>  
  9.             <prop key="com.twosnail.exception.BusinessException">business-error</prop>  
  10.             <prop key="com.twosnail.exception.SystemException">system-error</prop>  
  11.         </props>  
  12.     </property>  
  13.    
  14.     <!-- 相关状态码对应的错误页面 -->  
  15.     <property name="statusCodes">  
  16.         <props>  
  17.             <prop key="errors/500">500</prop>  
  18.             <prop key="errors/404">404</prop>  
  19.         </props>  
  20.     </property>  
  21.     <!-- 设置日志输出级别,不定义则默认不输出警告等错误日志信息 -->  
  22.     <property name="warnLogCategory" value="WARN" />  
  23.     <!-- 默认HTTP状态码 -->  
  24.     <property name="defaultStatusCode" value="500" />  
  25. </bean> 

2、第二种,通过自定义java类,继承SimpleMappingExceptionResolver

然后在Spring的配置。代码如下:

  1. <bean id="exceptionResolver" class="com.twosnail.exception.MyselfSimpleMappingExceptionResolver">  
  2.     <property name="exceptionMappings">  
  3.         <props>  
  4.             <prop key="com.twosnail.exception.SystemException">error/500</prop>  
  5.             <prop key="com.twosnail.exception.BusinessException">error/errorpage</prop>  
  6.             <prop key="java.lang.exception">error/500</prop>  
  7.         </props>  
  8.     </property>  
  9. </bean> 

java类代码如下,在这里可以处理相应逻辑,如下,分别处理了jsp页面和json数据:

  1. package com.twosnail.exception;  
  2.    
  3. import java.io.IOException;  
  4. import java.io.PrintWriter;  
  5. import javax.servlet.http.HttpServletRequest;  
  6. import javax.servlet.http.HttpServletResponse;  
  7. import org.springframework.web.servlet.ModelAndView;  
  8. import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;  
  9.    
  10. public class MyselfSimpleMappingExceptionResolver extends SimpleMappingExceptionResolver {  
  11.    
  12.     @Override 
  13.     protected ModelAndView doResolveException(HttpServletRequest request,  
  14.             HttpServletResponse response, Object handler, Exception ex) {  
  15.         // Expose ModelAndView for chosen error view.  
  16.         String viewName = determineViewName(ex, request);  
  17.         if (viewName != null) {// JSP格式返回  
  18.             if (!(request.getHeader("accept").indexOf("application/json") > -1 || (request  
  19.                     .getHeader("X-Requested-With") != null && request  
  20.                     .getHeader("X-Requested-With").indexOf("XMLHttpRequest") > -1))) {  
  21.                 // 如果不是异步请求  
  22.                 // Apply HTTP status code for error views, if specified.  
  23.                 // Only apply it if we're processing a top-level request.  
  24.                 Integer statusCode = determineStatusCode(request, viewName);  
  25.                 if (statusCode != null) {  
  26.                     applyStatusCodeIfPossible(request, response, statusCode);  
  27.                 }  
  28.                 return getModelAndView(viewName, ex, request);  
  29.             } else {// JSON格式返回  
  30.                 try {  
  31.                     PrintWriter writer = response.getWriter();  
  32.                     writer.write(ex.getMessage());  
  33.                     writer.flush();  
  34.                 } catch (IOException e) {  
  35.                     e.printStackTrace();  
  36.                 }  
  37.                 return null;  
  38.    
  39.             }  
  40.         } else {  
  41.             return null;  
  42.         }  
  43.     }  

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

三、HandlerExceptionResolver自定义异常

1.在Spring的配置文件中,增加以下内容:

  1. <bean id="exceptionHandler" class="com.twosnail.exception.MyExceptionHandler"/> 

2.添加自定义的MyExceptionHandler类,代码如下:

在这里,单独打印出了异常路径,便于在日志中查看,在对SystemException异常进行了特殊处理:

  1. package com.twosnail.exception;  
  2.    
  3. import java.util.Map;  
  4.    
  5. import javax.servlet.http.HttpServletRequest;  
  6. import javax.servlet.http.HttpServletResponse;  
  7. import org.springframework.web.servlet.HandlerExceptionResolver;  
  8. import org.springframework.web.servlet.ModelAndView;  
  9. import org.springframework.web.servlet.View;  
  10. import org.springframework.web.servlet.view.RedirectView;  
  11.    
  12. public class MyExceptionHandler implements HandlerExceptionResolver {  
  13.    
  14.     public ModelAndView resolveException( HttpServletRequest request, HttpServletResponse response,   
  15.             Object handler, Exception exception ) {  
  16.            
  17.         System.out.println( "【抛出异常】--异常路径为:" +   
  18.             request.getServletPath() + "\n【异常信息】--" +  exception.getMessage() ) ;  
  19.         //如果不是抛出的action业务异常则不处理  
  20.         if( !( exception instanceof SystemException ) ) {  
  21.             return null;  
  22.         }  
  23.            
  24.         final SystemException actionE = (SystemException) exception;         
  25.         ModelAndView model = null;  
  26.         if( actionE.getForwardType() == SystemException.FORWARD ) {  
  27.                 //进入页面渲染  
  28.                 model = new ModelAndView( actionE.getModelPath(), actionE.getAttributes());  
  29.         } else if( actionE.getForwardType() == SystemException.REDIRECT ) {  
  30.                 model = new ModelAndView( new RedirectView( actionE.getModelPath(), true));  
  31.         } else {  
  32.             //直接返回页面内容  
  33.             model = new ModelAndView( new View() {  
  34.                 @Override 
  35.                 public void render(Map<String, ?> arg0, HttpServletRequest arg1,  
  36.                         HttpServletResponse arg2) throws Exception {  
  37.                        
  38.                     arg2.setContentType( "text/html" );  
  39.                     arg2.setCharacterEncoding( actionE.getEncode() );  
  40.                     if( actionE.getResponseBody() != null ) {  
  41.                         arg2.getWriter().print( actionE.getResponseBody() );  
  42.                     }  
  43.                 }  
  44.                    
  45.                 @Override 
  46.                 public String getContentType() {  
  47.                     return "text/html; charset=utf-8";  
  48.                 }  
  49.             } );  
  50.         }  
  51.            
  52.         return model;  
  53.     }  

总结:从上面的集成过程可知,使用实现HandlerExceptionResolver接口的异常处理器进行异常处理,具有集成简单、有良好的扩展性、对已有代码没有入侵性等优点。在异常处理时能获取导致出现异常的对象,有利于提供更详细的异常处理信息。而SimpleMappingExceptionResolver就是HandlerExceptionResolver的默认实现类。

四、项目截图

代码地址:twosnail源码地址

参考资料:使用Spring MVC统一异常处理实战

原创作者:两只蜗牛

【编辑推荐】

  1. Spring MVC拦截器实现分析
  2. Spring MVC数据绑定的扩展
  3. 领略Spring 3.x时代的Spring MVC
  4. 快速开发和部署 Spring MVC 和 GWT 应用程序
  5. Spring MVC+JQuery+Google Map打造IP位置查找应用
【责任编辑:林师授 TEL:(010)68476606】

点赞 0
分享:
大家都在看
猜你喜欢

读 书 +更多

游戏开发核心技术--剧本和角色创造

《游戏开发核心技术--剧本和角色创造》分“剧本”、“角色”和“游戏玩法”三部分,第一部分着重说明故事的历史、一般故事元素、传统故事设...

订阅51CTO邮刊

点击这里查看样刊

订阅51CTO邮刊
× Python最火的编程语言