2014-02-19 98 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

希望这会有所帮助。