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

Spring MVC版本是4.1.5

我读过这样的话:

  • Stackoverflow Example 1
  • Stackoverflow Example 1 continuation

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

    这是我的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)

    应用程序配置
    @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;
        }
    }
    

    存储库配置
    @Configuration
    public class RepositoryConfiguration {
    
    }
    

    安全配置
    @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不会引发异常。

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

    因此,解决方案是删除行

       configurer.enable();
    

    从您的MvcConfiguration。现在应该触发异常,而您的GlobalExceptionHandler应该做其余的事情!

    09-27 02:24
    查看更多