天天看點

spring mvc 異常統一處理方式

springMVC提供的異常處理主要有兩種方式,一種是直接實作自己的HandlerExceptionResolver,另一種是使用注解的方式實作一個專門用于處理異常的Controller——ExceptionHandler。

1、實作自己的HandlerExceptionResolver,HandlerExceptionResolver是一個接口,springMVC本身已經對其有了一個自身的實作——DefaultExceptionResolver,該解析器隻是對其中的一些比較典型的異常進行了攔截處理。

spring mvc 異常統一處理方式

import javax.servlet.http.HttpServletRequest;   

import javax.servlet.http.HttpServletResponse;   

import org.springframework.web.servlet.HandlerExceptionResolver;   

import org.springframework.web.servlet.ModelAndView;   

public class ExceptionHandler implements HandlerExceptionResolver {   

    @Override  

    public ModelAndView resolveException(HttpServletRequest request,   

            HttpServletResponse response, Object handler, Exception ex) {   

        // TODO Auto-generated method stub   

        return new ModelAndView("exception");   

    }   

}  

 上述的resolveException的第4個參數表示對哪種類型的異常進行處理,如果想同時對多種異常進行處理,可以把它換成一個異常數組。

定義了這樣一個異常處理器之後就要在applicationContext中定義這樣一個bean對象,如:

spring mvc 異常統一處理方式

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

2、使用@ExceptionHandler進行處理

使用@ExceptionHandler進行處理有一個不好的地方是進行異常處理的方法必須與出錯的方法在同一個Controller裡面

如:

spring mvc 異常統一處理方式

import org.springframework.stereotype.Controller;   

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

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

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

@Controller  

public class GlobalController {   

    /**  

     * 用于處理異常的  

     * @return  

     */  

    @ExceptionHandler({MyException.class})   

