Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 20197|回复: 0

Spring MVC统一异常处理

[复制链接]
  • TA的每日心情
    奋斗
    2024-11-24 15:47
  • 签到天数: 804 天

    [LV.10]以坛为家III

    2053

    主题

    2111

    帖子

    72万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    726782
    发表于 2021-4-11 11:43:59 | 显示全部楼层 |阅读模式

    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又拥有一个处理该异常的方法,这个时候处理异常的方法就会被调用

      

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

     http://gaojiewyh.iteye.com/blog/1297746

     

     

    最近使用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)  
            分析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;   
    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;   
    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.     }  



    http://fancyboy2050.iteye.com/blog/1300037

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

    如果我们在使用Spring MVC的过程中,想自定义异常页面的话,我们可以使用DispatcherServlet来指定异常页面,具体的做法很简单:

    下面看我曾经的一个项目的spring配置文件:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    <? xml  version="1.0" encoding="UTF-8" ?>
            xmlns:context="http://www.springframework.org/schema/context"
            xsi:schemaLocation="http://www.springframework.org/schema/beans
         <!-- 扫描web包,应用Spring的注解 -->
         < context:component-scan  base-package="com.xxx.training.spring.mvc"/>
     
         <!-- 配置视图解析器,将ModelAndView及字符串解析为具体的页面 -->
         < bean
                 class="org.springframework.web.servlet.view.InternalResourceViewResolver"
                 p:viewClass="org.springframework.web.servlet.view.JstlView"
                 p:prefix="/WEB-INF/views/"
                 p:suffix=".jsp"/>
     
         <!--定义异常处理页面-->
         < bean  id="exceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
             < property  name="exceptionMappings">
                 < props >
                     < prop  key="java.sql.SQLException">outException</ prop >
                     < prop  key="java.io.IOException">outException</ prop >
                 </ props >
             </ property >
         </ bean >
    </ beans >

      上面的定义异常处理部分的解释为:只要发生了SQLException或者IOException异常,就会自动跳转到WEB-INF/views/outException.jsp页面。

    一般情况下我们的outException.jsp页面的代码为:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <%@ page contentType= "text/html;charset=UTF-8"  language= "java"  %>
    <html>
    <head>
         <title>异常处理页面</title>
    </head>
    <body>
    <% Exception ex = (Exception) request.getAttribute( "Exception" );%>
    <H2>Exception:<%=ex.getMessage()%>
    </H2>
    </body>
    </html>

      当然你也可以修改样式,这个就看个人喜好了、

    另外记得要在web.xml也使用类似下面的方式处理异常哦。:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    < error-page >
          < error-code >404</ error-code >
          < location >/WEB-INF/pages/404.jsp</ location >
      </ error-page >
     
      < error-page >
          < exception-type >java.lang.Exception</ exception-type >
          < location >/WEB-INF/pages/exception.jsp</ location >
      </ error-page >

      因为这两个异常处理的维度是不一样的,简单说,spring的resolver是spring内部使用的,而web。xml里的是整个webapp共同使用的。

    建议两个都配置上,

    因为spring的resolver可以和spring结合的更紧密,可扩展的更多。

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-12-23 00:35 , Processed in 0.065472 second(s), 29 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表