Java @ControllerAdvice 不触发

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21884737/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 11:15:54  来源:igfitidea点击:

@ControllerAdvice Not Firing

javaspringspring-mvcexception-handling

提问by user676567

I'm working on a Spring MVC/Webflow Application (version 3.2) and trying to get exception handling working where I can output a custom exception message to a logfile and error.jsp. The problem I'm having is that the Exception Handler is not getting fired. I've created the following class and annotated it "@ControllerAdvice" and put it into the same package as my controller that is throwing the exception:

我正在开发 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;
    }
}

and added the following to the mvc-config File:

并将以下内容添加到 mvc-config 文件中:

<mvc:annotation-driven/>

And included the following in my app-config File:

并在我的 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> 

Any ideas why this isn't working?

任何想法为什么这不起作用?

回答by Sotirios Delimanolis

The <mvc:annotation-driven/>element implicitly registers a ExceptionHandlerExceptionResolverbean. This class has a initExceptionHandlerAdviceCache()method which scans beans in the context to find those whose class type is annotated with @ControllerAdvice.

<mvc:annotation-driven/>元素隐式注册了一个ExceptionHandlerExceptionResolverbean。这个类有一个initExceptionHandlerAdviceCache()方法,它在上下文中扫描 bean 以查找那些类类型用@ControllerAdvice.

It does this by first calling ControllerAdviceBean.findAnnotatedBeans(ApplicationContext). Internally, this method uses ApplicationContext#getBeanDefinitionNames(). The javadoc of this method states

它通过首先调用ControllerAdviceBean.findAnnotatedBeans(ApplicationContext). 在内部,此方法使用ApplicationContext#getBeanDefinitionNames(). 此方法的 javadoc 说明

Does not consider any hierarchy this factory may participate

不考虑该工厂可能参与的任何层次结构

To clarify what this means. When you declare a ContextLoaderListenerin your deployment descriptor, it loads what we call a root or application ApplicationContextand makes it available in the ServletContext. When you then declare a DispatcherServlet, it creates its own servletApplicationContextand uses any ApplicationContextit finds in the ServletContextattributes loaded by the ContextLoaderListeneras a parent to that context. The hierarchy looks like so

澄清这意味着什么。当您ContextLoaderListener在部署描述符中声明 a时,它会加载我们称为根或应用程序的内容,ApplicationContext并使其在ServletContext. 然后DispatcherServlet,当您声明 a 时,它会创建自己的servlet,ApplicationContext并使用ApplicationContext它在ServletContext加载的属性中找到的任何servletContextLoaderListener作为该上下文的父级。层次结构看起来像这样

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

Every ApplicationContexthas access to beans in parent contexts, but not the other way around.

每个人ApplicationContext都可以访问父上下文中的 bean,但反过来不行。

The method above chooses not to use the beans in parent contexts and so only has access to beans in the current ApplicationContext(BeanFactoryreally).

上面的方法选择不在父上下文中使用 bean,因此只能访问当前ApplicationContextBeanFactory真的)中的 bean 。

As such, if your

因此,如果您的

<context:component-scan .../>

is declared in a root ApplicationContextas I'll assume from the name app-config, but the

ApplicationContext正如我从 name 中假设的那样在根中声明app-config,但是

<mvc:annotation-driven />

is declared in the servlet ApplicationContext, again assuming from mvc-config, then the ExceptionHandlerExceptionResolverlooking for @ControllerAdvicebeans will not find any. It is looking for beans in the servlet context but they aren't there, they are in the root context.

在 servlet 中声明ApplicationContext,再次假设 from mvc-config,那么ExceptionHandlerExceptionResolver查找@ControllerAdvicebean 将找不到任何 bean。它正在 servlet 上下文中寻找 bean,但它们不在那里,它们在根上下文中。

回答by Brian Beech

In case anyone else runs into a problem like this - I found an error I had.

万一其他人遇到这样的问题 - 我发现了一个错误。

I only had one RequestMapping (http://localhost:8080/myapp/verify/verify)

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

In an InterceptorController, in the PreHandle method, I explicitly threw an exception -> throw new MyCustomException("error","error.jsp")to test my @ControllerAdviceExceptionhandling.

InterceptorController, 在 PreHandle 方法中,我显式地抛出了一个异常 ->throw new MyCustomException("error","error.jsp")来测试我的@ControllerAdviceException处理。

When I went to http://localhost:8080/myapp/I would see the interceptor controller get called, my custom exception get thrown, but the @ControllerAdviceclass with my @ExceptionHandler(MyCustomException.class)was never called.

当我访问http://localhost:8080/myapp/ 时,我会看到拦截器控制器被调用,我的自定义异常被抛出,但@ControllerAdvice我的类@ExceptionHandler(MyCustomException.class)从未被调用。

I added a @RequestMapping(value="/")and it resolved my issues. Since I was attempting to go to a URI that had no @RequestMappingassociated with it, i was getting a 'NoHandlerFoundException'which was shorting out my Exceptionfrom bubbling up.

我添加了一个@RequestMapping(value="/"),它解决了我的问题。由于我试图访问一个@RequestMapping与它无关的 URI ,我得到了一个 URI,它使'NoHandlerFoundException'Exception的冒泡时间缩短了。

In short, make sure the URI you're attempting to invoke has a @RequestMappingassociated with it, or have a method in your ExceptionHandlerclass to deal with the NoHandlerFoundException.

简而言之,请确保您尝试调用的 URI@RequestMapping与其关联,或者在您的ExceptionHandler类中有一个方法来处理NoHandlerFoundException.

Hope this helps.

希望这可以帮助。