2014-02-19 96 views
8

我正在研究Spring MVC/Webflow應用程序(版本3.2),並試圖獲得異常處理工作,我可以在其中輸出自定義異常消息到日誌文件和error.jsp。我遇到的問題是異常處理程序沒有被解僱。我創建了下面的類並註明爲「@ControllerAdvice」,並把它放到同一個包我的控制器時拋出異常:@ControllerAdvice沒有觸發

@ControllerAdvice 
public class MyCustomExceptionController { 

    @ExceptionHandler(MyCustomException.class) 
    public ModelAndView handleMyException(MyCustomException ex) { 
     ModelAndView modelAndView = new ModelAndView(); 
     modelAndView.setViewName("/error/error"); 
     modelAndView.addObject("errorId", ex.getErrorId()); 
     modelAndView.addObject("message", ex.getErrorMessage());   
     return modelAndView; 
    } 
} 

,並增加了以下的MVC-config文件:

<mvc:annotation-driven/> 

而且包括在我的應用程序,配置文件如下:

<context:component-scan base-package="package containing my controllers and MyCustomExceptionController"> 
     <context:include-filter type="annotation" 
    expression="org.springframework.web.bind.annotation.ControllerAdvice" /> 
    </context:component-scan> 

爲什麼這是行不通的任何想法?

+0

只有在您選擇的未處理的自定義異常發生時('MyCustomException'),纔會調用handleMyException()方法。即使在拋出MyCustomException之後,這個方法是不是被調用的? [This](http://viralpatel.net/blogs/spring-mvc-exception-handling-controlleradvice-annotation/)是你可能會接近的教程。 – Tiny

+0

我在handleMyException上放了一個斷點,即使在拋出MyCustomException之後該方法也不會被調用。 – user676567

+0

如果您要在此類中使用'@ InitBinder'註釋來註釋您選擇的方法,就像該示例所調用的那樣? – Tiny

回答

8

<mvc:annotation-driven/>元素隱式註冊一個ExceptionHandlerExceptionResolver bean。該類有一個initExceptionHandlerAdviceCache()方法,該方法在上下文中掃描bean以找到那些類型爲@ControllerAdvice的註釋。

它通過首先調用ControllerAdviceBean.findAnnotatedBeans(ApplicationContext)來完成此操作。在內部,該方法使用ApplicationContext#getBeanDefinitionNames()。這種方法的Javadoc指出

不考慮這家工廠可能參與

爲了澄清這意味着什麼任何層次。當您在部署描述符中聲明ContextLoaderListener時,它會加載我們所稱的根或應用程序ApplicationContext,並使其在ServletContext中可用。當你再聲明DispatcherServlet,它會創建自己的servletApplicationContext,並使用它找到任何ApplicationContextContextLoaderListener加載爲父母這方面的ServletContext屬性。層次結構看起來像這樣

Root ApplicationContext // loaded by the ContextLoaderListener 
      | 
Servlet ApplicationContext // loaded by the DispatcherServlet 

每個ApplicationContext訪問豆父上下文,而不是周圍的其他方法。

上面的方法選擇不在父上下文中使用bean,因此只能訪問當前的ApplicationContext(實際上爲BeanFactory)中的bean。

因此,如果您

<context:component-scan .../> 

在根ApplicationContext被聲明爲我起的名字app-config承擔,但

<mvc:annotation-driven /> 

在servlet ApplicationContext聲明,再次假設從mvc-config,然後ExceptionHandlerExceptionResolver尋找@ControllerAdvice豆不會找到任何。它正在servlet上下文中查找bean,但它們不在那裏,它們位於根上下文中。

+0

所以我們應該在這裏做什麼? – gabby

+0

@gabby您重新排列上面提到的配置元素在一起。 –

+2

很好的解釋,但仍然缺少解決方案 – shaILU

0

萬一有人遇到這樣的問題 - 我發現我有一個錯誤。

我只有一個RequestMapping(http://localhost:8080/myapp/verify/verify

InterceptorController,在PreHandle方法,我明確地拋出一個異常 - >throw new MyCustomException("error","error.jsp")來測試我的@ControllerAdviceException處理。

當我去http://localhost:8080/myapp/時,我會看到攔截器控制器被調用,我的自定義異常被拋出,但@ControllerAdvice類與我的@ExceptionHandler(MyCustomException.class)從未被調用過。

我加了一個@RequestMapping(value="/"),它解決了我的問題。由於我試圖去找一個沒有@RequestMapping的URI,所以我得到了一個'NoHandlerFoundException',這使得我的Exception不再冒泡。

總之,要確保你正在試圖調用URI具有與之相關聯的@RequestMapping,或在你的ExceptionHandler類的方法來處理NoHandlerFoundException

希望這會有所幫助。