Spring Boot靜態資源處理


Spring Boot靜態資源處理

    <!-- 文章內容 -->
    <div data-note-content="" class="show-content">
      <div class="show-content-free">
        <h1>8.8 Spring Boot靜態資源處理</h1>

當使用Spring Boot來開發一個完整的系統時,我們往往需要用到前端頁面,這就不可或缺地需要訪問到靜態資源,比如圖片、css、js等文件。

Spring Boot使用 WebMvcAutoConfiguration 中的配置各種屬性, 默認為我們提供了靜態資源處理。如果需要特殊處理的再通過配置進行修改。

我們來看一下WebMvcAutoConfiguration類里面的默認配置。

靜態資源默認配置WebMvcAutoConfiguration

在WebMvcAutoConfiguration類里面有個addResourceHandlers方法:

        @Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
return;
}
Integer cachePeriod = this.resourceProperties.getCachePeriod();
if (!registry.hasMappingForPattern("/webjars/**")) {
customizeResourceHandlerRegistration(
registry.addResourceHandler("/webjars/**")
.addResourceLocations(
"classpath:/META-INF/resources/webjars/")
.setCachePeriod(cachePeriod));
}
String staticPathPattern = this.mvcProperties.getStaticPathPattern();
if (!registry.hasMappingForPattern(staticPathPattern)) {
customizeResourceHandlerRegistration(
registry.addResourceHandler(staticPathPattern)
.addResourceLocations(
this.resourceProperties.getStaticLocations())
.setCachePeriod(cachePeriod));
}
}

其中,針對webjars做了默認的處理:

registry.addResourceHandler("/webjars/**")
.addResourceLocations(
"classpath:/META-INF/resources/webjars/")

其中,如果當前的ResourceHandlerRegistry里面資源映射沒有 “/**”, 則啟用SpringBoot內置默認的靜態資源處理:

String staticPathPattern = this.mvcProperties.getStaticPathPattern();//"/**"
        <span class="hljs-keyword">if</span> (!registry.hasMappingForPattern(staticPathPattern)) {</br>
            customizeResourceHandlerRegistration(</br>
                    registry.addResourceHandler(staticPathPattern)</br>
                            .addResourceLocations(</br>
                                    <span class="hljs-keyword">this</span>.resourceProperties.getStaticLocations())</br>
                    .setCachePeriod(cachePeriod));</br>
        }</br>

默認的靜態資源映射路徑在ResourceProperties類里面,相關代碼如下:

private static final String[] CLASSPATH_RESOURCE_LOCATIONS = {
"classpath:/META-INF/resources/", "classpath:/resources/",
"classpath:/static/", "classpath:/public/" };

<span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> String[] RESOURCE_LOCATIONS;</br></br>

<span class="hljs-keyword">static</span> {</br>
    RESOURCE_LOCATIONS = <span class="hljs-keyword">new</span> String[CLASSPATH_RESOURCE_LOCATIONS.length</br>
            + SERVLET_RESOURCE_LOCATIONS.length];</br>
    System.arraycopy(SERVLET_RESOURCE_LOCATIONS, <span class="hljs-number">0</span>, RESOURCE_LOCATIONS, <span class="hljs-number">0</span>,</br>
            SERVLET_RESOURCE_LOCATIONS.length);</br>
    System.arraycopy(CLASSPATH_RESOURCE_LOCATIONS, <span class="hljs-number">0</span>, RESOURCE_LOCATIONS,</br>
            SERVLET_RESOURCE_LOCATIONS.length, CLASSPATH_RESOURCE_LOCATIONS.length);</br>
}</br></br>

<span class="hljs-comment">/**</br>
 * Locations of static resources. Defaults to classpath:[/META-INF/resources/,</br>
 * /resources/, /static/, /public/] plus context:/ (the root of the servlet context).</br>
 */</span></br>
<span class="hljs-keyword">private</span> String[] staticLocations = RESOURCE_LOCATIONS;</br>

