HOWTO使用基于Java的Annotations配置的Spring MVC全局处理404exception

(问题末尾发布的解决方案

我正在构建一个Spring 4 MVC应用程序。 它完全使用Java Annotations进行配置。 没有web.xml 。 通过使用AbstractAnnotationConfigDispatcherServletInitializerWebMvcConfigurerAdapter实例配置应用程序, WebMvcConfigurerAdapter所示,

 @Configuration @EnableWebMvc @ComponentScan(basePackages = {"com.example.*"}) @EnableTransactionManagement @PropertySource("/WEB-INF/properties/application.properties") public class WebAppConfig extends WebMvcConfigurerAdapter { ... } 

 public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { ... } 

我现在正在尝试为404页面添加一个global / catch-allexception处理程序,即HttpStatus.NOT_FOUND但没有成功。 以下是我尝试过的一些方法。

 import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.NoHandlerFoundException; import org.springframework.web.servlet.mvc.multiaction.NoSuchRequestHandlingMethodException; @ControllerAdvice public class GlobalExceptionHandlerController { @ExceptionHandler @ResponseStatus(HttpStatus.NOT_FOUND) public ModelAndView handleException (NoSuchRequestHandlingMethodException ex) { ModelAndView mav = new ModelAndView(); return mav; } @ExceptionHandler @ResponseStatus(HttpStatus.NOT_FOUND) public ModelAndView handleExceptiond (NoHandlerFoundException ex) { ModelAndView mav = new ModelAndView(); return mav; } @ResponseStatus(HttpStatus.NOT_FOUND) @ExceptionHandler(NoHandlerFoundException.class) public void handleConflict() { } @ResponseStatus(HttpStatus.NOT_FOUND) @ExceptionHandler(NoSuchRequestHandlingMethodException.class) public void handlesdConflict() { } } 

这些方法都没有执行。 我不知道如何处理这个问题。 我不想使用web.xml因为那时我必须为此创建一个。

解决方案我做了@Sotirios 在这里提到的 。 这是我的部分WebAppInitializer代码,它将正确设置调度程序。

 public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { ... @Override protected void registerDispatcherServlet(ServletContext servletContext) { String servletName = super.getServletName(); Assert.hasLength(servletName, "getServletName() may not return empty or null"); WebApplicationContext servletAppContext = super.createServletApplicationContext(); Assert.notNull(servletAppContext, "createServletApplicationContext() did not return an application " + "context for servlet [" + servletName + "]"); DispatcherServlet dispatcherServlet = new DispatcherServlet(servletAppContext); //>>> START: My custom code, rest is exqact copy of the super class dispatcherServlet.setThrowExceptionIfNoHandlerFound(true); //>>> END ServletRegistration.Dynamic registration = servletContext.addServlet(servletName, dispatcherServlet); Assert.notNull(registration, "Failed to register servlet with name '" + servletName + "'." + "Check if there is another servlet registered under the same name."); registration.setLoadOnStartup(1); registration.addMapping(getServletMappings()); registration.setAsyncSupported(isAsyncSupported()); Filter[] filters = getServletFilters(); if (!ObjectUtils.isEmpty(filters)) { for (Filter filter : filters) { super.registerServletFilter(servletContext, filter); } } super.customizeRegistration(registration); } ... } 

虽然我对这个解决方案不是特别满意,因为我唯一的自定义代码是1行,而rest是直接从超类中复制的。 我希望有一个更好的方法来做到这一点。

默认情况下, DispatcherServlet不会抛出NoHandlerFoundException 。 你需要启用它。

AbstractAnnotationConfigDispatcherServletInitializer应该允许您覆盖DispatcherServlet的创建方式。 那样做并打电话

 DispatcherServlet dispatcherServlet = ...; // might get it from super implementation dispatcherServlet.setThrowExceptionIfNoHandlerFound(true); 

启用DispatcherServlet通过web.xml configuartion抛出NoHandlerFoundException。

  throwExceptionIfNoHandlerFound true  

而是覆盖registerDispatcherServlet可以覆盖createDispatcherServlet方法,如下所示。

 @Override protected DispatcherServlet createDispatcherServlet(WebApplicationContext servletAppContext) { DispatcherServlet ds = new DispatcherServlet(servletAppContext); ds.setThrowExceptionIfNoHandlerFound(true); return ds; } 

我不能通过@Ysak评论上述post(声誉<50),但我可以确认这种方法适用于OP描述的设置。

我将从另一个指南中添加它,我还在我的WebConfig中配置了DefaultServletHandling来修复一个单独的问题,如下所示:

 @Configuration @EnableWebMvc @ComponentScan("com.acme.tat.controllers") public class WebConfig extends WebMvcConfigurerAdapter implements ApplicationContextAware { ... @Override public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { configurer.enable(); } } 

启用此设置后,不会抛出exception。 一旦我删除了这一行并设置了手动resourceHandlers,一切都按预期工作。

由于这种简单的单行方法,我花了大约2.5小时来设置404重定向。

我在application.yml中使用以下条目解决了问题

  server.error.whitelabel.enabled: false spring.mvc.throw-exception-if-no-handler-found: true 

以及以下ControllerExceptionHandler:

 @ControllerAdvice public class ControllerExceptionHandler { @ExceptionHandler(Exception.class) @ResponseStatus(HttpStatus.BAD_REQUEST) public String processMethodNotSupportedException(Exception exception) { exception.printStackTrace(); return "error"; } } 

最后但并非最不重要的是我添加了一个模板“/html/error.html”