Serving static content in Spring Boot

In this tutorial, we are going to show how to serve static content in Spring Boot. Static content consists of HTML, JavaScript, CSS files, or various types of images.

Spring is a popular Java application framework. Spring Boot is an effort to create stand-alone, production-grade Spring based applications with minimal effort.

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

The directories are located in the classpath or in the root of the ServletContext.

In our application, we have one HTML file which contains a simple link. The link triggers a response from the web Boot application. It returns a plain text message.

$ tree
.
├── pom.xml
└── src
    ├── main
    │   ├── java
    │   │   └── com
    │   │       └── zetcode
    │   │           ├── Application.java
    │   │           ├── bean
    │   │           │   └── Message.java
    │   │           └── controller
    │   │              └── MyController.java
    │   └── resources
    │       ├── application.properties
    │       └── static
    │           ├── css
    │           │  └── main.css
    │           └── index.html
    └── test
        └── java
            └── com
                └── zetcode
                    └── controller
                        └── MyControllerTest.java

This is the project structure of the Spring Boot application.

pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
                             http://maven.apache.org/xsd/maven-4.0.0.xsd">
    
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.zetcode</groupId>
    <artifactId>SpringBootStatic</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>
    
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.2.RELEASE</version>
    </parent>    
    
    <dependencies>
        
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>    
        
       
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>            
       
    </dependencies>    

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>            
        </plugins>
    </build>       
    
</project>

This is the Maven build file. The spring-boot-starter-web is starter for building web applications using Spring MVC. The spring-boot-starter-test imports necessary testing modules. The application is packaged into a JAR file.

Message.java
package com.zetcode.bean;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class Message {
    
    @Value("${app.message}")
    private String msg;
    
    public String get() {
        return msg;
    }
}

The Message sets up the Spring Boot application. The @SpringBootApplication annotation enables auto-configuration and component scanning.

@Value("${app.message}")
private String msg;

We inject a value from the application.properties into the msg variable.

application.properties
app.message=Hello there

The application.properties file contains various configuration settings of a Spring Boot application. We define a custom property having a text message.

MyController.java
package com.zetcode.controller;

import com.zetcode.bean.Message;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class MyController {

    @Autowired
    private Message message;

    @RequestMapping(path = "/msg", method = RequestMethod.GET)
    @ResponseBody
    public String message() {

        return message.get();
    }
}

This is the controller class for the Spring Boot web application. A controller is decorated with the @Controller annotation. The controller has one mapping; it is mapped to the /msg path and returns a plain text message.

@Autowired
private Message message;

A Message object is injected into the property.

@RequestMapping(path = "/msg", method = RequestMethod.GET)
@ResponseBody
public String message() {

    return message.get();
}

The message() method responds to a GET request. The @ResponseBody annotation puts the string value to the web response body.

index.html
<!DOCTYPE html>
<html>
    <head>
        <title>Home page</title>
        <link href="css/main.css" rel="stylesheet" type="text/css">
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
    </head>
    <body>
        <h2>This is home page</h2>
        
        <a href="/msg">Get message</a>
    </body>
</html>

In the index.html file we have a link that invokes a response from the web application. The file is located in the src/main/resources/static directory, which is a default directory where Spring looks for static content.

<link href="css/main.css" rel="stylesheet" type="text/css">

In the link tag we refer to the main.css static resource, which is located in the src/main/resources/static/css directory.

main.css
h2 { color: blue }

In the main.css file, we set the h2 tag to blue colour.

MyControllerTest.java
package com.zetcode.controller;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.forwardedUrl;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;

@RunWith(SpringRunner.class)
@SpringBootTest
public class MyControllerTest {

    @Autowired
    private WebApplicationContext wac;

    private MockMvc mockMvc;

    @Before
    public void setup() {
        this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
    }

    @Test
    public void getHome() throws Exception {
        this.mockMvc.perform(get("/"))
                .andDo(print())
                .andExpect(status().isOk())
                .andExpect(forwardedUrl("index.html"));;
    }

    @Test
    public void getMessage() throws Exception {
        this.mockMvc.perform(get("/msg"))
                .andDo(print())
                .andExpect(status().isOk())
                .andExpect(content().string("Hello there"));
    }
}

In the MyControllerTest we have two tests: one for the home page and one for the returned message text.

Application.java
package com.zetcode;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

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

The Application sets up the Spring Boot application. The @SpringBootApplication annotation enables auto-configuration and component scanning.

In this tutorial, we have served static context in a Spring Boot application. You might also be interested in the related tutorials: Spring Boot DataSourceBuilder tutorial, Spring Boot iText tutorial, Spring Boot RESTFul application, Introduction to Spring web applications, Standalone Spring applications, Java tutorial.