Serve Static Resources with Spring – 用Spring服务静态资源

最后修改: 2014年 11月 9日

1. Overview


This tutorial will explore how to serve static resources with Spring using both XML and Java configuration.


2. Using Spring Boot

2.使用Spring Boot

Spring Boot comes with a pre-configured implementation of ResourceHttpRequestHandler to facilitate serving static resources.

Spring Boot 预先配置了 ResourceHttpRequestHandler 的实现,以便为静态资源提供服务。

By default, this handler serves static content from any of the /static, /public, /resources, and /META-INF/resources directories that are on the classpath. Since src/main/resources is typically on the classpath by default, we can place any of these directories there.


For example, if we put an about.html file inside the /static directory in our classpath, then we can access that file via http://localhost:8080/about.html. Similarly, we can achieve the same result by adding that file in the other mentioned directories.


2.1. Custom Path Patterns


By default, Spring Boot serves all static content under the root part of the request, /**Even though it seems to be a good default configuration, we can change it via the spring.mvc.static-path-pattern configuration property. 

默认情况下,Spring Boot在请求的根部下提供所有静态内容,/**尽管这似乎是一个很好的默认配置,我们可以通过spring.mvc.static-path-pattern 配置属性来改变它。

For example, if we want to access the same file via http://localhost:8080/content/about.html, we can say so in our

例如,如果我们想通过http://localhost:8080/content/about.html 访问同一个文件,我们可以在我们的>中这样说:


In WebFlux environments, we should use the spring.webflux.static-path-pattern property.


2.2. Custom Directories


Similar to path patterns, it’s also possible to change the default resource locations via the spring.web.resources.static-locations configuration property. This property can accept multiple comma-separated resource locations:



Here we’re serving static contents from the /files and /static-files directories inside the classpath. Moreover, Spring Boot can serve static files from outside of the classpath:

在这里,我们从classpath中的/files/static-files目录中提供静态内容。此外,Spring Boot可以从classpath之外提供静态文件


Here we’re using the file resource signature, file:/, to serve files from our local disk.


3. XML Configuration


If we need to go the old fashion way with XML-based configuration, we can make good use of the mvc:resources element to point to the location of resources with a specific public URL pattern.


For example, the following line will serve all requests for resources coming in with a public URL pattern, like “/resources/**”, by searching in the “/resources/” directory under the root folder in our application:


<mvc:resources mapping="/resources/**" location="/resources/" />

Now we can access a CSS file like in the following HTML page:


<%@ taglib uri="" prefix="c" %>
    <link href="<c:url value="/resources/myCss.css" />" rel="stylesheet">
    <h1>Hello world!</h1>

4. The ResourceHttpRequestHandler


Spring 3.1. introduced the ResourceHandlerRegistry to configure ResourceHttpRequestHandlers for serving static resources from the classpath, the WAR, or the file system. We can configure the ResourceHandlerRegistry programmatically inside our web context configuration class.

Spring 3.1.引入了ResourceHandlerRegistry来配置ResourceHttpRequestHandlers 用于服务来自classpath、WAR或文件系统的静态资源。我们可以在我们的Web上下文配置类中以编程方式配置ResourceHandlerRegistry

4.1. Serving a Resource Stored in the WAR


To illustrate this, we’ll use the same URL as before to point to myCss.css, but now the actual file will be located in the WAR’s webapp/resources folder, which is where we should place static resources when deploying Spring 3.1+ applications:

为了说明这一点,我们将使用与之前相同的URL指向myCss.css,但现在实际文件将位于WAR的webapp/resources文件夹中,这是我们在部署Spring 3.1+应用程序时应该放置静态资源的地方。

public class MvcConfig implements WebMvcConfigurer {
    public void addResourceHandlers(ResourceHandlerRegistry registry) {

Let’s analyze this example a bit. First, we configure the external-facing URI path by defining a resource handler. Then we map that external-facing URI path internally to the physical path where the resources are actually located.


We can, of course, define multiple resource handlers using this simple, yet flexible, API.


Now the following line in an html page would get us the myCss.css resource inside the webapp/resources directory:


<link href="<c:url value="/resources/myCss.css" />" rel="stylesheet">

4.2. Serving a Resource Stored in the File System


Let’s say we want to serve a resource stored in the /opt/files/ directory whenever a request comes in for the public URL matching the /files/** pattern. We simply configure the URL pattern and map it to that particular location on the disk:


public void addResourceHandlers(ResourceHandlerRegistry registry) {

For Windows users, the argument passed to addResourceLocations for this example would be “file:///C:/opt/files/“.


Once we configure the resource location, we can use the mapped URL pattern in our home.html to load an image stored in the file system:


<%@ taglib uri="" prefix="c" %>
    <link href="<c:url value="/resources/myCss.css" />" rel="stylesheet">
    <h1>Hello world!</h1>
    <img alt="image"  src="<c:url value="files/myImage.png" />">

4.3. Configuring Multiple Locations for a Resource


What if we want to look for a resource in more than one location?


We can include multiple locations with the addResourceLocations method. The list of locations will be searched in order until the resource is found:


public void addResourceHandlers(ResourceHandlerRegistry registry) {

The following curl request will display the Hello.html page stored in either the application’s webappp/resources or the other-resources folder in the classpath:


curl -i http://localhost:8080/handling-spring-static-resources/resources/Hello.html

5. The New ResourceResolvers


Spring 4.1. provides, with the new ResourcesResolvers, different types of resource resolvers that can be used to optimize browser performance when loading static resources. These resolvers can be chained and cached in the browser to optimize request handling.

Spring 4.1.提供了新的ResourcesResolvers,不同类型的资源解析器,可用于优化加载静态资源时的浏览器性能。这些解析器可以在浏览器中被链化和缓存,以优化请求处理。

5.1. The PathResourceResolver


This is the simplest resolver, and its purpose is to find a resource given a public URL pattern. In fact, if we don’t add a ResourceResolver to the ResourceChainRegistration, this is the default resolver.

这是最简单的解析器,它的目的是找到一个给定的公共 URL 模式的资源。事实上,如果我们不在ResourceResolver中添加ResourceChainRegistration,这就是默认的解析器。

Let’s look at an example:


public void addResourceHandlers(ResourceHandlerRegistry registry) {
      .addResolver(new PathResourceResolver());

Things to notice:


  • We’re registering the PathResourceResolver in the resource chain as the sole ResourceResolver in it. We can refer to section 4.3. to see how to chain more than one ResourceResolver.
  • The resources served will be cached in the browser for 3600 seconds.
  • The chain is finally configured with the method resourceChain(true).

Now for the HTML code that, in conjunction with the PathResourceResolver, locates the foo.js script in either the webapp/resources or the webapp/other-resources folder:


<script type="text/javascript" src="<c:url value="/resources/foo.js" />">

5.2. The EncodedResourceResolver


This resolver attempts to find an encoded resource based on the Accept-Encoding request header value.


For example, we may need to optimize bandwidth by serving the compressed version of a static resource using gzip content coding.


To configure an EncodedResourceResolver, we need to configure it in the ResourceChain, just as we configured the PathResourceResolver:


  .addResolver(new EncodedResourceResolver());

By default, the EncodedResourceResolver is configured to support br and gzip codings.


So the following curl request will get the zipped version of the Home.html file located in the file system in the Users/Me/ directory:


curl -H  "Accept-Encoding:gzip" 

Notice how we’re setting the header’s “Accept-Encoding” value to gzip. This is important because this particular resolver will only kick in if the gzip content is valid for the response.


Finally, note that, same as before, the compressed version will remain available for the period of time it is cached in the browser, which in this case is 3600 seconds.


5.3. Chaining ResourceResolvers


To optimize resource lookup, ResourceResolvers can delegate the handling of resources to other resolvers. The only resolver that can’t delegate to the chain is the PathResourceResolver, which we should add at the end of the chain.


In fact, if the resourceChain isn’t set to true, then by default only a PathResourceResolver will be used to serve resources. Here we’re chaining the PathResourceResolver to resolve the resource if the GzipResourceResolver is unsuccessful:


public void addResourceHandlers(ResourceHandlerRegistry registry) {
      .addResolver(new GzipResourceResolver())
      .addResolver(new PathResourceResolver());

Now that we’ve added the /js/** pattern to the ResourceHandler, let’s include the foo.js resource, located in the webapp/js/ directory in our home.html page:


<%@ taglib uri="" prefix="c" %>
    <link href="<c:url value="/resources/bootstrap.css" />" rel="stylesheet" />
    <script type="text/javascript"  src="<c:url value="/js/foo.js" />"></script>
    <h1>This is Home!</h1>
    <img alt="bunny hop image"  src="<c:url value="files/myImage.png" />" />
    <input type = "button" value="Click to Test Js File" onclick = "testing();" />

It’s worth mentioning that, as of Spring Framework 5.1, the GzipResourceResolver has been deprecated in favor of the EncodedResourceResolver. Therefore, we should avoid using it in the future.

值得一提的是,从 Spring Framework 5.1 开始,GzipResourceResolver已经被弃用,而改为EncodedResourceResolver。因此,我们应该在未来避免使用它。

6. Additional Security Configuration


If using Spring Security, it’s important to allow access to static resources. We’ll need to add the corresponding permissions for accessing the resource URL:

如果使用Spring Security,允许访问静态资源是很重要的。我们需要为访问资源的URL添加相应的权限。

<intercept-url pattern="/files/**" access="permitAll" />
<intercept-url pattern="/other-files/**/" access="permitAll" />
<intercept-url pattern="/resources/**" access="permitAll" />
<intercept-url pattern="/js/**" access="permitAll" />

7. Conclusion


In this article, we illustrated various ways in which a Spring application can serve static resources.


The XML-based resource configuration is a legacy option that we can use if we can’t go down the Java configuration route yet.


Spring 3.1. came out with a basic programmatic alternative through its ResourceHandlerRegistry object.

Spring 3.1.推出了通过其ResourceHandlerRegistry对象的基本程序化替代方案。

Finally, the new out of the box ResourceResolvers and ResourceChainRegistration object that shipped with Spring 4.1. offers resource loading optimization features, like caching and resource handler chaining, to improve efficiency in serving static resources.

最后,新的开箱即用的ResourceResolversResourceChainRegistration对象,随Spring 4.1出货。 提供资源加载优化功能,如缓存和资源处理程序链,以提高服务静态资源的效率。

As always, the full example is available over on Github. Additionally, Spring Boot related source codes are also available in this project.

一如既往,完整的示例可在 Github 上获取。此外,Spring Boot 的相关源代码也可在该项目中获得