【WEEK9】 【DAY5】Web Development Static Resource Handling 【English Version】
2024.4.26 Friday
Contents
- 7. Web Development Static Resource Handling
-
-
7.1. Exploring Web Development
-
- 7.1.1. Introduction
- 7.1.2. Steps to use Spring Boot:
-
- 7.1.2.1. Create a Spring Boot application, choose the modules we need, and Spring Boot will automatically configure the required modules by default
-
7.1.2.2. Manually configure some settings in the configuration file to get started
-
7.1.2.3. Focus on writing business code, no need to worry about a pile of configurations like before.
-
7.2. Handling Static Resources
-
- 7.2.1. Static Resource Mapping Rules
-
- 7.2.1.1. Create a new springboot-03-web project
-
7.2.1.2. Delete irrelevant files
-
7.2.1.3. Create HelloController.java
-
7.2.1.4. Locate WebMvcAutoConfiguration (shortcut key shift+shift)
- 7.2.2. What are Webjars?
-
- 7.2.2.1. The first rule of static resource mapping
-
7.2.2.2. The second rule of static resource mapping
-
7.2.2.3. Customizing Static Resource Paths
- 7.2.3. Summary
-
- 7.2.3.1. In Spring Boot, we can use the following methods to handle static resources:
-
7.2.3.2. Priority: resources > static (default) > public
-
7.3. Handling Homepages
-
- 7.3.1. How to Customize the Homepage
-
- 7.3.1.1. Enter WebMvcAutoConfiguration.java
-
7.3.1.2. Modifying the Icon
-
7. Web Development Static Resource Handling
7.1. Exploring Web Development
7.1.1. Introduction
Next, we begin studying Spring Boot and Web Development; from this chapter onwards, it’s the practical part of the content;
Actually, using Spring Boot is very simple, as its biggest feature is automatic configuration.
7.1.2. Steps to use Spring Boot:
7.1.2.1. Create a Spring Boot application, choose the modules we need, and Spring Boot will automatically configure the required modules by default
7.1.2.2. Manually configure some settings in the configuration file to get started
7.1.2.3. Focus on writing business code, no need to worry about a pile of configurations like before.
To become proficient in development, one must clearly understand the principles of auto-configuration learned before!
For example, what exactly has Spring Boot configured for us? Can we modify it? What configurations can we modify? Can we extend it?
- Automatically configures components to the container: *** Autoconfiguration
- Auto-configuration class, encapsulates the content of the configuration file: ***Properties
Occasionally, search for classes and understand the principles of auto-configuration!
We will later carry out a small monolithic project test to allow everyone to quickly get started with development!
7.2. Handling Static Resources
7.2.1. Static Resource Mapping Rules
- Writing requests is very simple, but how do we introduce our frontend resources? We have many static resources in our project, such as CSS, JS files, etc. How does Spring Boot handle this?
- If we have a web application, under our main there would be a webapp, where we used to import all our pages, right! But now our pom, the packaging method is jar. So, can Spring Boot still handle our pages in this way? Of course, it can, but Spring Boot has specific rules about where static resources should be placed!
7.2.1.1. Create a new springboot-03-web project


After creation, a bizarre problem may occur -> delete and recreate
Add Maven support (click the plus sign in Project Structure->Modules to add the corresponding project),




Remember to rename the added names as needed

As usual, modify Maven settings, JDK, and Java version in settings, and JDK and Java version in Project Structure. Reload Maven and run again.
7.2.1.2. Delete irrelevant files

7.2.1.3. Create HelloController.java

package com.P14.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello(){
return "hello world";
}
}
Test it out
http://localhost:8080/hello

