我正在开发一个Spring MVC / Webflow应用程序(版本3.2),并尝试在我可以向日志文件和error.jsp输出自定义异常消息的地方进行异常处理。我遇到的问题是异常处理程序没有被解雇。我已经创建了以下类并将其注释为“@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/>
并在我的app-config文件中包含以下内容:
<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 :(得分:8)
<mvc:annotation-driven/>
元素隐式注册ExceptionHandlerExceptionResolver
bean。此类具有initExceptionHandlerAdviceCache()
方法,该方法扫描上下文中的bean以查找其类类型使用@ControllerAdvice
注释的bean。
首先调用ControllerAdviceBean.findAnnotatedBeans(ApplicationContext)
来完成此操作。在内部,此方法使用ApplicationContext#getBeanDefinitionNames()
。此方法的javadoc说明
不考虑此工厂可能参与的任何层级
澄清这意味着什么。在部署描述符中声明ContextLoaderListener
时,它会加载我们称为根或应用程序ApplicationContext
的内容,并使其在ServletContext
中可用。然后,当您声明DispatcherServlet
时,它会创建自己的 servlet ApplicationContext
并使用它在ApplicationContext
加载的ServletContext
属性中找到的任何ContextLoaderListener
{1}}作为该上下文的父级。层次结构看起来像这样
Root ApplicationContext // loaded by the ContextLoaderListener
|
Servlet ApplicationContext // loaded by the DispatcherServlet
每个ApplicationContext
都可以访问父上下文中的bean,但不是相反。
上面的方法选择不在父上下文中使用bean,因此只能访问当前ApplicationContext
中的bean(BeanFactory
)。
因此,如果你的
<context:component-scan .../>
在根ApplicationContext
中声明,我将从名称app-config
中假设,但
<mvc:annotation-driven />
在servlet ApplicationContext
中声明,再次假设来自mvc-config
,然后查找ExceptionHandlerExceptionResolver
bean的@ControllerAdvice
将找不到任何内容。它正在servlet上下文中查找bean,但它们不存在,它们位于根上下文中。
答案 1 :(得分:0)
如果其他人遇到这样的问题 - 我发现了一个错误。
我只有一个RequestMapping(http://localhost:8080/myapp/verify/verify)
在InterceptorController
中,在PreHandle方法中,我明确地抛出了异常 - &gt; throw new MyCustomException("error","error.jsp")
来测试我的@ControllerAdvice
Exception
处理。
当我去http://localhost:8080/myapp/时,我会看到拦截器控制器被调用,我的自定义异常被抛出,但@ControllerAdvice
类与我的@ExceptionHandler(MyCustomException.class)
从未被调用过。
我添加了@RequestMapping(value="/")
,它解决了我的问题。由于我试图转到没有@RequestMapping
与之关联的URI,因此我得到了'NoHandlerFoundException'
,这使我的Exception
漏掉了。
简而言之,请确保您尝试调用的URI与@RequestMapping
关联,或者在ExceptionHandler
类中使用方法来处理NoHandlerFoundException
。< / p>
希望这有帮助。