How to serve .html files with Spring

JavaSpringSpring Mvc

Java Problem Overview


I am developing a website with Spring, and am trying to serve resources that are not .jsp files (.html for example)

right now i have commented out this part of my servlet configuration

	<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver" 
		p:prefix="/WEB-INF/jsp/" p:suffix=".jsp" />

And tried to return fromthe controller the full path to the resource.

@Controller
public class LandingPageController {

protected static Logger logger = Logger.getLogger(LandingPageController.class);

@RequestMapping({"/","/home"})
public String showHomePage(Map<String, Object> model) {
	return "/WEB-INF/jsp/index.html";	
   }
}

the index.html file exists in that folder.

NOTE: when i change the index.html to index.jsp my server now serves the page correctly.

Thank you.

Java Solutions


Solution 1 - Java

The initial problem is that the the configuration specifies a property suffix=".jsp" so the ViewResolver implementing class will add .jsp to the end of the view name being returned from your method.

However since you commented out the InternalResourceViewResolver then, depending on the rest of your application configuration, there might not be any other ViewResolver registered. You might find that nothing is working now.

Since .html files are static and do not require processing by a servlet then it is more efficient, and simpler, to use an <mvc:resources/> mapping. This requires Spring 3.0.4+.

For example:

<mvc:resources mapping="/static/**" location="/static/" />

which would pass through all requests starting with /static/ to the webapp/static/ directory.

So by putting index.html in webapp/static/ and using return "static/index.html"; from your method, Spring should find the view.

Solution 2 - Java

I'd just add that you don't need to implement a controller method for that as you can use the view-controller tag (Spring 3) in the servlet configuration file:

<mvc:view-controller path="/" view-name="/WEB-INF/jsp/index.html"/>

Solution 3 - Java

Background of the problem

First thing to understand is following: it is NOT spring which renders the jsp files. It is JspServlet (org.apache.jasper.servlet.JspServlet) which does it. This servlet comes with Tomcat (jasper compiler) not with spring. This JspServlet is aware how to compile jsp page and how to return it as html text to the client. The JspServlet in tomcat by default only handles requests matching two patterns: *.jsp and *.jspx.

Now when spring renders the view with InternalResourceView (or JstlView), three things really takes place:

  1. get all the model parameters from model (returned by your controller handler method i.e. "public ModelAndView doSomething() { return new ModelAndView("home") }")
  2. expose these model parameters as request attributes (so that it can be read by JspServlet)
  3. forward request to JspServlet. RequestDispatcher knows that each *.jsp request should be forwarded to JspServlet (because this is default tomcat's configuration)

When you simply change the view name to home.html tomcat will not know how to handle the request. This is because there is no servlet handling *.html requests.

Solution

How to solve this. There are three most obvious solutions:

  1. expose the html as a resource file
  2. instruct the JspServlet to also handle *.html requests
  3. write your own servlet (or pass to another existing servlet requests to *.html).

For complete code examples how to achieve this please reffer to my answer in another post: https://stackoverflow.com/questions/16598594/how-to-map-requests-to-html-file-in-spring-mvc/32628600#32628600

Solution 4 - Java

You can still continue to use the same View resolver but set the suffix to empty.

<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver" 
    p:prefix="/WEB-INF/jsp/" p:suffix="" />

Now your code can choose to return either index.html or index.jsp as shown in below sample -

@RequestMapping(value="jsp", method = RequestMethod.GET )
public String startJsp(){
	return "/test.jsp";
}

@RequestMapping(value="html", method = RequestMethod.GET )
public String startHtml(){
	return "/test.html";
}	

Solution 5 - Java

> I faced the same issue and tried various solutions to load the html > page from Spring MVC, following solution worked for me

Step-1 in server's web.xml comment these two lines

<!--     <mime-mapping>
        <extension>htm</extension>
        <mime-type>text/html</mime-type>
    </mime-mapping>--> 
<!--     <mime-mapping>
        <extension>html</extension>
        <mime-type>text/html</mime-type>
    </mime-mapping>
 -->

Step-2 enter following code in application's web xml

  <servlet-mapping>
    <servlet-name>jsp</servlet-name>
    <url-pattern>*.htm</url-pattern>
</servlet-mapping>

Step-3 create a static controller class

@Controller 
public class FrontController {
	 @RequestMapping("/landingPage") 
	public String getIndexPage() { 
	return "CompanyInfo"; 

	}
	 
}

Step-4 in the Spring configuration file change the suffix to .htm .htm

Step-5 Rename page as .htm file and store it in WEB-INF and build/start the server

localhost:8080/.../landingPage

Solution 6 - Java

Java configuration for html files (in this case index.html):

@Configuration
@EnableWebMvc
public class DispatcherConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {

        registry.addResourceHandler("/index.html").addResourceLocations("/index.html");
    }

}

Solution 7 - Java

change p:suffix=".jsp" value acordingly otherwise we can develope custom view resolver

http://static.springsource.org/spring/docs/3.1.x/javadoc-api/org/springframework/web/servlet/view/UrlBasedViewResolver.html

Solution 8 - Java

