springboot static resource processing

Transfer: https://blog.csdn.net/catoop/article/details/50501706

Spring Boot provides us with static resource processing by default, using the configuration properties in WebMvcAutoConfiguration.

It is recommended that you use the default configuration method of Spring Boot. If you need special processing, you can modify it through configuration.

If you want to fully control WebMVC by yourself, you need to add @EnableWebMvc to the configuration class annotated with @Configuration (the program entry class annotated with @SpringBootApplication already contains @Configuration). After adding this annotation, the configuration in WebMvcAutoConfiguration will not take effect, you need to do it yourself to configure everything you need. The configuration in this case still needs to look at the WebMvcAutoConfiguration class.

Since we are using Spring Boot quickly, we don't want to reconfigure too much ourselves. This article is mainly for the default processing method of Spring Boot, some of which are configured in the application configuration file (.properties or .yml)

Default resource mapping

When we start the application, we can see the following information in the console:

2016-01-08 09:29:30.362  INFO 24932 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] 2016-01-08 09:29:30.362 INFO 24932 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] 2016-01-08 09:29:30.437 INFO 24932 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
  • 1
  • 2
  • 3

Where the default configuration /** maps to /static (or /public, /resources, /META-INF/resources) 
where the default configuration /webjars/** maps to classpath:/META-INF/resources/webjars/ 
PS: The above static, public, resources and other directories are all under classpath: (such as src/main/resources/static).

If I store images with the same name in the following structure, what is the priority for Spring Boot to read the images? 
As shown below: 
write picture description here

When we visit the address  http://localhost:8080/fengjing.jpg  , which picture is displayed? Here the blogger can tell you directly that the priority order is: META/resources > resources > static > public 
If we want to access pic2.jpg, the request address is  http://localhost:8080/img/pic2.jpg

custom resource mapping

Above we introduced the default resource mapping of Spring Boot, which is generally enough, so how do we customize the directory? 
These resources are all packaged in jar packages, and in practical applications, we still have many resources that are dynamically maintained in the management system, and cannot be in the program package. How to access such resources in arbitrarily specified directories?

custom directory

 The code processing of  adding /myres/ * to classpath:/myres/*
as an example is: the implementation class inherits WebMvcConfigurerAdapter and rewrites the method addResourceHandlers (it has been mentioned in the previous article on WebMvcConfigurerAdapter that introduces interceptors)

package org.springboot.sample.config;

import org.springboot.sample.interceptor.MyInterceptor1; import org.springboot.sample.interceptor.MyInterceptor2; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; @Configuration public class MyWebAppConfigurer extends WebMvcConfigurerAdapter { @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/myres/**").addResourceLocations("classpath:/myres/"); super.addResourceHandlers(registry); } } 

 

The address of accessing the fengjing.jpg image in the myres folder is  http://localhost:8080/myres/fengjing.jpg 
This way of using code to customize the directory mapping does not affect the default mapping of Spring Boot and can be used at the same time.

If we change /myres/ * to /*  which is the same as the default, the system configuration will be overwritten. You can use addResourceLocations to add directories multiple times. The priority added first is higher than the one added later.

// 访问myres根目录下的fengjing.jpg 的URL为 http://localhost:8080/fengjing.jpg (/** 会覆盖系统默认的配置)
// registry.addResourceHandler("/**").addResourceLocations("classpath:/myres/").addResourceLocations("classpath:/static/");
  • 1
  • 2

The parameters of addResourceLocations are dynamic parameters, you can write addResourceLocations(“classpath:/img1/”, “classpath:/img2/”, “classpath:/img3/”);

Use an external directory

If we want to specify a folder with an absolute path (such as H:/myimgs/ ), we only need to use addResourceLocations to specify it.

// 可以直接使用addResourceLocations 指定磁盘绝对路径,同样可以配置多个位置,注意路径写法需要加上file:
registry.addResourceHandler("/myimgs/**").addResourceLocations("file:H:/myimgs/");
  • 1
  • 2

Configure via configuration file

The above is to use code to define the mapping of static resources. In fact, Spring Boot also provides us with methods that can be configured directly in application.properties (or .yml). 
The configuration method is as follows:

# 默认值为 /**
spring.mvc.static-path-pattern=
# 默认值为 classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/ 
spring.resources.static-locations=这里设置要指向的路径,多个使用英文逗号隔开,
  • 1
  • 2
  • 3
  • 4

Use spring.mvc.static-path-pattern to redefine the pattern. If it is changed to /myres/**, the fengjing.jpg file in the static directory should be  http://localhost:8080/myres/fengjing.jpg  , before modification, use spring.resources.static-locations for  http://localhost:8080/fengjing.jpg 
to redefine the path pointed to by pattern, support classpath: and file: (described above) 
Pay attention to spring.mvc. Only one static-path-pattern can be defined, and multiple comma-separated methods are currently not supported.

used in the page

The above examples have also explained how to access static resources. In fact, there is nothing special about using jsp or freemarker in the page. It is the same as we usually develop web projects. 
Below is my index.jsp:

<body>
    <img alt="读取默认配置中的图片" src="${pageContext.request.contextPath }/pic.jpg"> <br/> <img alt="读取自定义配置myres中的图片" src="${pageContext.request.contextPath }/myres/fengjing.jpg"> </body>
  • 1
  • 2
  • 3
  • 4
  • 5

using webjars

First talk about what is webjars? In Web development, we use more and more JS or CSS in front-end pages, such as jQuery, etc. Usually, we copy these Web resources to the Java directory. This manual copying may cause version errors. , the copy version is wrong, and the front-end page cannot be displayed correctly. 
WebJars is derived to solve this problem. These Web front-end resources are packaged into Java Jar packages, and then managed by Maven to ensure the uniqueness of these Web resource versions.

WebJars is to put js, css and other resource files in classpath:/META-INF/resources/webjars/, and then package them into jars and publish them in the maven repository.

Simple application

Taking jQuery as an example, the file storage structure is:

META-INF/resources/webjars/jquery/2.1.4/jquery.js
META-INF/resources/webjars/jquery/2.1.4/jquery.min.js META-INF/resources/webjars/jquery/2.1.4/jquery.min.map META-INF/resources/webjars/jquery/2.1.4/webjars-requirejs.js
  • 1
  • 2
  • 3
  • 4

Spring Boot maps /webjars/** to classpath:/META-INF/resources/webjars/ by default. Combined with the rules for accessing resources we mentioned above, we can know that our method of introducing jquery.js in JSP pages is :

<script type="text/javascript" src="${pageContext.request.contextPath }/webjars/jquery/2.1.4/jquery.js"></script>
  • 1

To achieve this, we only need to add jquery's webjars dependency in the pom.xml file, as follows:

<dependency>
    <groupId>org.webjars</groupId> <artifactId>jquery</artifactId> <version>2.1.4</version> </dependency>
  • 1
  • 2
  • 3
  • 4
  • 5

Version number unified management

However, in our actual development, we may encounter the situation of upgrading the version number. If we have more than 100 pages, and almost every page has jquery.js imported as above, then we need to replace the version number with 3.0.0, a A replacement is obviously not the best way. 
How to solve it? It can be handled as follows.

First add dependencies in pom.xml:

<dependency>
    <groupId>org.webjars</groupId> <artifactId>webjars-locator</artifactId> </dependency>
  • 1
  • 2
  • 3
  • 4

Then add a WebJarsController:

package org.springboot.sample.controller;

import javax.servlet.http.HttpServletRequest; import org.springframework.core.io.ClassPathResource; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.servlet.HandlerMapping; import org.webjars.WebJarAssetLocator; /** * 处理WebJars,自动读取版本号 * * @author 单红宇(365384722) * @myblog http://blog.csdn.net/catoop/ * @create 2016年1月8日 */ @Controller public class WebJarsController { private final WebJarAssetLocator assetLocator = new WebJarAssetLocator(); @ResponseBody @RequestMapping("/webjarslocator/{webjar}/**") public ResponseEntity<Object> locateWebjarAsset(@PathVariable String webjar, HttpServletRequest request) { try { String mvcPrefix = "/webjarslocator/" + webjar + "/"; // This prefix must match the mapping path! String mvcPath = (String) request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE); String fullPath = assetLocator.getFullPath(webjar, mvcPath.substring(mvcPrefix.length())); return new ResponseEntity<>(new ClassPathResource(fullPath), HttpStatus.OK); } catch (Exception e) { return new ResponseEntity<>(HttpStatus.NOT_FOUND); } } } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

The final way to use in the page:

<script type="text/javascript" src="${pageContext.request.contextPath }/webjarslocator/jquery/jquery.js"></script>
  • 1

Static resource version management

Spring provides support for static resource version mapping by default. 
When the content of our resource changes, the user's local resource is still the old resource due to browser caching, in order to prevent problems caused by this situation. We may choose to add the parameter "version number" or other methods after the resource file.

Use the version number parameter like:

<script type="text/javascript" src="${pageContext.request.contextPath }/js/common.js?v=1.0.1"></script>
  • 1

In this way, when we modify the file, we manually modify the version number to prevent the URL file from being cached by the browser. There is also the problem that many files need to be modified. Or some people will increase the timestamp in a way that I think is the most inadvisable, every time the browser makes a request, it adds unnecessary pressure to the server.

However, Spring provides two solutions to solve this problem. 
* Resource name md5 method* 
1. Modify the application.properties configuration file (or .yml)

spring.resources.chain.strategy.content.enabled=true spring.resources.chain.strategy.content.paths=/**
  • 1
  • 2

All /** requested static resources will be processed.

  1. Create the ResourceUrlProviderController file
package org.springboot.sample.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.servlet.resource.ResourceUrlProvider; /** * 处理静态资源URL * * @author 单红宇(365384722) * @myblog http://blog.csdn.net/catoop/ * @create 2016年1月8日 */ @ControllerAdvice public class ResourceUrlProviderController { @Autowired private ResourceUrlProvider resourceUrlProvider; @ModelAttribute("urls") public ResourceUrlProvider urls() { return this.resourceUrlProvider; } } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  1. spelling used in the page
<script type="text/javascript" src="${pageContext.request.contextPath }${urls.getForLookupPath('/js/common.js') }"></script>
  • 1

When we visit the page, the actual generated code in HTML is:

<script type="text/javascript" src="/myspringboot/js/common-c6b7da8fffc9be141b48c073e39c7340.js"></script>
  • 1

Where /myspringboot is the contextPath of my project

* Resource version number method* 
This method does not make much sense to me, and I will not explain it in detail. This is a unified version control for all resources, unlike the above md5, which is for files. 
Except the configuration in application.properties (or .yml) is different, the page usage is the same as md5.

spring.resources.chain.strategy.fixed.enabled=true spring.resources.chain.strategy.fixed.paths=/js/**,/v1.0.0/** spring.resources.chain.strategy.fixed.version=v1.0.0
  • 1
  • 2
  • 3

After this configuration, taking the above common.js as an example, the HTML code generated in the actual page is:

<script type="text/javascript" src="/myspringboot/v1.0.0/js/common.js"></script>
  • 1

*The processing principle of md5 and version number method* The 
urls.getForLookupPath method will be called first in the page, and a /v1.0.0/js/common.js or /css/common-c6b7da8fffc9be141b48c073e39c7340.js will be returned, 
and then the browser will initiate a request. 
When the requested address is in md5 mode, it will try to see if the file name in the url contains -, if it does, the latter part will be removed, and then go to the mapped directory (such as /static/) to find the /js/common.js file, if Return if you can find it.

When the requested address is in version number mode, it will judge whether /v1.0.0 exists in the url. If it exists, first remove /v1.0.0 from the URL, then go to the mapping directory to find the corresponding file, and return if found.

Summarize

There are so many ways to manage our resource files, but although they may be used in practical applications (there is a reason for existence), but based on personal experience. 
1. When we use a third-party library, it is recommended to use the webjars method and use it through the dynamic version number (webjars-locator method) (because the third-party library changes very little during project development, even if it changes, it is the version number. Revise). 
2. When we use the resources stored in the static resource mapping directory, it is recommended to use the md5 resource file name (some css and js files will be modified frequently during project development). 
3. It is recommended that the project material files be placed in the classpath:/static (or other) directory, packaged in the project, and some images and resources maintained by the CMS, we use the configuration to refer to the specific absolute disk path for use. 
4. Note that when using the md5 file name method, Spring has a caching mechanism, that is to say, if you change and modify these resource files without restarting the service, the md5 value of the file name will not change, only Restart the service to access it again to take effect. If you need to get the md5 value of the actual file every time, you need to rewrite the relevant class to achieve this. We do not recommend this, because it takes performance costs to calculate the md5 value of the file all the time.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325204704&siteId=291194637