7.2.1.4. Locate WebMvcAutoConfiguration (shortcut key shift+shift)
In Spring Boot, the web configuration for Spring MVC is all contained within the WebMvcAutoConfiguration class.
Static resources are placed under the static folder (for more locations see the source code)
WebMvcAutoConfigurationAdapter (line188)
Find addResourceHandlers (line333) to add resource handlers
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
return;
} // If it has been customized, just return; how to customize?
addResourceHandler(registry, "/webjars/**", "classpath:/META-INF/resources/webjars/");
addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> {
registration.addResourceLocations(this.resourceProperties.getStaticLocations());
if (this.servletContext != null) {
ServletContextResource resource = new ServletContextResource(this.servletContext, SERVLET_LOCATION);
registration.addResourceLocations(resource);
}
});
}
How to customize: Locate @EnableConfigurationProperties({ WebMvcProperties.class, WebProperties.class }) (line186) and enter WebMvcProperties to configure it yourself.
Read the source code: For example, all /webjars/** needs to go to classpath:/META-INF/resources/webjars/ to find the corresponding resources.
7.2.2. What are Webjars?
Webjars are essentially static resources that are imported into our projects as jar files, as opposed to directly importing static resource files as before.
7.2.2.1. The first rule of static resource mapping
Using Spring Boot requires the use of Webjars:
https://www.webjars.org/

<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.4.1</version>
</dependency>
Insert this code into the dependencies section of the pom.xml file:
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.13</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>springboot-03-web2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-03-web2</name>
<description>springboot-03-web2</description>
<properties>
<java.version>8</java.version>
</properties>
<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>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.4.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Once imported, check the Webjars directory structure and access the Jquery.js file!

Restart and access: As long as it’s a static resource, Spring Boot will search for resources at the corresponding path. Here we access:
http://localhost:8080/webjars/jquery/3.4.1/jquery.js

7.2.2.2. The second rule of static resource mapping
How do we import our own static resources into our projects? Let’s look at the following line of code:
7.2.2.2.1. WebMvcAutoConfiguration.java -> getStaticPathPattern (line339) -> WebMvcProperties.java’s getStaticPathPattern method: Click on staticPathPattern (line184) -> private String staticPathPattern = “/**”; (line92) This statement means that everything in the directory can be recognized.
7.2.2.2.2. Inside WebMvcAutoConfiguration.java, go to WebMvcProperties (line186) -> enter resourceProperties to analyze.
For reading the source code, it’s recommended to view the structure clearly, use the shortcut key alt+7.
7.2.2.2.3. WebMvcProperties.java
private String[] staticLocations = CLASSPATH_RESOURCE_LOCATIONS;
(line95)
Click to enter CLASSPATH_RESOURCE_LOCATIONS
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = { "classpath:/META-INF/resources/",
"classpath:/resources/", "classpath:/static/", "classpath:/public/" };
(line88)
ResourceProperties allows setting parameters related to our static resources; it points to the directories where it will search for resources, as indicated by the array above.
Thus, we conclude that static resources stored in the following four directories can be recognized:
"classpath:/META-INF/resources/",
"classpath:/resources/",
"classpath:/static/",
"classpath:/public/"

JS files created in the above subfolders can be accessed.
7.2.2.2.4. Testing
Create three 1.js files, located in the public folder, resources folder, and static folder respectively, with contents “hello_public”, “hello_resources”, and “hello_static”. Restart and access:
http://localhost:8080/1.js

It appears that the JS file located under the resources folder has a higher priority than those in the other two folders.

After deleting the 1.js file from the resources, it is observed that the static folder has a higher priority than the public folder.

7.2.2.3. Customizing Static Resource Paths
We can also specify which folders to use for static resources through the configuration file. Configure it in application.properties.
For example: spring.resources.static-locations=classpath:/coding/,classpath:/kuang/
Once the static folder paths are custom defined, the original auto-configuration becomes invalid! This is highly discouraged.
7.2.3. Summary
7.2.3.1. In Spring Boot, we can use the following methods to handle static resources:
- Webjars
localhost:8080/webjars/ - public, static, /**, resources
localhost:8080/
7.2.3.2. Priority: resources > static (default) > public
7.3. Handling Homepages
7.3.1. How to Customize the Homepage
7.3.1.1. Enter WebMvcAutoConfiguration.java
Find the mapping method for the Welcome Page Handler Mapping (line 439):
@Bean
public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext,
FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) {
return createWelcomePageHandlerMapping(applicationContext, mvcConversionService, mvcResourceUrlProvider,
WelcomePageHandlerMapping::new);
}
@Bean
public WelcomePageNotAcceptableHandlerMapping welcomePageNotAcceptableHandlerMapping(
ApplicationContext applicationContext, FormattingConversionService mvcConversionService,
ResourceUrlProvider mvcResourceUrlProvider) {
return createWelcomePageHandlerMapping(applicationContext, mvcConversionService, mvcResourceUrlProvider,
WelcomePageNotAcceptableHandlerMapping::new);
}
private <T extends AbstractUrlHandlerMapping> T createWelcomePageHandlerMapping(
ApplicationContext applicationContext, FormattingConversionService mvcConversionService,
ResourceUrlProvider mvcResourceUrlProvider, WelcomePageHandlerMappingFactory<T> factory) {
TemplateAvailabilityProviders templateAvailabilityProviders = new TemplateAvailabilityProviders(
applicationContext);
String staticPathPattern = this.mvcProperties.getStaticPathPattern();
T handlerMapping = factory.create(templateAvailabilityProviders, applicationContext, getIndexHtmlResource(),
staticPathPattern);
handlerMapping.setInterceptors(getInterceptors(mvcConversionService, mvcResourceUrlProvider));
handlerMapping.setCorsConfigurations(getCorsConfigurations());
return handlerMapping;
}
Among them, line 459’s getIndexHtmlResource refers to the section at line 492:
private Resource getIndexHtmlResource() {
for (String location : this.resourceProperties.getStaticLocations()) {
Resource indexHtml = getIndexHtmlResource(location);
if (indexHtml != null) {
return indexHtml;
}
}
ServletContext servletContext = getServletContext();
if (servletContext is not null) {
return getIndexHtmlResource(new ServletContextResource(servletContext, SERVLET_LOCATION));
}
return null;
}
Moving further, you can see:
private Resource getIndexHtmlResource(String location) {
return getIndexHtmlResource(this.resourceLoader.getResource(location));
}
private Resource getIndexHtmlResource(Resource location) {
try {
Resource resource = location.createRelative("index.html");
if (resource.exists() && (resource.getURL() != null)) {
return resource;
}
}
catch (Exception ex) {
}
return null;
}
The line Resource resource = location.createRelative("index.html"); indicates that index.html will be mapped to the homepage.
Delete all existing 1.js files and create a new index.html:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>first page</h1>
</body>
</html>
Restart and visit:
http://localhost:8080/

7.3.1.2. Modifying the Icon
Select an image to import into IntelliJ IDEA and name it favicon.ico.
Explanation: Like other static resources, Spring Boot looks for favicon.ico in the configured static content locations. If such a file exists, it is automatically used as the application’s favicon.

Restart and visit (Chrome may not load it, but Edge works):
http://localhost:8080/

You might need to disable the Spring Boot default icon (although I didn’t need to do this to get the icon to load).
Versions after 2.2.x (like 2.3.0) don’t require this step.
# Disable default icon
spring.mvc.favicon.enabled=false
