HOWTO使用基于Java的Annotations配置的Spring MVC全局处理404exception
(问题末尾发布的解决方案 )
我正在构建一个Spring 4 MVC应用程序。 它完全使用Java Annotations进行配置。 没有web.xml
。 通过使用AbstractAnnotationConfigDispatcherServletInitializer
和WebMvcConfigurerAdapter
实例配置应用程序, 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”