Spring MVC - Spring uses sometimes RequestMappingH

2019-09-02 05:25发布

问题:

I have been trying to solve this problem for past 2 days and found no answer so far. I reaserched a lot of google concerning this ;)

So the problem is that I'm trying to develop Spring MVC app using Hibernate and deploying it on Tomcat 8 local server. The thing is that on 10 runs I have about 6 times 404 Not Found page and 4 times my app i working fine and showing what I want. I made a little digging and found out in Debug logs that when request mapping fails Spring uses SimpleUrlHandlerMapping (which I do not configured) and when app works fine Spring uses RequestMappingHandlerMapping (which I configured).

A little bit of code then ;)

WebConfig.java

package pkw.config;

@EnableWebMvc
@Configuration
@ComponentScan(basePackages = {"pkw"})
@Import({AppConfig.class, SecurityConfig.class})
public class WebConfig extends WebMvcConfigurerAdapter{


    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/resources/**").addResourceLocations("classpath:bootstrap/");
    }

    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }

    @Bean
    public RequestMappingHandlerMapping requestMappingHandlerMapping(){
        return new RequestMappingHandlerMapping();
    }

    @Bean
    public UrlBasedViewResolver viewResolver() {
        UrlBasedViewResolver viewResolver = new UrlBasedViewResolver();
        viewResolver.setViewClass(TilesView.class);
        return viewResolver;
    }

    @Bean
    public TilesConfigurer tilesConfigurer(){
        TilesConfigurer result = new TilesConfigurer();
        result.setDefinitions("/WEB-INF/layouts/layout.xml");
        return result;
    }

}

SpringMvcInitilizer.java

package pkw.config.core;

public class SpringMvcInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {

        AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
        ctx.register(WebConfig.class);

        servletContext.addListener(new ContextLoaderListener(ctx));
        servletContext.addListener(new RequestContextListener());

        ctx.setServletContext(servletContext);

        Dynamic servlet = servletContext.addServlet("Enter", new DispatcherServlet(ctx));
        servlet.addMapping("/");
        servlet.setLoadOnStartup(1);

    }

}

EnterController.java

package pkw.controllers;

@Controller
public class EnterController {

    private static final Logger logger = LogManager.getLogger(EnterController.class);

    @Autowired
    IUserDAO userDAO;

    @Autowired
    IUserRoleDAO userRoleDAO;

    @Autowired
    DatabaseFinder finder;

    @Autowired
    PasswordEncoder passwordEncoder;

    @RequestMapping(value = {"/", "/main"}, method = {RequestMethod.GET, RequestMethod.HEAD})
    public String enterMain(Model model) {

        return "main";
    }


    @RequestMapping(value = "/login", method = {RequestMethod.GET, RequestMethod.HEAD})
    private String login(@RequestParam(value = "error", required = false) String error, @RequestParam(value = "logout",
            required = false) String logout, @RequestParam(value = "denied", required = false) String denied, @RequestParam(value = "success", required = false) String success,
                         Model model) {

        if (error != null) {
            model.addAttribute("error", "1");
        }

        if (logout != null) {
            model.addAttribute("logout", "1");
        }

        if (denied != null) {
            model.addAttribute("denied", "1");
        }

        if (success != null) {
            Authentication auth = SecurityContextHolder.getContext().getAuthentication();

            userBean.setLoggedUser(userDAO.findByPesel(auth.getName()));
            model.addAttribute("success", "1");
        }


        return "main";

    }
}

Debug log from bad run

16:31:44.433 [http-apr-8080-exec-8] DEBUG o.s.s.w.u.m.AntPathRequestMatcher - Checking match of request : '/'; against '/resources/**'
16:31:44.434 [http-apr-8080-exec-8] DEBUG o.s.security.web.FilterChainProxy - / at position 1 of 12 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
16:31:44.434 [http-apr-8080-exec-8] DEBUG o.s.security.web.FilterChainProxy - / at position 2 of 12 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
16:31:44.434 [http-apr-8080-exec-8] DEBUG o.s.s.w.c.HttpSessionSecurityContextRepository - No HttpSession currently exists
16:31:44.434 [http-apr-8080-exec-8] DEBUG o.s.s.w.c.HttpSessionSecurityContextRepository - No SecurityContext was available from the HttpSession: null. A new one will be created.
16:31:44.434 [http-apr-8080-exec-8] DEBUG o.s.security.web.FilterChainProxy - / at position 3 of 12 in additional filter chain; firing Filter: 'HeaderWriterFilter'
16:31:44.434 [http-apr-8080-exec-8] DEBUG o.s.s.w.h.writers.HstsHeaderWriter - Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@3b904681
16:31:44.434 [http-apr-8080-exec-8] DEBUG o.s.security.web.FilterChainProxy - / at position 4 of 12 in additional filter chain; firing Filter: 'CsrfFilter'
16:31:44.434 [http-apr-8080-exec-8] DEBUG o.s.security.web.FilterChainProxy - / at position 5 of 12 in additional filter chain; firing Filter: 'LogoutFilter'
16:31:44.434 [http-apr-8080-exec-8] DEBUG o.s.s.w.u.m.AntPathRequestMatcher - Request 'HEAD /' doesn't match 'POST /logout
16:31:44.434 [http-apr-8080-exec-8] DEBUG o.s.security.web.FilterChainProxy - / at position 6 of 12 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
16:31:44.434 [http-apr-8080-exec-8] DEBUG o.s.s.w.u.m.AntPathRequestMatcher - Request 'HEAD /' doesn't match 'POST /login
16:31:44.434 [http-apr-8080-exec-8] DEBUG o.s.security.web.FilterChainProxy - / at position 7 of 12 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
16:31:44.434 [http-apr-8080-exec-8] DEBUG o.s.security.web.FilterChainProxy - / at position 8 of 12 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
16:31:44.434 [http-apr-8080-exec-8] DEBUG o.s.security.web.FilterChainProxy - / at position 9 of 12 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
16:31:44.434 [http-apr-8080-exec-8] DEBUG o.s.s.w.a.AnonymousAuthenticationFilter - Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken@9055e4a6: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@957e: RemoteIpAddress: 127.0.0.1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS'
16:31:44.435 [http-apr-8080-exec-8] DEBUG o.s.security.web.FilterChainProxy - / at position 10 of 12 in additional filter chain; firing Filter: 'SessionManagementFilter'
16:31:44.435 [http-apr-8080-exec-8] DEBUG o.s.security.web.FilterChainProxy - / at position 11 of 12 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
16:31:44.435 [http-apr-8080-exec-8] DEBUG o.s.security.web.FilterChainProxy - / at position 12 of 12 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
16:31:44.435 [http-apr-8080-exec-8] DEBUG o.s.s.w.u.m.AntPathRequestMatcher - Checking match of request : '/'; against '/admin/*'
16:31:44.435 [http-apr-8080-exec-8] DEBUG o.s.s.w.a.i.FilterSecurityInterceptor - Public object - authentication not attempted
16:31:44.435 [http-apr-8080-exec-8] DEBUG o.s.security.web.FilterChainProxy - / reached end of additional filter chain; proceeding with original chain
16:31:44.435 [http-apr-8080-exec-8] DEBUG o.s.web.servlet.DispatcherServlet - DispatcherServlet with name 'Enter' processing HEAD request for [/]
16:31:44.435 [http-apr-8080-exec-8] DEBUG o.s.w.s.h.SimpleUrlHandlerMapping - Matching patterns for request [/] are [/**]
16:31:44.435 [http-apr-8080-exec-8] DEBUG o.s.w.s.h.SimpleUrlHandlerMapping - URI Template variables for request [/] are {}
16:31:44.435 [http-apr-8080-exec-8] DEBUG o.s.w.s.h.SimpleUrlHandlerMapping - Mapping [/] to HandlerExecutionChain with handler [org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler@1b8fe99] and 1 interceptor
16:31:44.435 [http-apr-8080-exec-8] DEBUG o.s.web.servlet.DispatcherServlet - Last-Modified value for [/] is: -1
16:31:44.436 [http-apr-8080-exec-8] DEBUG o.s.s.w.c.HttpSessionSecurityContextRepository - SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
16:31:44.436 [http-apr-8080-exec-8] DEBUG o.s.web.servlet.DispatcherServlet - Null ModelAndView returned to DispatcherServlet with name 'Enter': assuming HandlerAdapter completed request handling
16:31:44.436 [http-apr-8080-exec-8] DEBUG o.s.web.servlet.DispatcherServlet - Successfully completed request
16:31:44.436 [http-apr-8080-exec-8] DEBUG o.s.s.w.a.ExceptionTranslationFilter - Chain processed normally
16:31:44.436 [http-apr-8080-exec-8] DEBUG o.s.s.w.c.SecurityContextPersistenceFilter - SecurityContextHolder now cleared, as request processing completed

Debug logs from good run

16:35:26.914 [http-apr-8080-exec-2] DEBUG o.s.s.w.u.m.AntPathRequestMatcher - Checking match of request : '/'; against '/resources/**'
16:35:26.917 [http-apr-8080-exec-2] DEBUG o.s.security.web.FilterChainProxy - / at position 1 of 12 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
16:35:26.926 [http-apr-8080-exec-2] DEBUG o.s.security.web.FilterChainProxy - / at position 2 of 12 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
16:35:26.927 [http-apr-8080-exec-2] DEBUG o.s.s.w.c.HttpSessionSecurityContextRepository - No HttpSession currently exists
16:35:26.928 [http-apr-8080-exec-2] DEBUG o.s.s.w.c.HttpSessionSecurityContextRepository - No SecurityContext was available from the HttpSession: null. A new one will be created.
16:35:26.932 [http-apr-8080-exec-2] DEBUG o.s.security.web.FilterChainProxy - / at position 3 of 12 in additional filter chain; firing Filter: 'HeaderWriterFilter'
16:35:26.932 [http-apr-8080-exec-2] DEBUG o.s.s.w.h.writers.HstsHeaderWriter - Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@1e30dd63
16:35:26.932 [http-apr-8080-exec-2] DEBUG o.s.security.web.FilterChainProxy - / at position 4 of 12 in additional filter chain; firing Filter: 'CsrfFilter'
16:35:26.935 [http-apr-8080-exec-2] DEBUG o.s.security.web.FilterChainProxy - / at position 5 of 12 in additional filter chain; firing Filter: 'LogoutFilter'
16:35:26.936 [http-apr-8080-exec-2] DEBUG o.s.s.w.u.m.AntPathRequestMatcher - Request 'HEAD /' doesn't match 'POST /logout
16:35:26.936 [http-apr-8080-exec-2] DEBUG o.s.security.web.FilterChainProxy - / at position 6 of 12 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
16:35:26.936 [http-apr-8080-exec-2] DEBUG o.s.s.w.u.m.AntPathRequestMatcher - Request 'HEAD /' doesn't match 'POST /login
16:35:26.936 [http-apr-8080-exec-2] DEBUG o.s.security.web.FilterChainProxy - / at position 7 of 12 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
16:35:26.936 [http-apr-8080-exec-2] DEBUG o.s.security.web.FilterChainProxy - / at position 8 of 12 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
16:35:26.938 [http-apr-8080-exec-2] DEBUG o.s.security.web.FilterChainProxy - / at position 9 of 12 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
16:35:26.940 [http-apr-8080-exec-2] DEBUG o.s.s.w.a.AnonymousAuthenticationFilter - Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken@9055e4a6: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@957e: RemoteIpAddress: 127.0.0.1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS'
16:35:26.941 [http-apr-8080-exec-2] DEBUG o.s.security.web.FilterChainProxy - / at position 10 of 12 in additional filter chain; firing Filter: 'SessionManagementFilter'
16:35:26.941 [http-apr-8080-exec-2] DEBUG o.s.security.web.FilterChainProxy - / at position 11 of 12 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
16:35:26.941 [http-apr-8080-exec-2] DEBUG o.s.security.web.FilterChainProxy - / at position 12 of 12 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
16:35:26.942 [http-apr-8080-exec-2] DEBUG o.s.s.w.u.m.AntPathRequestMatcher - Checking match of request : '/'; against '/admin/*'
16:35:26.942 [http-apr-8080-exec-2] DEBUG o.s.s.w.a.i.FilterSecurityInterceptor - Public object - authentication not attempted
16:35:26.943 [http-apr-8080-exec-2] DEBUG o.s.security.web.FilterChainProxy - / reached end of additional filter chain; proceeding with original chain
16:35:26.947 [http-apr-8080-exec-2] DEBUG o.s.web.servlet.DispatcherServlet - DispatcherServlet with name 'Enter' processing HEAD request for [/]
16:35:26.952 [http-apr-8080-exec-2] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping - Looking up handler method for path /
16:35:26.956 [http-apr-8080-exec-2] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping - Returning handler method [public java.lang.String pkw.controllers.EnterController.enterMain(org.springframework.ui.Model)]
16:35:26.956 [http-apr-8080-exec-2] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'enterController'
16:35:26.956 [http-apr-8080-exec-2] DEBUG o.s.web.servlet.DispatcherServlet - Last-Modified value for [/] is: -1

and more but not concerning the problem anymore (at least I think so... ^^) 

So the question is why Spring uses sometimes one mapping handler and sometimes antoher one even when I configured which one it suppose to use?

It's weird because I get two different results, one working and one not from exactly the same code O.o

P.S I checked all paths to solve this problem concerning bad deployment, Intellij not cleaning Tomcat properly on restart and so on. I also tried tune Tomcat memory. Nothing of it gave me the solution :/

Edit for Tiles Config as suggested by iamiddy

layout.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE tiles-definitions PUBLIC "-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN"
        "http://tiles.apache.org/dtds/tiles-config_3_0.dtd">

<tiles-definitions>
    <definition name="DefaultTemplate" template="/WEB-INF/pages/template/SiteTemplate.jsp">
        <put-attribute name="title" value="Home"/>
        <put-attribute name="header" value="/WEB-INF/pages/header.jsp"/>
        <put-attribute name="navbar" value="/WEB-INF/pages/navbar.jsp"/>
        <put-attribute name="body" value=""/>
        <put-attribute name="footer" value="/WEB-INF/pages/footer.jsp"/>
    </definition>

    <definition name="main" extends="DefaultTemplate">
        <put-attribute name="body" value="/WEB-INF/pages/main.jsp"/>
    </definition>
    <definition name="addUser" extends="DefaultTemplate">
        <put-attribute name="body" value="/WEB-INF/pages/addUser.jsp" />
    </definition>
    <definition name="users" extends="DefaultTemplate">
        <put-attribute name="body" value="/WEB-INF/pages/users.jsp" />
    </definition>
</tiles-definitions>

TilesConfigurer and ViewResolver are in WebConfig.java

回答1:

try to add the following requestHandlerMapping beans explicitly, if that

  <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />

<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>


回答2:

make sure that you are always returning the tiles definition and not the jsp pages as configures in your "/WEB-INF/layouts/layout.xml"

If you are already doing that please share the tiles definition and the resource file for the url & Tiles class.