spring mvc 异常统一处理方式

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring mvc 异常统一处理方式相关的知识,希望对你有一定的参考价值。


springMVC提供的异常处理主要有两种方式,一种是直接实现自己的HandlerExceptionResolver,另一种是使用注解的方式实现一个专门用于处理异常的Controller——ExceptionHandler。

 

1、实现自己的HandlerExceptionResolver,HandlerExceptionResolver是一个接 口,springMVC本身已经对其有了一个自身的实现——DefaultExceptionResolver,该解析器只是对其中的一些比较典型的异常 进行了拦截处理。

 

  1. import javax.servlet.http.HttpServletRequest;   

  2. import javax.servlet.http.HttpServletResponse;   

  3.   

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

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

  6.   

  7. public class ExceptionHandler implements HandlerExceptionResolver {   

  8.   

  9.     @Override  

  10.     public ModelAndView resolveException(HttpServletRequest request,   

  11.             HttpServletResponse response, Object handler, Exception ex) {   

  12.         // TODO Auto-generated method stub   

  13.         return new ModelAndView("exception");   

  14.     }   

  15.   

  16. }  

 

 上述的resolveException的第4个参数表示对哪种类型的异常进行处理,如果想同时对多种异常进行处理,可以把它换成一个异常数组。

定义了这样一个异常处理器之后就要在applicationContext中定义这样一个bean对象,如:

  1. <bean id="exceptionResolver" class="com.tiantian.xxx.web.handler.ExceptionHandler"/>  

 

2、使用@ExceptionHandler进行处理获取【下载地址】  

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

如:

  1. import org.springframework.stereotype.Controller;   

  2. import org.springframework.web.bind.annotation.ExceptionHandler;   

  3. import org.springframework.web.bind.annotation.RequestMapping;   

  4.   

  5. import com.tiantian.blog.web.servlet.MyException;   

  6.   

  7. @Controller  

  8. public class GlobalController {   

  9.   

  10.        

  11.     /**  

  12.      * 用于处理异常的  

  13.      * @return  

  14.      */  

  15.     @ExceptionHandler({MyException.class})   

  16.     public String exception(MyException e) {   

  17.         System.out.println(e.getMessage());   

  18.         e.printStackTrace();   

  19.         return "exception";   

  20.     }   

  21.        

  22.     @RequestMapping("test")   

  23.     public void test() {   

  24.         throw new MyException("出错了!");   

  25.     }   

  26.        

  27.        

  28. }  

 

这里在页面上访问test方法的时候就会报错,而拥有该test方法的Controller又拥有一个处理该异常的方法,这个时候处理异常的方法就会被调用

  

当发生异常的时候,上述两种方式都使用了的时候,第一种方式会将第二种方式覆盖


 

最近使用spring mvc开发一个web系统,发现在controller里发生未捕获异常时不出日志。 

分析DispatcherServlet,初始化handlerExceptionResolvers

  1.         /**  

  2.      * Initialize the strategy objects that this servlet uses.  

  3.      * <p>May be overridden in subclasses in order to initialize  

  4.      * further strategy objects.  

  5.      */  

  6.     protected void initStrategies(ApplicationContext context) {   

  7.         initMultipartResolver(context);   

  8.         initLocaleResolver(context);   

  9.         initThemeResolver(context);   

  10.         initHandlerMappings(context);   

  11.         initHandlerAdapters(context);   

  12. // 初始化异常处理支持器   

  13.         initHandlerExceptionResolvers(context);   

  14.         initRequestToViewNameTranslator(context);   

  15.         initViewResolvers(context);   

  16.     }   

  17.   

  18. // 进入初始化处理方法,具体内容就不贴了,主要是先到上下文中搜寻我们自己定义的ExceptionResolvers,如果没有自定义的resolvers,从默认配置中读取。   

  19. private void initHandlerExceptionResolvers(ApplicationContext context)   

  20.   

  21. // 从默认策略中取得默认配置,从DispatcherServlet.properties文 件中取得相关的配置策略,但是在spring2.5的mvc jar包中properties文件中没有 HandlerExceptionResolver的默认配置,返回一个EmptyList给handlerExceptionResolvers   

  22. protected List getDefaultStrategies(ApplicationContext context, Class strategyInterface)  

