处理Web应用程序中的错误404 – 而不是REST应用程序

我正在尝试使用完全使用Javaconfig配置的Spring MVC应用程序中的@ControllerAdvice来处理404错误。

Spring MVC版本是4.1.5

我读过这个:

  • Stackoverflow示例1
  • Stackoverflow示例1继续

但不幸的是,它对我不起作用。

在这里你有我的conf:

SpringConfigurationInitializer

 public class SpringConfigurationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class[] getRootConfigClasses() { return new Class[] { AppConfiguration.class }; } @Override protected Class[] getServletConfigClasses() { return null; } @Override protected String[] getServletMappings() { return new String[] { "/" }; } @Override public void customizeRegistration(ServletRegistration.Dynamic registration) { registration.setInitParameter("throwExceptionIfNoHandlerFound", "true"); } } 

请注意,我正在使用

 registration.setInitParameter("throwExceptionIfNoHandlerFound", "true"); 

GlobalExceptionHandler(版本1)

 @ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(NoHandlerFoundException.class) public ModelAndView handleError404(HttpServletRequest request, Exception e) { System.out.println("handled!!!"); ModelAndView mav = new ModelAndView("/errors/404"); mav.addObject("exception", e); return mav; } } 

GlobalExceptionHandler(版本2)

 @ControllerAdvice public class GlobalExceptionHandler extends ResponseEntityExceptionHandler { @Override public ResponseEntity handleNoHandlerFoundException(NoHandlerFoundException ex, HttpHeaders headers, HttpStatus status, WebRequest request) { System.out.println("handled¡¡¡"); return null; } } 

请记住,我没有使用任何类型的xml配置文件,我正在尝试构建一个Web应用程序(而不是REST)

AppConfiguration

 @Configuration @ComponentScan({ "org.moyanojv.opendata.*" }) @Import({ MvcConfiguration.class, RepositoryConfiguration.class, SecurityConfig.class }) public class AppConfiguration extends WebMvcConfigurerAdapter{ } 

MvcConfiguration

 @EnableWebMvc @Configuration public class MvcConfiguration extends WebMvcConfigurerAdapter { @Bean public UrlBasedViewResolver viewResolver() { UrlBasedViewResolver viewResolver = new UrlBasedViewResolver(); viewResolver.setViewClass(TilesView.class); return viewResolver; } @Bean public TilesConfigurer tilesConfigurer() { TilesConfigurer tilesConfigurer = new TilesConfigurer(); tilesConfigurer.setDefinitions(new String[] { "/WEB-INF/tiles.xml" }); tilesConfigurer.setCheckRefresh(true); return tilesConfigurer; } @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/resources/**").addResourceLocations("/resources/"); } @Override public void configureDefaultServletHandling( DefaultServletHandlerConfigurer configurer) { configurer.enable(); } /* Localization section is started */ @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(localeChangeInterceptor()); } @Bean public LocaleChangeInterceptor localeChangeInterceptor(){ LocaleChangeInterceptor localeChangeInterceptor=new LocaleChangeInterceptor(); localeChangeInterceptor.setParamName("lang"); return localeChangeInterceptor; } @Bean(name = "localeResolver") public LocaleResolver getLocaleResolver(){ return new CookieLocaleResolver(); } @Bean public ResourceBundleMessageSource messageSource() { ResourceBundleMessageSource source = new ResourceBundleMessageSource(); source.setBasename("i18n/messages"); source.setUseCodeAsDefaultMessage(true); return source; } } 

RepositoryConfiguration

 @Configuration public class RepositoryConfiguration { } 

SecurityConfig

 @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication().withUser("admin").password("admin").roles("ADMIN"); auth.inMemoryAuthentication().withUser("user").password("user").roles("USER"); } @Override public void configure( WebSecurity web ) throws Exception { // This is here to ensure that the static content (JavaScript, CSS, etc) // is accessible from the login page without authentication web .ignoring() .antMatchers( "/resources/**" ); } @Override protected void configure(HttpSecurity http) throws Exception { http // access-denied-page: this is the page users will be // redirected to when they try to access protected areas. .exceptionHandling() .accessDeniedPage( "/403" ) .and() // The intercept-url configuration is where we specify what roles are allowed access to what areas. // We specifically force the connection to https for all the pages, although it could be sufficient // just on the login page. The access parameter is where the expressions are used to control which // roles can access specific areas. One of the most important things is the order of the intercept-urls, // the most catch-all type patterns should at the bottom of the list as the matches are executed // in the order they are configured below. So /** (anyRequest()) should always be at the bottom of the list. .authorizeRequests() .antMatchers( "/admin" ).hasRole("ADMIN") .antMatchers("/login**").permitAll() .antMatchers("/home").permitAll() .antMatchers("/404").permitAll() .anyRequest().authenticated() .and() // This is where we configure our login form. // login-page: the page that contains the login screen // login-processing-url: this is the URL to which the login form should be submitted // default-target-url: the URL to which the user will be redirected if they login successfully // authentication-failure-url: the URL to which the user will be redirected if they fail login // username-parameter: the name of the request parameter which contains the username // password-parameter: the name of the request parameter which contains the password .formLogin() .loginPage( "/login" ) .failureUrl( "/login?err=1" ) .defaultSuccessUrl("/private") .usernameParameter( "username" ) .passwordParameter( "password" ) .permitAll() .and() // This is where the logout page and process is configured. The logout-url is the URL to send // the user to in order to logout, the logout-success-url is where they are taken if the logout // is successful, and the delete-cookies and invalidate-session make sure that we clean up after logout .logout() .logoutUrl("/logout") .logoutSuccessUrl("/login?logout=1") .invalidateHttpSession(true) //.deleteCookies("JSESSIONID,SPRING_SECURITY_REMEMBER_ME_COOKIE") .and() .csrf() .disable() // The session management is used to ensure the user only has one session. This isn't // compulsory but can add some extra security to your application. .sessionManagement() .maximumSessions(1); } @Override @Bean public UserDetailsService userDetailsServiceBean() throws Exception { return super.userDetailsServiceBean(); } } 

SpringSecurityInitializer

 public class SpringSecurityInitializer extends AbstractSecurityWebApplicationInitializer{ //do nothing } 

使用此配置,我无法处理404错误代码。

提前致谢。

已更新以添加有关配置文件的更多信息

结论似乎是将throwExceptionIfNoHandlerFound设置为true不会在找不到处理程序时抛出exception。

解决方案非常简单。 来自javadoc @ DispatcherServlet.setThrowExceptionIfNoHandlerFound 。 它声明如果使用DefaultServletHttpRequestHandler,则永远不会抛出NoHandlerFoundException。

解决方案因此是删除线

  configurer.enable(); 

来自你的MvcConfiguration。 现在应该触发exception,你的GlobalExceptionHandler应该完成其余的工作!

解决方案是扩展AbstractAnnotationConfigDispatcherServletInitializer并覆盖此方法:

 @Override protected DispatcherServlet createDispatcherServlet(WebApplicationContext servletAppContext) { final DispatcherServlet dispatcherServlet = (DispatcherServlet) super.createDispatcherServlet(servletAppContext); dispatcherServlet.setThrowExceptionIfNoHandlerFound(true); return dispatcherServlet; } 

或者这一个:

 @Override public void customizeRegistration(ServletRegistration.Dynamic registration) { registration.setInitParameter("throwExceptionIfNoHandlerFound", "true"); } 

最后在你的ControlerAdvice使用:

 @ExceptionHandler(NoHandlerFoundException.class) public String error404(Exception ex) { return new ModelAndView("404"); } 

解决方法:添加@RequestMapping(“/ **”)

 @Controller @ControllerAdvice public class GlobalExceptionHandler { private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class); @RequestMapping("/**") public String handlerNotMappingRequest(HttpServletRequest request, HttpServletResponse response, HttpHeaders httpHeaders) throws NoHandlerFoundException { throw new NoHandlerFoundException("No handler mapping found.", request.getRequestURL().toString(), httpHeaders); } @ExceptionHandler(Throwable.class) @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public ModelAndView handleControllerException(Throwable ex) { logger.error("ErrorLog: ", ex); return new ModelAndView("error/exception", "exceptionMsg", "ExceptionHandler msg: " + ex.toString()); } @ExceptionHandler(NoHandlerFoundException.class) @ResponseStatus(HttpStatus.NOT_FOUND) public ModelAndView handleNoHandlerFoundException(NoHandlerFoundException ex) { logger.error("ErrorLog: ", ex); return new ModelAndView("error/exception", "exceptionMsg", "NoHandlerFoundException msg: " + ex.toString()); } }