Spring MVC 5 - Static resources handling example

Posted on February 6, 2018


This post shows you how to configure the resource handler to serve the static resources (CSS, JavaScript or Images) in spring MVC application.

You can also specify the cache period (in seconds) for served resources by resource handler.

Tools and technologies used for this application are -

  • Spring MVC 5.0.3.RELEASE
  • Servlet API 4.0.0
  • Java SE 9
  • Maven 3.5.2
  • Jetty Maven plugin 9.4.8
  • Eclipse Oxygen.2 Release (4.7.2)
     

Project structure

Final project structure of our application will look like as follows.

spring-mvc-static-resource.png

Related - How to create a web project using maven build tool in eclipse IDE.

Jar dependencies

Open pom.xml file of your maven project and add the following jars dependencies in your in it.

pom.xml

<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.boraji.tutorial.springmvc</groupId>
   <artifactId>spring-mvc-static-resource-example</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <packaging>war</packaging>
   <name>Spring MVC - Static Resources Mapping example</name>
   <properties>
      <failOnMissingWebXml>false</failOnMissingWebXml>
      <maven.compiler.source>9</maven.compiler.source>
      <maven.compiler.target>9</maven.compiler.target>
   </properties>
   <dependencies>
      <dependency>
         <groupId>org.springframework</groupId>
         <artifactId>spring-webmvc</artifactId>
         <version>5.0.3.RELEASE</version>
      </dependency>
      <dependency>
         <groupId>javax.servlet</groupId>
         <artifactId>javax.servlet-api</artifactId>
         <version>4.0.0</version>
         <scope>provided</scope>
      </dependency>
      <dependency>
         <groupId>javax.servlet.jsp</groupId>
         <artifactId>javax.servlet.jsp-api</artifactId>
         <version>2.3.2-b02</version>
         <scope>provided</scope>
      </dependency>
   </dependencies>
   <build>
      <plugins>
         <!-- Embedded Jetty HTTP Server for testing war application -->
         <plugin>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-maven-plugin</artifactId>
            <version>9.4.8.v20171121</version>
         </plugin>
      </plugins>
   </build>
</project>

Static Resources

First, create a CSS file under src\main\resources\statics\css folder and write the following code in it.

style.css

.color1 {
   color: black;
}
.color2 {
   color: red;
}

Next, create a JS file under src\main\resources\statics\js folder as follows.

app.js

function changeColor() {
   var title = document.getElementById('title');
   if (title.className == 'color1') {
   	title.className = 'color2';
   } else {
   	title.className = 'color1';
   }
}

Spring Web Configuration and Registering Resource Handler

To configure the resource handler, you need to override the default addResourceHandlers() method of WebMvcConfigurer interface in  your web @Configuration class as follows.

MvcWebConfig.java

package com.boraji.tutorial.spring.config;

import java.util.concurrent.TimeUnit;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.CacheControl;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@EnableWebMvc
@ComponentScan("com.boraji.tutorial.spring.controller")
public class MvcWebConfig implements WebMvcConfigurer {

   @Override
   public void configureViewResolvers(ViewResolverRegistry registry) {
      registry.jsp("/WEB-INF/views/", ".jsp");
   }

   @Override
   public void addResourceHandlers(ResourceHandlerRegistry registry) {

      // Register resource handler for CSS and JS
      registry.addResourceHandler("/resources/**").addResourceLocations("classpath:/statics/", "D:/statics/")
            .setCacheControl(CacheControl.maxAge(2, TimeUnit.HOURS).cachePublic());

      // Register resource handler for images
      registry.addResourceHandler("/images/**").addResourceLocations("/WEB-INF/images/")
            .setCacheControl(CacheControl.maxAge(2, TimeUnit.HOURS).cachePublic());
   }
}

As you can see, Spring will severs the static contents from either classpath:/statics/ or D:/statics/ for specified URL pattern /resources/**

You can specify the multiple locations of statics resources with comma separated list, Spring will check the given resource in the order specified.

Similar, you can register the resources handler for images files with cache period as shown in the above example.
 

 

Servlet container Initialization and configuration 

In Spring MVC, The DispatcherServlet needs to be declared and mapped for processing all requests either using java or web.xmlconfiguration.

In a Servlet 3.0+ environment, you can use AbstractAnnotationConfigDispatcherServletInitializer class to register and initialize the DispatcherServlet programmatically as follows.

MvcWebApplicationInitializer.java

package com.boraji.tutorial.spring.config;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

public class MvcWebApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

   @Override
   protected Class<?>[] getRootConfigClasses() {
      return null;
   }

   @Override
   protected Class<?>[] getServletConfigClasses() {
      return new Class[] { MvcWebConfig.class };
   }

   @Override
   protected String[] getServletMappings() {
      return new String[] { "/" };
   }

}

Controller class

Create a simple @Controller class under com.boraji.tutorial.spring.controller package as follows. 

MyContoller.java

package com.boraji.tutorial.spring.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class MyController {

   @GetMapping("/")
   public String index(Model model) {

      return "index";
   }
}

JSP views

To use the static resources in JSP views, you can you use the Spring <spring:url/> tag.

Create an index.jsp file under src\main\webapp\WEB-INF\views folder and write the following code in it.

index.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<%@ taglib uri="http://www.springframework.org/tags" prefix="spring"%>
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>BORAJI.COM</title>

<link href='<spring:url value="/resources/css/style.css"/>' rel="stylesheet" />
<script type="text/javascript" src='<spring:url value="/resources/js/app.js"/>'></script>

</head>
<body>
   <h1 id="title" class="color1">Spring MVC- Static Resource Mapping Example</h1>

   <button onclick="changeColor()">Change Color</button>
   <hr />
   
   <img alt="boraji.com" src="<spring:url value="/images/img01.png"/>" width="200">
</body>
</html>

 

Run application

Use the following maven command to run your application.

mvn jetty:run (This command deploy the webapp from its sources, instead of build war).

Enter the http://localhost:8080 URL in browser's address bar to test the resource handler configuration.

On entering the URL, you will see the following page.

spring-mvc-static-resource-01.png

Click on the Button to change the color of page header as specified in the CSS file.

spring-mvc-static-resource-02.png

Check the cache period of static resources -

spring-mvc-static-resource-03.png