带有.jsp/.jsp后缀的Spring MVC链接返回404



我在我的Spring-MVC (4.1.5.RELEASE) web应用程序中有一个简单的页面,名为headers.jsp,我想从我的索引页中调用,如下所示:

<body>
<c:url value="/headers" var="headersUrl1"/>
<c:url value="/headers.jsp" var="headersUrl2"/>
<c:url value="/headers.jspx" var="headersUrl3"/>
<ul>
    <li><a href="${headersUrl1}">Works!</a></li>
    <li><a href="${headersUrl2}">Does not work!</a></li>
    <li><a href="${headersUrl3}">Does not work!</a></li>
</ul> 

第一个url (to/headers)可以正常工作,但其他两个(后缀为.jsp/jspx)不行;结果是404。我有一个需要的链接工作(在现实生活中,他们来自一个遗留的数据库,我必须使用)。我花了相当多的时间在谷歌上搜索,但还没有找到解决方案。对链接的请求由以下控制器代码处理:

@Controller
public class HeadersViewController {
@RequestMapping(value = {"/headers"}, method = RequestMethod.GET)
public String getHeadersPage() {
    return "headers";
}
@RequestMapping(value = {"/headers**"}, method = RequestMethod.GET)
public String getHeaderPages() {
    return "headers";
}
@RequestMapping(value = {"/headers.jspx"}, method = RequestMethod.GET)
public String getHeaderPageJspx() {
    return "headers";
}
@RequestMapping("/{name}.jspx")
public String getPageByName(@PathVariable("name") String name) {
    return name;
}
}

当请求/headers.jsp或/headers.jspx时,没有任何控制器方法被调用。

奇怪的是,当使用spring-test和mock-mvc时,它们确实会被触发并测试以检查提到的url的通过。任何帮助,非常感谢!其余的配置代码如下所示。

Dispatcherservlet init:

public class DispatcherServletInitializer extends
    AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
    return new Class<?>[] { SecurityConfiguration.class, WebMvcConfiguration.class };
}
@Override
protected Class<?>[] getServletConfigClasses() {
    return new Class<?>[] { };
}
@Override
protected String[] getServletMappings() {
    return new String[] { "/" };
}
@Override
protected Filter[] getServletFilters() {
    return new Filter[] { new HiddenHttpMethodFilter() };
}
}

MvcConfiguration:

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"nl.demo.web.controller"})
public class WebMvcConfiguration extends WebMvcConfigurerAdapter {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
    registry.addViewController("/").setViewName("index");
    registry.addViewController("/index").setViewName("index");
    registry.addViewController("/login");
    registry.addViewController("/logout");
}
@Bean 
public InternalResourceViewResolver viewResolver() {
      InternalResourceViewResolver viewResolver=new InternalResourceViewResolver();
      viewResolver.setViewClass(JstlView.class);
      viewResolver.setPrefix("/WEB-INF/");
      viewResolver.setSuffix(".jsp");
      viewResolver.setOrder(0);
      return viewResolver;
}
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
}
 }
安全配置:

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
public void configure(WebSecurity web) throws Exception {
    web
        .ignoring()
            .antMatchers("/images/**", "/js/**", "/css/**", "/fonts/**");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        .authorizeRequests()
            .anyRequest().authenticated()
            .and()
        .formLogin()
            .loginPage("/login")
            .defaultSuccessUrl("/index")
            .failureUrl("/login?error=1")
            .permitAll()
            .and()
        .httpBasic()
            .and()
        .logout()
            .logoutUrl("/logout")
            .logoutSuccessUrl("/login?logout=1")
            .permitAll();
}

@Autowired
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    String user = "test";
    String password = "blabla";
    String[] roleList = "USER,SUPERVISOR".split(",");
    auth.inMemoryAuthentication()
        .withUser(user)
        .password(password)
        .roles(roleList);
}
}

最可能的原因是*.jsp*.jspx扩展通常由容器处理。例如,如果您签出tomcat的conf/web.xml,您将注意到配置

<servlet>
  <servlet-name>jsp</servlet-name> 
  <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class> 
</servlet>
<servlet-mapping>
  <servlet-name>jsp</servlet-name> 
  <url-pattern>*.jsp</url-pattern> 
  <url-pattern>*.jspx</url-pattern> 
</servlet-mapping>

其他容器也是如此。这就是为什么你的测试工作,但你真正的应用程序请求失败。

您最好的选择是实现一个过滤器,它将映射到相同的模式,并且将重定向headers.jspheaders.jspx,由控制器处理,同时将其他请求留给容器处理,因为它们通常是,您在这个问题上有一个例子

问题是您的servlet映射到/而不是/*/是一个特殊的映射,意味着Spring MVC DispatcherServlet接收所有未被其他任何管理的请求

由于JSP和JSF是自动注册的servlet, servlet容器尝试将请求传递给JSP (resp)。如果没有找到,它会立即发送404,并且不会尝试将其传递给DispatcherServlet。

您应该将dispatcher servlet映射到/*。但是要注意,在这种情况下,所有的URL都将被提供给分派器servlet,并且您必须对提供静态资源做特殊处理:您必须在Spring MVC配置文件中添加addResourceHandlers的覆盖(摘自Spring框架参考手册-提供静态资源):

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

最新更新