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.