Java代码  技术分享

  1. 分析DispatcherServlet,分发处理请求   

  1. // 从dispatch方法中看到,系统对请求进行具体的逻辑处理部分被catch住了一次exception,然后会使用servlet持有的ExceptionResolver进行处理   

  2. protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {   

  3.         HttpServletRequest processedRequest = request;   

  4.         HandlerExecutionChain mappedHandler = null;   

  5.         int interceptorIndex = -1;   

  6.   

  7.         // Expose current LocaleResolver and request as LocaleContext.   

  8.         LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();   

  9.         LocaleContextHolder.setLocaleContext(buildLocaleContext(request), this.threadContextInheritable);   

  10.   

  11.         // Expose current RequestAttributes to current thread.   

  12.         RequestAttributes previousRequestAttributes = RequestContextHolder.getRequestAttributes();   

  13.         ServletRequestAttributes requestAttributes = new ServletRequestAttributes(request);   

  14.         RequestContextHolder.setRequestAttributes(requestAttributes, this.threadContextInheritable);   

  15.   

  16.         if (logger.isTraceEnabled()) {   

  17.             logger.trace("Bound request context to thread: " + request);   

  18.         }   

  19.            

  20.         try {   

  21.             ModelAndView mv = null;   

  22.             boolean errorView = false;   

  23.   

  24.             try {   

  25.                 processedRequest = checkMultipart(request);   

  26.   

  27.                 // Determine handler for the current request.   

  28.                 mappedHandler = getHandler(processedRequest, false);   

  29.                 if (mappedHandler == null || mappedHandler.getHandler() == null) {   

  30.                     noHandlerFound(processedRequest, response);   

  31.                     return;   

  32.                 }   

  33.   

  34.                 // Apply preHandle methods of registered interceptors.   

  35.                 HandlerInterceptor[] interceptors = mappedHandler.getInterceptors();   

  36.                 if (interceptors != null) {   

  37.                     for (int i = 0; i < interceptors.length; i++) {   

  38.                         HandlerInterceptor interceptor = interceptors[i];   

  39.                         if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) {   

  40.                             triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);   

  41.                             return;   

  42.                         }   

  43.                         interceptorIndex = i;   

  44.                     }   

  45.                 }   

  46.   

  47.                 // Actually invoke the handler.   

  48.                 HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());   

  49.                 mv = ha.handle(processedRequest, response, mappedHandler.getHandler());   

  50.   

  51.                 // Do we need view name translation?   

  52.                 if (mv != null && !mv.hasView()) {   

  53.                     mv.setViewName(getDefaultViewName(request));   

  54.                 }   

  55.   

  56.                 // Apply postHandle methods of registered interceptors.   

  57.                 if (interceptors != null) {   

  58.                     for (int i = interceptors.length - 1; i >= 0; i--) {   

  59.                         HandlerInterceptor interceptor = interceptors[i];   

  60.                         interceptor.postHandle(processedRequest, response, mappedHandler.getHandler(), mv);   

  61.                     }   

  62.                 }   

  63.             }   

  64.             catch (ModelAndViewDefiningException ex) {   

  65.                 logger.debug("ModelAndViewDefiningException encountered", ex);   

  66.                 mv = ex.getModelAndView();   

  67.             }   

  68. // 这里catch住controller抛出的异常,使用持有的ExceptionResolver处理,当没有配置自己的处理器时,程序会将异常继续往上抛出,最终交给我们的容器处理   

  69.             catch (Exception ex) {   

  70.                 Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);   

  71.                 mv = processHandlerException(processedRequest, response, handler, ex);   

  72.                 errorView = (mv != null);   

  73.             }   

  74.   

  75.             // Did the handler return a view to render?   

  76.             if (mv != null && !mv.wasCleared()) {   

  77.                 render(mv, processedRequest, response);   

  78.                 if (errorView) {   

  79.                     WebUtils.clearErrorRequestAttributes(request);   

  80.                 }   

  81.             }   

  82.             else {   

  83.                 if (logger.isDebugEnabled()) {   

  84.                     logger.debug("Null ModelAndView returned to DispatcherServlet with name ‘" +   

  85.                             getServletName() + "‘: assuming HandlerAdapter completed request handling");   

  86.                 }   

  87.             }   

  88.   

  89.             // Trigger after-completion for successful outcome.   

  90.             triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);   

  91.         }   

  92. // 当没有配置ExceptionResolver时,异常将到达这里,最终抛出   

  93.         catch (Exception ex) {   

  94.             // Trigger after-completion for thrown exception.   

  95.             triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);   

  96.             throw ex;   

  97.         }   

  98.         catch (Error err) {   

  99.             ServletException ex = new NestedServletException("Handler processing failed", err);   

  100.             // Trigger after-completion for thrown exception.   

  101.             triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);   

  102.             throw ex;   

  103.         }   

  104.   

  105.         finally {   

  106.             // Clean up any resources used by a multipart request.   

  107.             if (processedRequest != request) {   

  108.                 cleanupMultipart(processedRequest);   

  109.             }   

  110.   

  111.             // Reset thread-bound context.   

  112.             RequestContextHolder.setRequestAttributes(previousRequestAttributes, this.threadContextInheritable);   

  113.             LocaleContextHolder.setLocaleContext(previousLocaleContext, this.threadContextInheritable);   

  114.   

  115.             // Clear request attributes.   

  116.             requestAttributes.requestCompleted();   

  117.             if (logger.isTraceEnabled()) {   

  118.                 logger.trace("Cleared thread-bound request context: " + request);   

  119.             }   

  120.         }   

  121.     }  


