2

I have a simple page called headers.jsp in my Spring-MVC (4.1.5.RELEASE) web-app which i would like to call up from my index page like this:

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

The first url (to /headers) works fine but the other two (with suffix .jsp/jspx) do not; result is a 404. I have a need for the links to work (in real life they come from a legacy database which i have to use). I have spent quite some time googling but found no solution as yet. The requests to links are handled by the following controller code:

@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;
}
}

None of the controller methods get called when requesting /headers.jsp or /headers.jspx.

Strangely enough when using spring-test and mock-mvc they do get fired and tests to check the mentioned url`s passes. Any help greatly appreciated! The rest of the config code is given below.

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();
}
 }

Security config:

@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);
}
}
s.ijpma
  • 930
  • 1
  • 11
  • 23

2 Answers2

1

The most likely cause of your issue is that the *.jsp and *.jspx extensions are normally handled by the container. If you for example checkout tomcat's conf/web.xml you'll notice a configuration

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

Similar goes for other containers. That is why your tests are working, yet your real app request fail.

Your best option would be to implement a Filter, that will be mapped to the same pattern, and that will redirect the headers.jsp and headers.jspx, to be handled by the controller, while leaving the other requests to be processed by the container as they would normally be, you have an example at this question

Community
  • 1
  • 1
Master Slave
  • 27,771
  • 4
  • 57
  • 55
  • This works for me, i have implemented a new Filter that forwards the request to the servletPath if the servletPath endswith .jsp/.jspx. Adding @WebFilter(urlPatterns = "/*") as annotation the the Filter and adding it to the getServletFilters of the dispatcher init does the trick! Big thank you! – s.ijpma Jun 08 '15 at 13:32
0

The problem is that your servlet is mapped to / and not to /*. / is a special mapping meaning that Spring MVC DispatcherServlet receives all requests that have not been managed by anything else.

As JSP and JSF are automatically registered servlets, the servlet container tries to pass the request to a JSP (resp. JSF) file and if it does not find it immediately sends a 404 and does not try to pass it to the DispatcherServlet.

You should map the dispatcher servlet to /*. But beware in that case, all URL will be given to the dispatcher servlet, and you will have to do a special treatment for serving static resources : you must add an override for addResourceHandlers to your Spring MVC configuration file (extract from Spring Framework Reference Manual - Serving of static resources) :

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("/resources/**").addResourceLocations("/public-resources/");
}
Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252