Spring MVC - Spring 有时使用 RequestMappingHandlerMapping 有时使用 SimpleUrlHandlerMapping

Spring MVC - Spring uses sometimes RequestMappingHandlerMapping and sometimes SimpleUrlHandlerMapping

过去两天我一直在尝试解决这个问题,但到目前为止还没有找到答案。关于这个我研究了很多 google ;)

所以问题是我正在尝试使用 Hibernate 开发 Spring MVC 应用程序并将其部署在 Tomcat 8 本地服务器上。问题是在 10 运行 秒我有大约 6 次 404 Not Found 页面和 4 次我的应用程序我工作正常并显示我想要的东西。我做了一些挖掘并在调试日志中发现当请求映射失败时 Spring 使用 SimpleUrlHandlerMapping (我没有配置)并且当应用程序正常工作时 Spring 使用 RequestMappingHandlerMapping (我配置)。

然后是一些代码 ;)

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";

    }
}

错误的调试日志 运行

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

良好的调试日志运行

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... ^^) 

所以问题是为什么 Spring 有时使用一个映射处理程序,有时使用另一个映射处理程序,即使我配置了它应该使用的映射处理程序?

这很奇怪,因为我得到了两种不同的结果,一种有效,另一种不是来自完全相同的代码 O.o

P.S 我检查了所有路径以解决有关部署不当、Intellij 无法在重启时正确清理 Tomcat 等问题。我也试过调整 Tomcat 内存。它没有给我解决方案:/

按照 iamiddy 的建议编辑 Tiles Config

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 和 ViewResolver 在 WebConfig.java

确保您始终返回图块定义,而不是 jsp 页面,如 "/WEB-INF/layouts/layout.xml"

中配置的那样

如果您已经在这样做,请分享 url 和 Tiles class 的 tiles 定义和资源文件。

尝试显式添加以下 requestHandlerMapping beans,如果

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

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