即默認配置的 /** 映射到如下目錄:

classpath:/META-INF/resources/
classpath:/resources/
classpath:/static/
classpath:/public/

綜上所述,Spring Boot 默認配置為:

頁面請求路徑模式 靜態資源在工程的路徑 優先級
/** classpath:/META-INF/resources/ 第1優先
/** classpath:/resources/ 第2優先
/** classpath:/META-INF/resources/ 第3優先
/** classpath:/static/ 第4優先
/webjars/** classpath:/META-INF/resources/webjars/ -

自定義靜態資源映射

在SpringBoot集成Swagger的時候,我們需要增加swagger-ui.html映射到classpath:/META-INF/resources/,我們自定義配置類,繼承WebMvcConfigurerAdapter,然后重寫addResourceHandlers方法:

@Configuration
//@EnableWebMvc //這個注解會覆蓋掉SpringBoot的默認的靜態資源映射配置
class WebMvcConfig extends WebMvcConfigurerAdapter {
@Override
void addResourceHandlers(ResourceHandlerRegistry registry) {

    <span class="hljs-comment">//Swagger ui Mapping</span></br>
    registry.addResourceHandler(<span class="hljs-string">"swagger-ui.html"</span>)</br>
            .addResourceLocations(<span class="hljs-string">"classpath:/META-INF/resources/"</span>)</br></br>

}</br></br>

}

如果想要自己完全控制WebMVC(完全覆蓋SpringBoot默認配置),就需要在@Configuration注解的配置類上增加@EnableWebMvc,當增加@EnableWebMvc注解以后,WebMvcAutoConfiguration中配置就不會生效,會自動覆蓋了官方給出的/static, /public, META-INF/resources, /resources等存放靜態資源的目錄。而將靜態資源定位於src/main/webapp。

在spring-boot-features.adoc中指出,如果你的應用要打成jar形式來運行的話,不要把靜態資源放到src/main/webapp目錄,雖然這是標准目錄,但是僅在打war包的時候起作用。因為大多數的構建工具在打jar包的時候,會默認忽略此目錄:

TIP: Do not use the src/main/webapp directory if your application will be packaged as a
jar. Although this directory is a common standard, it will only work with war packaging
and it will be silently ignored by most build tools if you generate a jar.

當需要重新定義好資源所在目錄時,則需要主動添加上述的那個配置類,來Override addResourceHandlers方法。你需要自己來配置需要的每一項。

這種方式會在默認的基礎上增加

swagger-ui.html映射到classpath:/META-INF/resources/

不會影響默認的方式,可以同時使用。

前端資源的引用方法

在index.ftl中該如何引用上面的靜態資源呢?
推薦默認的寫法如下:

<link rel="stylesheet" type="text/css" href="/css/index.css">
<script type="text/javascript" src="/js/index.js"></script>

注意:默認配置的/**映射到/static(或/public ,/resources,/META-INF/resources)

當請求/css/index.css的時候,Spring MVC 會在/static/目錄下面找到。

如果配置為/static/js/index.js

<script src="${request.contextPath}/static/js/index.js"></script>

那么上面配置的幾個目錄下面都沒有/static目錄,因此會找不到資源文件。

這個時候,就需要另外添加自定義的映射了:

registry.addResourceHandler("/static/**")
               .addResourceLocations("classpath:/static/")

所以,當我們使用SpringBoot默認靜態資源配置的時候,寫靜態資源位置不要帶上映射的目錄名(如/static/,/public/ ,/resources/,/META-INF/resources/)。

使用WebJars

Spring Boot 在支持 Spring MVC的靜態資源處理的特性的同時, 允許使用jar包版本的靜態資源和使用版本無關的URL的靜態資源的引用。它就是Webjars[1]。

例如,使用jQuery,添加依賴:

compile group: 'org.webjars.bower', name: 'jquery', version: '3.2.1'

然后,在前端html代碼中,就可以直接如下使用:

<script type="text/javascript" src="/webjars/jquery/3.2.1/jquery.js"></script>

你可能注意到href中的1.11.3版本號了,如果僅僅這么使用,那么當我們切換版本號的時候還要手動修改href,比較麻煩。我們完全可以約定一套目錄規則,把后端webjars的依賴版本,直接傳遞到后端。而負責完成維護管理這套目錄規則的人就是webjars-locator。webjars-locator通過在classpath中尋找需要加載的靜態資源,然后引入前端頁面。查找路徑的邏輯的方法是WebJarAssetLocator類里的getFullPath方法。

我們要想使用webjars-locator,先要添加依賴:

    //Group: org.webjars.bower
    // https://mvnrepository.com/artifact/org.webjars/webjars-locator
    compile group: 'org.webjars', name: 'webjars-locator', version: '0.32'

然后,增加一個WebJarController:

package com.easy.springboot.h5perf.controller

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

import javax.servlet.http.HttpServletRequest

/**

  • Created by jack on 2017/4/22.

    */

    @Controller

    class WebJarsController {

    WebJarAssetLocator assetLocator = new WebJarAssetLocator();

    @ResponseBody

    @RequestMapping("/webjarslocator/{webjar}/**")

    def ResponseEntity<?> 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);

    }

    }

    }

然后,前端代碼使用方式如下:

<link href="${request.contextPath}/webjarslocator/datatables/jquery.dataTables.min.css" rel="stylesheet" type="text/css">
<link href="${request.contextPath}/webjarslocator/tether/tether.min.css" rel="stylesheet" type="text/css">
<link href="${request.contextPath}/css/index.css" rel="stylesheet" type="text/css">
<link href="${request.contextPath}/css/report.css" rel="stylesheet" type="text/css">

<script src="${request.contextPath}/webjarslocator/jquery/jquery.min.js"></script>

<script src="${request.contextPath}/js/index.js"></script>

<script src="${request.contextPath}/webjarslocator/tether/tether.min.js"></script>

<script src="${request.contextPath}/webjarslocator/bootstrap/bootstrap.min.js"></script>

<script src="${request.contextPath}/webjarslocator/datatables/jquery.dataTables.min.js"></script>

這里是freemarker的模板view代碼示例。其中,request對象是內置對象。在application.yml配置如下:

spring:
# 在freemarker獲取request對象
freemarker:
request-context-attribute: request

注意:這里不需要在寫版本號了,但是注意寫url的時候,只是在原來url基礎上去掉了版本號,其他的都不能少!

靜態資源動態版本

當我們資源內容發生變化時,由於瀏覽器緩存,用戶本地的靜態資源還是舊的資源,為了防止這種情況導致的問題,我們在請求url的時候加個版本號。

版本號如:

<script type="text/javascript" src="/js/index.js?v=1.0.1"></script>

這個版本號1.0.1,可以由后端代碼傳到前端頁面${version}。

小結

本章節主要探討了Spring Boot 靜態資源處理的內容。當我們在開發中,遵循SpringBoot的默認配置,可以大大減少了我們靜態資源處理的工作。

本章節完整的工程代碼:

https://github.com/EasySpringBoot/h5perf

參考資料:

1.WebJars:http://www.webjars.org/

      </div>
    </div>
</div>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM