How can I serve static html from spring boot?
Asked Answered
O

8

77

I ran the spring-boot-sample-web-static project from here, made this alteration to the pom

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>

And added this class to serve a duplicate page index2.html from the same static folder location:

import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class Rester {

    @RequestMapping(value = "/rand", produces = MediaType.APPLICATION_JSON_VALUE)
    @ResponseBody
    private RandomObj jsonEndpoint() {
        return new RandomObj();
    }

    @RequestMapping(value = "/tw")
    public String somePg() {
        return "index2";
    }
}

The json url works fine, but when I try to access localhost:8080/tw I get a blank page, and this error in the console:

2017-02-22 15:37:22.076 ERROR 21494 --- [nio-8080-exec-9] o.s.boot.web.support.ErrorPageFilter     : Cannot forward to error page for request [/tw] as the response has already been committed. As a result, the response may have the wrong status code. If your application is running on WebSphere Application Server you may be able to resolve this problem by setting com.ibm.ws.webcontainer.invokeFlushAfterService to false

Am I doing something wrong?

Officinal answered 22/2, 2017 at 13:44 Comment(2)
you don't really need tomcat dependency, spring starter web & thymeleaf should do it.Saprophyte
thymeloaf is not needed. Just put index.html in src/main/resources/static/ folder and static html is done!Suddenly
B
102

Static files should be served from resources, not from a controller.

Spring Boot will automatically add static web resources located within any of the following directories:

/META-INF/resources/  
/resources/  
/static/  
/public/

refs:
https://spring.io/blog/2013/12/19/serving-static-web-content-with-spring-boot
https://spring.io/guides/gs/serving-web-content/

Bughouse answered 22/2, 2017 at 13:49 Comment(8)
oh, ok so I saw that localhost:8080/index2.html is viewable from the browser actually, and there is no way to serve it from the controller ?Officinal
check my second ref link, or if u dont want to handle parameters: https://mcmap.net/q/266420/-controller-for-json-and-html-with-spring-bootBughouse
I have to add spring-boot-starter-thymeleaf and only refer to files in the templates directory, I think I got it, thank youOfficinal
thanks! I created the folders resources/static, put a index.html file and it just works!Wolof
where exactly should these directorys be? i hope src/main/resources is not served automaticallyEnzymology
These dirs should be located in src/main/resources. src/main/resources is not served automatically.Bughouse
I have my app.properties in resources and it doesn't serve itAcetify
@Bughouse any diff between src/main/resources and src/main/resources?Acetify
E
58

In Spring boot, /META-INF/resources/, /resources/, static/ and public/ directories are available to serve static contents.

So you can create a static/ or public/ directory under resources/ directory and put your static contents there. And they will be accessible by: http://localhost:8080/your-file.ext. (assuming the server.port is 8080)

You can customize these directories using spring.resources.static-locations in the application.properties.

For example:

spring.resources.static-locations=classpath:/custom/

Now you can use custom/ folder under resources/ to serve static files.

This is also possible using Java config in Spring Boot 2:

@Configuration
public class StaticConfig implements WebMvcConfigurer {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/static/**").addResourceLocations("classpath:/custom/");
    }
}

This confugration maps contents of custom directory to the http://localhost:8080/static/** url.

Entrance answered 19/2, 2018 at 9:9 Comment(1)
What if I want the file in the static folder to be returned by a Spring controller? Which path should I use in new File()?Tannin
C
12

I am using :: Spring Boot :: (v2.0.4.RELEASE) with Spring Framework 5

Spring Boot 2.0 requires Java 8 as a minimum version. Many existing APIs have been updated to take advantage of Java 8 features such as: default methods on interfaces, functional callbacks, and new APIs such as javax.time.

Static Content

By default, Spring Boot serves static content from a directory called /static (or /public or /resources or /META-INF/resources) in the classpath or from the root of the ServletContext. It uses the ResourceHttpRequestHandler from Spring MVC so that you can modify that behavior by adding your own WebMvcConfigurer and overriding the addResourceHandlers method.

By default, resources are mapped on /** and located on /static directory. But you can customize the static loactions programmatically inside our web context configuration class.

@Configuration @EnableWebMvc
public class Static_ResourceHandler implements WebMvcConfigurer {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        // When overriding default behavior, you need to add default(/) as well as added static paths(/webapp).

        // src/main/resources/static/...
        registry
            //.addResourceHandler("/**") // « /css/myStatic.css
            .addResourceHandler("/static/**") // « /static/css/myStatic.css
            .addResourceLocations("classpath:/static/") // Default Static Loaction
            .setCachePeriod( 3600 )
            .resourceChain(true) // 4.1
            .addResolver(new GzipResourceResolver()) // 4.1
            .addResolver(new PathResourceResolver()); //4.1

        // src/main/resources/templates/static/...
        registry
            .addResourceHandler("/templates/**") // « /templates/style.css
            .addResourceLocations("classpath:/templates/static/");

        // Do not use the src/main/webapp/... directory if your application is packaged as a jar.
        registry
            .addResourceHandler("/webapp/**") // « /webapp/css/style.css
            .addResourceLocations("/");

        // File located on disk
        registry
            .addResourceHandler("/system/files/**")
            .addResourceLocations("file:///D:/");
    }
}
http://localhost:8080/handlerPath/resource-path+name
                    /static         /css/myStatic.css
                    /webapp         /css/style.css
                    /templates      /style.css

In Spring every request will go through the DispatcherServlet. To avoid Static file request through DispatcherServlet(Front contoller) we configure MVC Static content.

As @STEEL said static resources should not go through Controller. Thymleaf is a ViewResolver which takes the view name form controller and adds prefix and suffix to View Layer.

Cidevant answered 20/11, 2018 at 13:56 Comment(0)
T
3

As it is written before, some folders (/META-INF/resources/, /resources/, /static/, /public/) serve static content by default, conroller misconfiguration can break this behaviour.

It is a common pitfall that people define the base url of a controller in the @RestController annotation, instead of the @RequestMapping annotation on the top of the controllers.

This is wrong:

@RestController("/api/base")
public class MyController {

    @PostMapping
    public String myPostMethod( ...) {

The above example will prevent you from opening the index.html. The Spring expects a POST method at the root, because the myPostMethod is mapped to the "/" path.

You have to use this instead:

@RestController
@RequestMapping("/api/base")
public class MyController {

    @PostMapping
    public String myPostMethod( ...) {
Therein answered 1/8, 2019 at 8:30 Comment(0)
R
3

I had to add thymeleaf dependency to pom.xml. Without this dependency Spring boot didn't find static resources.

 <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
Robinet answered 1/10, 2020 at 8:17 Comment(0)
F
3

There are three kinds of url in Spring Boot:

  1. relative to web application root: eg. "/abc"
  2. relative to classpath: eg. "classpath:/abc"
  3. relative to file system: eg. "file:/abc"

Return to the subject, in Spring Boot, static resources in the following 4 url can be accessed via "http://localhost:8080/${context root}/${your static resources}".

classpath:/META-INF/resources
classpath:/resources
classpath:/static
classpath:/public
Featherstone answered 15/5, 2023 at 17:37 Comment(0)
M
2

After creating a bunch of "findme.txt" files, each of which had different "source-relative" path string inside, I found that the following locations can be fetched with "http://host/findme.txt" are:

src/main/resources/public/findme.txt
src/main/resources/static/findme.txt
src/main/resources/resources/findme.txt - (yes, resources^2!)
src/main/resources/findme.txt - not found!!
Monniemono answered 12/4 at 15:23 Comment(0)
J
-1

You can quickly serve static content in JAVA Spring-boot App via thymeleaf (ref: source)

I assume you have already added Spring Boot plugin apply plugin: 'org.springframework.boot' and the necessary buildscript

Then go ahead and ADD thymeleaf to your build.gradle ==>

dependencies {
    compile('org.springframework.boot:spring-boot-starter-web')
    compile("org.springframework.boot:spring-boot-starter-thymeleaf")
    testCompile('org.springframework.boot:spring-boot-starter-test')
}

Lets assume you have added home.html at src/main/resources To serve this file, you will need to create a controller.

package com.ajinkya.th.controller;

  import org.springframework.stereotype.Controller;
  import org.springframework.web.bind.annotation.RequestMapping;

  @Controller
  public class HomePageController {

      @RequestMapping("/")
      public String homePage() {
        return "home";
      }

  }

Thats it ! Now restart your gradle server. ./gradlew bootRun

Jeffreyjeffreys answered 19/3, 2018 at 14:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.