It sounds like you are trying to do something like this:

  • Static HTML views
  • Spring controllers serving AJAX

If that is the case, as previously mentioned, the most efficient way is to let the web server(not Spring) handle HTML requests as static resources. So you'll want the following:

  1. Forward all .html, .css, .js, .png, etc requests to the webserver's resource handler
  2. Map all other requests to spring controllers

Here is one way to accomplish that...

web.xml - Map servlet to root (/)

<servlet>
			<servlet-name>sprung</servlet-name>
			<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            ...
<servlet>

<servlet-mapping>
			<servlet-name>sprung</servlet-name>
			<url-pattern>/</url-pattern>
</servlet-mapping>

Spring JavaConfig

public class SpringSprungConfig extends DelegatingWebMvcConfiguration {

	// Delegate resource requests to default servlet
	@Bean
	protected DefaultServletHttpRequestHandler defaultServletHttpRequestHandler() {
		DefaultServletHttpRequestHandler dsrh = new DefaultServletHttpRequestHandler();
		return dsrh;
	}

    //map static resources by extension
    @Bean
	public SimpleUrlHandlerMapping resourceServletMapping() {
		SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
        
        //make sure static resources are mapped first since we are using
        //a slightly different approach
		mapping.setOrder(0);
		Properties urlProperties = new Properties();
		urlProperties.put("/**/*.css", "defaultServletHttpRequestHandler");
		urlProperties.put("/**/*.js", "defaultServletHttpRequestHandler");
		urlProperties.put("/**/*.png", "defaultServletHttpRequestHandler");
		urlProperties.put("/**/*.html", "defaultServletHttpRequestHandler");
		urlProperties.put("/**/*.woff", "defaultServletHttpRequestHandler");
		urlProperties.put("/**/*.ico", "defaultServletHttpRequestHandler");
		mapping.setMappings(urlProperties);
		return mapping;
	}

	@Override
	@Bean
	public RequestMappingHandlerMapping requestMappingHandlerMapping() {
		RequestMappingHandlerMapping handlerMapping = super.requestMappingHandlerMapping();

        //controller mappings must be evaluated after the static resource requests
		handlerMapping.setOrder(1);
		handlerMapping.setInterceptors(this.getInterceptors());
	    handlerMapping.setPathMatcher(this.getPathMatchConfigurer().getPathMatcher());
		handlerMapping.setRemoveSemicolonContent(false);
		handlerMapping.setUseSuffixPatternMatch(false);
        //set other options here
		return handlerMapping;
	}
}

Additional Considerations

  • Hide .html extension - This is outside the scope of Spring if you are delegating the static resource requests. Look into a URL rewriting filter.
  • Templating - You don't want to duplicate markup in every single HTML page for common elements. This likely can't be done on the server if serving HTML as a static resource. Look into a client-side *VC framework. I'm fan of YUI which has numerous templating mechanisms including Handlebars.

Solution 9 - Java

In case you use spring boot, you must not set the properties spring.mvc.view.prefix and spring.mvc.view.suffix in your application.properties file, instead configure the bean ViewResolver from a configuration class.

application.properties

# Configured in @Configuration GuestNav
#spring.mvc.view.prefix=/WEB-INF/views/
#spring.mvc.view.suffix=.jsp
# Live reload
spring.devtools.restart.additional-paths=.
# Better logging
server.tomcat.accesslog.directory=logs
server.tomcat.accesslog.file-date-format=yyyy-MM-dd
server.tomcat.accesslog.prefix=access_log
server.tomcat.accesslog.suffix=.log

Main method

@SpringBootApplication
public class WebApp extends SpringBootServletInitializer {

	@Override
	protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
		return application.sources(WebApp.class);
	}

	public static void main(String[] args) throws Exception {
		SpringApplication.run(WebApp.class, args);
	}

}

Configuration class

@Configuration
@EnableWebMvc
public class DispatcherConfig implements WebMvcConfigurer {

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

    @Bean
    public ViewResolver viewResolver() {
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setViewClass(JstlView.class);
        viewResolver.setPrefix("/WEB-INF/notinuse/");
        viewResolver.setSuffix("");
        return viewResolver;
    }

}

A controller class

@Controller
public class GuestNav {

	@GetMapping("/")
	public String home() {
		return "forward:/views/guest/index.html";
	}
}

You must place your files in the directory /webapp/views/guest/index.html, be careful, the webapp directory is outside of the resources directory.
In this way you may use the url patterns of spring-mvc but serve static context.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionGleebView Question on Stackoverflow
Solution 1 - JavaandybView Answer on Stackoverflow
Solution 2 - JavaIvanView Answer on Stackoverflow
Solution 3 - JavawalkerosView Answer on Stackoverflow
Solution 4 - JavaSashiView Answer on Stackoverflow
Solution 5 - JavaAnimeshView Answer on Stackoverflow
Solution 6 - JavazygimantusView Answer on Stackoverflow
Solution 7 - JavaAnilHoneyView Answer on Stackoverflow
Solution 8 - JavaBreakerOfStonesView Answer on Stackoverflow
Solution 9 - JavaGeorgios SyngouroglouView Answer on Stackoverflow