spring mvc异常设置,

  1.       

  2. 此段代码ZZ from http://tdcq.iteye.com/blog/890957   

  3. <!-- 全局异常配置 start -->     

  4.      <bean id="exceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">     

  5.          <property name="exceptionMappings">     

  6.              <props>     

  7.                  <prop key="java.lang.Exception">errors/error</prop>     

  8.                  <prop key="java.lang.Throwable">errors/err</prop>     

  9.              </props>     

  10.          </property>     

  11.          <property name="statusCodes">     

  12.              <props>     

  13.                  <prop key="errors/error">500</prop>     

  14.                  <prop key="errors/404">404</prop>     

  15.              </props>     

  16.          </property>     

  17.          <!-- 设置日志输出级别,不定义则默认不输出警告等错误日志信息 -->     

  18.          <property name="warnLogCategory" value="WARN"></property>     

  19.          <!-- 默认错误页面,当找不到上面mappings中指定的异常对应视图时,使用本默认配置 -->     

  20.          <property name="defaultErrorView" value="errors/error"></property>     

  21.          <!-- 默认HTTP状态码 -->     

  22.          <property name="defaultStatusCode" value="500"></property>     

  23.      </bean>     

  24.      <!-- 全局异常配置 end -->    

Java代码  技术分享

  1.      

  2. 用spring mvc做了个项目,但是出现异常的情况下居然没有日志输出,然后各种尝试。。。正如上面介绍的:设置日志输出级别,不定义则默认不输出警告等错误日志信息!!【当然,try catch的异常没问题】   

  3. 敬请留意。   



以上是关于spring mvc 异常统一处理方式的主要内容,如果未能解决你的问题,请参考以下文章

Spring MVC学习—项目统一异常处理机制详解与使用案例

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

spring 或 springboot统一异常处理

Spring统一异常处理

Spring中的统一异常处理方式

Spring Boot 统一参数校验统一异常统一响应,这才是优雅的处理方式!