    public String exception(MyException e) {   

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

        e.printStackTrace();   

        return "exception";   

    @RequestMapping("test")   

    public void test() {   

        throw new MyException("出錯了!");   

這裡在頁面上通路test方法的時候就會報錯,而擁有該test方法的Controller又擁有一個處理該異常的方法,這個時候處理異常的方法就會被調用

當發生異常的時候,上述兩種方式都使用了的時候,第一種方式會将第二種方式覆寫

最近使用spring mvc開發一個web系統,發現在controller裡發生未捕獲異常時不出日志。 

分析DispatcherServlet,初始化handlerExceptionResolvers

spring mvc 異常統一處理方式

        /**  

     * Initialize the strategy objects that this servlet uses.  

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

     * further strategy objects.  

    protected void initStrategies(ApplicationContext context) {   

        initMultipartResolver(context);   

        initLocaleResolver(context);   

        initThemeResolver(context);   

        initHandlerMappings(context);   

        initHandlerAdapters(context);   

// 初始化異常處理支援器   

        initHandlerExceptionResolvers(context);   

        initRequestToViewNameTranslator(context);   

        initViewResolvers(context);   

// 進入初始化處理方法,具體内容就不貼了,主要是先到上下文中搜尋我們自己定義的ExceptionResolvers,如果沒有自定義的resolvers,從預設配置中讀取。   

private void initHandlerExceptionResolvers(ApplicationContext context)   

// 從預設政策中取得預設配置,從DispatcherServlet.properties檔案中取得相關的配置政策,但是在spring2.5的mvc jar包中properties檔案中沒有HandlerExceptionResolver的預設配置,傳回一個EmptyList給handlerExceptionResolvers   

protected List getDefaultStrategies(ApplicationContext context, Class strategyInterface)  

spring mvc 異常統一處理方式

// 從dispatch方法中看到,系統對請求進行具體的邏輯處理部分被catch住了一次exception,然後會使用servlet持有的ExceptionResolver進行處理   

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

        HttpServletRequest processedRequest = request;   

        HandlerExecutionChain mappedHandler = null;   

        int interceptorIndex = -1;   

        // Expose current LocaleResolver and request as LocaleContext.   

        LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();   

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

        // Expose current RequestAttributes to current thread.   

        RequestAttributes previousRequestAttributes = RequestContextHolder.getRequestAttributes();   

        ServletRequestAttributes requestAttributes = new ServletRequestAttributes(request);   

        RequestContextHolder.setRequestAttributes(requestAttributes, this.threadContextInheritable);   

        if (logger.isTraceEnabled()) {   

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

        }   

        try {   

            ModelAndView mv = null;   

            boolean errorView = false;   

            try {   

                processedRequest = checkMultipart(request);   

                // Determine handler for the current request.   

                mappedHandler = getHandler(processedRequest, false);   

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

                    noHandlerFound(processedRequest, response);   

                    return;   

                }   

                // Apply preHandle methods of registered interceptors.   

                HandlerInterceptor[] interceptors = mappedHandler.getInterceptors();   

                if (interceptors != null) {   

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

                        HandlerInterceptor interceptor = interceptors[i];   

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

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

                            return;   

                        }   

                        interceptorIndex = i;   

                    }   

                // Actually invoke the handler.   

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

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

                // Do we need view name translation?   

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

                    mv.setViewName(getDefaultViewName(request));   

                // Apply postHandle methods of registered interceptors.   

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

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

            }   

            catch (ModelAndViewDefiningException ex) {   

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

                mv = ex.getModelAndView();   

// 這裡catch住controller抛出的異常,使用持有的ExceptionResolver處理,當沒有配置自己的處理器時,程式會将異常繼續往上抛出,最終交給我們的容器處理   

            catch (Exception ex) {   

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

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

                errorView = (mv != null);   

            // Did the handler return a view to render?   

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

                render(mv, processedRequest, response);   

                if (errorView) {   

                    WebUtils.clearErrorRequestAttributes(request);   

            else {   

                if (logger.isDebugEnabled()) {   

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

                            getServletName() + "': assuming HandlerAdapter completed request handling");   

            // Trigger after-completion for successful outcome.   

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

// 當沒有配置ExceptionResolver時,異常将到達這裡,最終抛出   

        catch (Exception ex) {   

            // Trigger after-completion for thrown exception.   

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

            throw ex;   

        catch (Error err) {   

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

        finally {   

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

            if (processedRequest != request) {   

                cleanupMultipart(processedRequest);   

            // Reset thread-bound context.   

            RequestContextHolder.setRequestAttributes(previousRequestAttributes, this.threadContextInheritable);   

            LocaleContextHolder.setLocaleContext(previousLocaleContext, this.threadContextInheritable);   

            // Clear request attributes.   

            requestAttributes.requestCompleted();   

            if (logger.isTraceEnabled()) {   

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

    }  

<a href="http://fancyboy2050.iteye.com/blog/1300037">http://fancyboy2050.iteye.com/blog/1300037</a>

spring mvc異常設定,

spring mvc 異常統一處理方式

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

&lt;!-- 全局異常配置 start --&gt;     

     &lt;bean id="exceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"&gt;     

         &lt;property name="exceptionMappings"&gt;     

             &lt;props&gt;     

                 &lt;prop key="java.lang.Exception"&gt;errors/error&lt;/prop&gt;     

                 &lt;prop key="java.lang.Throwable"&gt;errors/err&lt;/prop&gt;     

             &lt;/props&gt;     

         &lt;/property&gt;     

         &lt;property name="statusCodes"&gt;     

                 &lt;prop key="errors/error"&gt;500&lt;/prop&gt;     

                 &lt;prop key="errors/404"&gt;404&lt;/prop&gt;     

         &lt;!-- 設定日志輸出級别,不定義則預設不輸出警告等錯誤日志資訊 --&gt;     

         &lt;property name="warnLogCategory" value="WARN"&gt;&lt;/property&gt;     

         &lt;!-- 預設錯誤頁面,當找不到上面mappings中指定的異常對應視圖時,使用本預設配置 --&gt;     

         &lt;property name="defaultErrorView" value="errors/error"&gt;&lt;/property&gt;     

         &lt;!-- 預設HTTP狀态碼 --&gt;     

         &lt;property name="defaultStatusCode" value="500"&gt;&lt;/property&gt;     

     &lt;/bean&gt;     

     &lt;!-- 全局異常配置 end --&gt;    

<a href="http://fancyboy2050.iteye.com/blog/965663">http://fancyboy2050.iteye.com/blog/965663</a>

本文轉自茄子_2008部落格園部落格,原文連結:http://www.cnblogs.com/xd502djj/archive/2012/09/24/2700490.html,如需轉載請自行聯系原作者。