使用spring利用HandlerExceptionResolver實現全局異常捕獲


最近一直沒有時間更新是因為一直在更新自己使用的框架。

之后會慢慢帶來對之前使用的spring+mvc+mybatis的優化。

會使用一些新的特性,實現一些新的功能。

我會盡量分離業務,封裝好再拿出來。

這次帶來的是全局異常捕獲。

PS:使用的是spring4.3.7版本

PPPPS:當前使用的全局異常捕獲方式已更新,不再使用當前博文描述的方式,詳細請參考:http://www.cnblogs.com/linkstar/p/8520027.html

 

實現的功能

首先描述實現的功能:因為在項目中,我們不可否認的會出現異常,而且這些異常並沒有進行捕獲。經常出現的bug如空指針異常等等。

在之前的項目中,如果我們沒有進行任何配置,那么容器會自動打印錯誤的信息,如果tomcat的404頁面,400頁面等等。

如果我們在web.xml中進行如下配置,就會攔截錯誤,然后跳轉到指定的錯誤頁面。

<error-page>
    <error-code>500</error-code>
    <location>/500.jsp</location>
</error-page>

但是這已經落后了,現在我們通過實現spring的HandlerExceptionResolver接口來捕獲所有的異常。

 

如何實現

1、新建GlobalExceptionResolver如下

/**
 * 全局異常捕獲
 * @author XXX
 *
 */
public class GlobalExceptionResolver implements HandlerExceptionResolver{

    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
            Exception exception) {
        //--------------------------------------------
        return null;
    }
}

 

2、在spring配置文件中配置剛才新建的類

<!--全局異常捕捉 -->
<bean class="com.ssm.exception.GlobalExceptionResolver" />

 

3、根據自己的需求修改GlobalExceptionResolver的橫線部分

在你在開發的時候,請返回null,這樣這個類就如同不起作用,之前該怎么樣就怎么樣。

當開發完成之后,根據錯誤的信息來返回需要的東西了。

首先我們可以做的是打印錯誤日志,當然也是必須的。

System.err.println("訪問" + request.getRequestURI() + " 發生錯誤, 錯誤信息:" + exception.getMessage());

這里我只是用控制台舉例,你當然可以用日志框架打印。打印信息主要是包括是訪問那個地址出現了什么錯誤。

之后如果你需要返回錯誤頁面,那么就直接在ModelAndView里面寫就行了,這里就不多舉例了,ModelAndView寫過MVC的Controller應該都熟悉。

ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("error");
return modelAndView;

 

Follow up

以上其實就已經實現了全局捕獲異常的功能,你可以自己拋出一個不捕獲的異常測試一下是否成功。

當然還有更多對於這個類的說明。

 

1、注意不同類型和來源的請求。

因為在實際項目中,可能遇到各種請求類型,如正常的get,post。也可能是來自ajax的請求。

所以如果均返回同一個ModelAndView顯然可能有點不合適,對於ajax可能需要特別處理。

還有就是如果有手機端和PC在同一個項目中的情況,那么來源不同,返回的頁面也可能不同。雖然可以交給前端去做自適應處理,但是我們還是得做好考慮。

總之,要考慮到各種不同的請求,單一返回可能並不適用所有項目。

 

2、GlobalExceptionResolver這個類推薦放在exception包下,屬於一種自定義異常

這個配置推薦放在和web相關的spring配置下,因為和類似一個controller

 

3、spring是怎么做到的?handler參數又是什么?

肯定有和我一樣的好奇寶寶。用了別人好的東西就想知道怎么實現的,但是又很怕麻煩。(推薦自己仔細讀源碼,不要聽我瞎說

首先spring官方文檔536頁說明了HandlerExceptionResolve

而官方推薦的是使用@ExceptionHandler注解去捕獲固定的異常。

然后我查了源碼,spring源碼中

/**
     * Resolve the exception by iterating over the list of configured exception resolvers.
     * The first one to return a ModelAndView instance wins. Otherwise {@code null} is returned.
     */
    @Override
    public ModelAndView resolveException(HttpServletRequest request,
                                         HttpServletResponse response,
                                         Object handler,
                                         Exception ex) {
        if (resolvers != null) {
            for (HandlerExceptionResolver handlerExceptionResolver : resolvers) {
                ModelAndView mav = handlerExceptionResolver.resolveException(request, response, handler, ex);
                if (mav != null) {
                    return mav;
                }
            }
        }
        return null;
    }

這是spring默認實現,也就是說,我們沒有重寫的話,spring是這樣執行的,從命名來瞎說就是

如果出現異常,private List<HandlerExceptionResolver> resolvers;

處理異常解析器就會非空

通過循環異常解析器處理resolvers中的異常,然后處理。

最后返回null也就是我們之前所說的不做任何錯誤頁面的那種處理。

然后處理異常打印異常信息是在抽象類里面完成的。

/**
     * Check whether this resolver is supposed to apply (i.e. if the supplied handler
     * matches any of the configured {@linkplain #setMappedHandlers handlers} or
     * {@linkplain #setMappedHandlerClasses handler classes}), and then delegate
     * to the {@link #doResolveException} template method.
     */
    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response,
            Object handler, Exception ex) {

        if (shouldApplyTo(request, handler)) {
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Resolving exception from handler [" + handler + "]: " + ex);
            }
            prepareResponse(ex, response);
            ModelAndView result = doResolveException(request, response, handler, ex);
            if (result != null) {
                logException(ex, request);
            }
            return result;
        }
        else {
            return null;
        }
    }

就是打印錯誤信息,這里我們看到handler被打印了。

打印的意思是從哪一個handler解析出什么異常。

最后如果有結果依舊返回。

 

總之我們可以知道的是,spring的handle在處理時發現異常后,HandlerExceptionResolver的列表會被賦值,然后進行處理。

有興趣的朋友可以繼續往下追。

 

最后

當然這也只是我在github上面見到的一種異常的處理方式,比我之前的好用。

所以我就拿來用了。如果有需要的就拿走,如果你有更好的也歡迎在下面分享。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM