2015-05-28 83 views
4

我试图在完全使用Javaconfig配置的Spring MVC应用程序中使用@ControllerAdvice来处理404错误。在Web应用程序中处理错误404 - 非REST应用程序

Spring MVC的版本是4.1.5

我已阅读本:

不过遗憾的是它并没有为我工作。

在这里,你有我的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(versio N + 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(); 
    } 
} 

SPRI ngSecurityInitializer

public class SpringSecurityInitializer extends AbstractSecurityWebApplicationInitializer{ 
    //do nothing 
} 

有了这个配置我不能够处理404错误代码。

在此先感谢。

更新添加有关配置文件

+0

你永远也不会是能够做到这一点。一个'@ ExceptionHandler'只适用于执行处理程序期间发生的异常。这不是处理程序的执行,而是在此之前失败。相反,在web.xml中使用'error-page'(在web.xml中是yes,因为没有java的等价物)。 –

+0

在这种情况下,是什么registration.setInitParameter的porpouse(“throwExceptionIfNoHandlerFound”,“真”);? – moyanojv

+0

默认情况下,它会发送一个404这让它会抛出一个异常,您可以在过滤器中处理异常。要注册错误页面,您必须使用web.xml,因为这在java配置中不可用。 (我怀疑在servlet API的3.x版本中有一个疏忽)。 –

回答

9

结论似乎是,throwExceptionIfNoHandlerFound设置为true时没有处理程序被发现不抛出异常的更多信息。

解决的办法很简单。来自javadoc @DispatcherServlet.setThrowExceptionIfNoHandlerFound。它在此声明,如果使用DefaultServletHttpRequestHandler,则不会引发NoHandlerFoundException。因此

解决方案是从您的MvcConfiguration删除行

configurer.enable(); 

。现在异常应该触发,你的GlobalExceptionHandler应该完成剩下的工作!

+0

对于那些使用xml config,删除这行: \t

+0

我做到了,它仍然抱怨Ambiguous @ExceptionHandler – BigDong

0

解决方法:添加@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()); 
    } 
} 
+0

它不是一个解决方案,它是解决方法。 – zygimantus

+0

谢谢。我有变化。 – KhanhLV

0

的解决方案是延伸AbstractAnnotationConfigDispatcherServletInitializer和覆盖此方法:

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

OR这一个:

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

最后在ControlerAdvice使用本:

@ExceptionHandler(NoHandlerFoundException.class) 
public String error404(Exception ex) { 

    return new ModelAndView("404"); 
}