Spring ResourceHandlerRegistry tutorial
last modified October 18, 2023
Spring ResourceHandlerRegistry tutorial shows how to serve static assets such as images, CSS or JavaScript files in Spring web applications.
Spring is a popular Java application framework for creating enterprise applications.
ResourceHandlerRegistry
ResourceHandlerRegistry stores registrations of resource handlers
for serving static resources such as images, css files and others through Spring
MVC. It allows setting cache headers optimized for efficient loading in a web
browser. Resources can be served out of locations under web application root,
from the classpath, and others.
Spring ResourceHandlerRegistry example
The following application uses ResourceHandlerRegistry to register
static assets in a Spring web application. We register handlers and locations
with addResourceHandlers for CSS and JavaScript files.
We use Thymeleaf as a view engine. We use Thymeleaf's @{} syntax
to point to the static resources.
pom.xml
src
├───main
│ ├───java
│ │ └───com
│ │ └───zetcode
│ │ ├───config
│ │ │ MyWebInitializer.java
│ │ │ WebConfig.java
│ │ └───controller
│ │ MyController.java
│ ├───resources
│ │ │ logback.xml
│ │ └───static
│ │ ├───css
│ │ │ format.css
│ │ └───js
│ │ main.js
│ └───webapp
│ └───WEB-INF
│ └───templates
│ homePage.html
└───test
└───java
This is the project structure.
<?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>staticresources</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.23</version>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
<version>3.0.11.RELEASE</version>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId>
<version>3.0.11.RELEASE</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.3.2</version>
</plugin>
</plugins>
</build>
</project>
In the pom.xml file we have the following dependencies: logback-classic,
javax.servlet-api, spring-webmvc, thymeleaf-spring5
and thymeleaf.
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<logger name="org.springframework" level="ERROR"/>
<logger name="com.zetcode" level="INFO"/>
<appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<Pattern>%d{HH:mm:ss.SSS} %blue(%-5level) %magenta(%logger{36}) - %msg %n
</Pattern>
</encoder>
</appender>
<root>
<level value="INFO" />
<appender-ref ref="consoleAppender" />
</root>
</configuration>
The logback.xml is a configuration file for the Logback logging library.
p {
background-color: aquamarine;
}
This is format.css file. It formats the p element.
const el = document.getElementById("block");
el.style.border = '1px dashed gray';
This is the main.js file. It adds border to the
div element. Note that even if JavaScript provides dynamic features
on the cient side, it is considerd a static resource from the perspective of Spring.
package com.zetcode.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
@Configuration
public class MyWebInitializer extends
AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return null;
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{WebConfig.class};
}
@Override
protected String[] getServletMappings() {
return new String[]{"/*"};
}
}
MyWebInitializer registers the Spring DispatcherServlet, which
is a front controller for a Spring web application.
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{WebConfig.class};
}
The getServletConfigClasses returns a web configuration class.
package com.zetcode.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
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;
import org.thymeleaf.spring5.SpringTemplateEngine;
import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver;
import org.thymeleaf.spring5.view.ThymeleafViewResolver;
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"com.zetcode"})
public class WebConfig implements WebMvcConfigurer {
@Autowired
private ApplicationContext applicationContext;
@Bean
public SpringResourceTemplateResolver templateResolver() {
var templateResolver = new SpringResourceTemplateResolver();
templateResolver.setApplicationContext(applicationContext);
templateResolver.setPrefix("/WEB-INF/templates/");
templateResolver.setSuffix(".html");
return templateResolver;
}
@Bean
public SpringTemplateEngine templateEngine() {
var templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(templateResolver());
templateEngine.setEnableSpringELCompiler(true);
return templateEngine;
}
@Bean
public ViewResolver viewResolver() {
var resolver = new ThymeleafViewResolver();
var registry = new ViewResolverRegistry(null, applicationContext);
resolver.setTemplateEngine(templateEngine());
registry.viewResolver(resolver);
return resolver;
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/js/**").addResourceLocations("classpath:/static/js/");
registry.addResourceHandler("/css/**").addResourceLocations("classpath:/static/css/");
}
}
The WebConfig enables Spring MVC annotations with @EnableWebMvc
and configures component scanning for the com.zetcode package. It sets up
the Thymeleaf engine and registers static resource handlers.
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/js/**").addResourceLocations("classpath:/static/js/");
registry.addResourceHandler("/css/**").addResourceLocations("classpath:/static/css/");
}
We override the addResourceHandlers to register handlers and locations
for JavaScript and CSS files.
package com.zetcode.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class MyController {
@GetMapping(value="/")
public String homePage() {
return "homePage";
}
}
MyController provides mappings for the home page. In the application,
we only use one view.
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Home page</title>
<link rel="stylesheet" th:href="@{/css/format.css}">
</head>
<body>
<div id="block">
<p>
This is home page.
</p>
</div>
<script th:src="@{/js/main.js}"></script>
</body>
</html>
The homePage.html is a view for the home page. It uses static resources;
one CSS and one JavaScript file.
<link rel="stylesheet" th:href="@{/css/format.css}">
We refer to the static files with specific Thymeleaf syntax.
In this article we have shown how to register static resources with
Spring's ResourceHandlerRegistry.
Author
List all Spring tutorials.