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
try to add the following requestHandlerMapping beans explicitly, if that
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.