Spring Boot静态资源处理

  1. <!-- 文章内容 -->
  2. <div data-note-content="" class="show-content">
  3. <div class="show-content-free">
  4. <h1>8.8 Spring Boot静态资源处理</h1>

当使用Spring Boot来开发一个完整的系统时,我们往往需要用到前端页面,这就不可或缺地需要访问到静态资源,比如图片、css、js等文件。

Spring Boot使用 WebMvcAutoConfiguration 中的配置各种属性, 默认为我们提供了静态资源处理。如果需要特殊处理的再通过配置进行修改。

我们来看一下WebMvcAutoConfiguration类里面的默认配置。

静态资源默认配置WebMvcAutoConfiguration

在WebMvcAutoConfiguration类里面有个addResourceHandlers方法:

  1. @Override

  2. public void addResourceHandlers(ResourceHandlerRegistry registry) {

  3. if (!this.resourceProperties.isAddMappings()) {

  4. logger.debug("Default resource handling disabled");

  5. return;

  6. }

  7. Integer cachePeriod = this.resourceProperties.getCachePeriod();

  8. if (!registry.hasMappingForPattern("/webjars/**")) {

  9. customizeResourceHandlerRegistration(

  10. registry.addResourceHandler("/webjars/**")

  11. .addResourceLocations(

  12. "classpath:/META-INF/resources/webjars/")

  13. .setCachePeriod(cachePeriod));

  14. }

  15. String staticPathPattern = this.mvcProperties.getStaticPathPattern();

  16. if (!registry.hasMappingForPattern(staticPathPattern)) {

  17. customizeResourceHandlerRegistration(

  18. registry.addResourceHandler(staticPathPattern)

  19. .addResourceLocations(

  20. this.resourceProperties.getStaticLocations())

  21. .setCachePeriod(cachePeriod));

  22. }

  23. }

其中,针对webjars做了默认的处理:

  1. registry.addResourceHandler("/webjars/**")

  2. .addResourceLocations(

  3. "classpath:/META-INF/resources/webjars/")

其中,如果当前的ResourceHandlerRegistry里面资源映射没有 “/**”, 则启用SpringBoot内置默认的静态资源处理:

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

默认的静态资源映射路径在ResourceProperties类里面,相关代码如下:

  1. private static final String[] CLASSPATH_RESOURCE_LOCATIONS = {

  2. "classpath:/META-INF/resources/", "classpath:/resources/",

  3. "classpath:/static/", "classpath:/public/" };

  4. <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> String[] RESOURCE_LOCATIONS;</br></br>
  5. <span class="hljs-keyword">static</span> {</br>
  6.     RESOURCE_LOCATIONS = <span class="hljs-keyword">new</span> String[CLASSPATH_RESOURCE_LOCATIONS.length</br>
  7.             + SERVLET_RESOURCE_LOCATIONS.length];</br>
  8.     System.arraycopy(SERVLET_RESOURCE_LOCATIONS, <span class="hljs-number">0</span>, RESOURCE_LOCATIONS, <span class="hljs-number">0</span>,</br>
  9.             SERVLET_RESOURCE_LOCATIONS.length);</br>
  10.     System.arraycopy(CLASSPATH_RESOURCE_LOCATIONS, <span class="hljs-number">0</span>, RESOURCE_LOCATIONS,</br>
  11.             SERVLET_RESOURCE_LOCATIONS.length, CLASSPATH_RESOURCE_LOCATIONS.length);</br>
  12. }</br></br>
  13. <span class="hljs-comment">/**</br>
  14.  * Locations of static resources. Defaults to classpath:[/META-INF/resources/,</br>
  15.  * /resources/, /static/, /public/] plus context:/ (the root of the servlet context).</br>
  16.  */</span></br>
  17. <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方法:

  1. @Configuration

  2. //@EnableWebMvc //这个注解会覆盖掉SpringBoot的默认的静态资源映射配置

  3. class WebMvcConfig extends WebMvcConfigurerAdapter {

  4. @Override

  5. void addResourceHandlers(ResourceHandlerRegistry registry) {

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


如果想要自己完全控制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中该如何引用上面的静态资源呢?

推荐默认的写法如下:

  1. <link rel="stylesheet" type="text/css" href="/css/index.css">
  2. <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

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

那么上面配置的几个目录下面都没有/static目录,因此会找不到资源文件。

这个时候,就需要另外添加自定义的映射了:

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

所以,当我们使用SpringBoot默认静态资源配置的时候,写静态资源位置不要带上映射的目录名(如/static/,/public/ ,/resources/,/META-INF/resources/)。

使用WebJars

Spring Boot 在支持 Spring MVC的静态资源处理的特性的同时, 允许使用jar包版本的静态资源和使用版本无关的URL的静态资源的引用。它就是Webjars[1]。

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

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

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

  1. <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,先要添加依赖:

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

然后,增加一个WebJarController:

  1. package com.easy.springboot.h5perf.controller

  2. import org.springframework.core.io.ClassPathResource


  3. import org.springframework.http.HttpStatus


  4. import org.springframework.http.ResponseEntity


  5. import org.springframework.stereotype.Controller


  6. import org.springframework.web.bind.annotation.PathVariable


  7. import org.springframework.web.bind.annotation.RequestMapping


  8. import org.springframework.web.bind.annotation.ResponseBody


  9. import org.springframework.web.servlet.HandlerMapping


  10. import org.webjars.WebJarAssetLocator

  11. import javax.servlet.http.HttpServletRequest

  12. /**
    • 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);


    • }


    • }


    • }

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

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

  2. <link href="${request.contextPath}/webjarslocator/tether/tether.min.css" rel="stylesheet" type="text/css">

  3. <link href="${request.contextPath}/css/index.css" rel="stylesheet" type="text/css">

  4. <link href="${request.contextPath}/css/report.css" rel="stylesheet" type="text/css">

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


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

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


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


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

这里是freemarker的模板view代码示例。其中,request对象是内置对象。在application.yml配置如下:

  1. spring:

  2. # 在freemarker获取request对象

  3. freemarker:

  4. request-context-attribute: request

注意:这里不需要在写版本号了,但是注意写url的时候,只是在原来url基础上去掉了版本号,其他的都不能少!

静态资源动态版本

当我们资源内容发生变化时,由于浏览器缓存,用户本地的静态资源还是旧的资源,为了防止这种情况导致的问题,我们在请求url的时候加个版本号。

版本号如:

  1. <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/

  1. </div>
  2. </div>
  3. </div>

Spring Boot静态资源处理的更多相关文章

  1. Spring Boot 静态资源处理

    spring Boot 默认的处理方式就已经足够了,默认情况下Spring Boot 使用WebMvcAutoConfiguration中配置的各种属性. 建议使用Spring Boot 默认处理方式 ...

  2. Spring Boot 静态资源处理(转)

    Spring Boot 静态资源处理 Spring Boot 系列 Spring Boot 入门 Spring Boot 属性配置和使用 Spring Boot 集成MyBatis Spring Bo ...

  3. 从零开始的Spring Boot(3、Spring Boot静态资源和文件上传)

    Spring Boot静态资源和文件上传 写在前面 从零开始的Spring Boot(2.在Spring Boot中整合Servlet.Filter.Listener的方式) https://www. ...

  4. 十二、 Spring Boot 静态资源处理

    spring Boot 默认为我们提供了静态资源处理,使用 WebMvcAutoConfiguration 中的配置各种属性. 建议大家使用Spring Boot的默认配置方式,如果需要特殊处理的再通 ...

  5. Spring Boot 静态资源路径分析

    最近在接触一个看公司的java后台项目(采用的耶鲁大学开源的一个cas单点登录系统),用的是框架是Spring Boot,用的模板是Thymeleaf,于是我生成一个Spring Boot的项目,并且 ...

  6. Spring Boot 静态资源访问原理解析

    一.前言 springboot配置静态资源方式是多种多样,接下来我会介绍其中几种方式,并解析一下其中的原理. 二.使用properties属性进行配置 应该说 spring.mvc.static-pa ...

  7. Spring Boot 静态资源映射与上传文件路由配置

    默认静态资源映射目录 默认映射路径 在平常的 web 开发中,避免不了需要访问静态资源,如常规的样式,JS,图片,上传文件等;Spring Boot 默认配置对静态资源映射提供了如下路径的映射 /st ...

  8. Spring Boot 静态资源能加载css 不能加载js

    Spring Boot 配置拦截器的时候默认 是放行 静态资源 , 也就是说不需要进行配置 registry.addResourceHandler("/**") .addResou ...

  9. Spring Boot 静态资源处理,妙!

    作者:liuxiaopeng https://www.cnblogs.com/paddix/p/8301331.html 做web开发的时候,我们往往会有很多静态资源,如html.图片.css等.那如 ...

随机推荐

  1. Gift

    [问题描述] 人生赢家老王在网上认识了一个妹纸,然后妹纸的生日到了,为了表示自己的心 意,他决定送她礼物.可是她喜爱的东西特别多,然而他的钱数有限,因此他想 知道当他花一定钱数后剩余钱数无法再购买任何 ...

  2. 你真的懂SDWebImage?

    SDWebImage已经到了用烂了的地步,对于一名优秀的开发者来说,会用只是最简单的一步,我们要能够研究到其底层的技术实现和设计思路原理.在网上偶然间看到了一篇文章,感觉不错,略作修改,批注,后面的内 ...

  3. windows下写的脚本,在linux下执行失败

    Windows中的换行符为CRLF, 即正则表达式的rn(ASCII码为13和10), 而Unix(或Linux)换行符为LF, 即正则表达式的n. 在Windows和Linux下协同工作的时候, 往 ...

  4. 使用GitHub(转载)

    转自:http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000/00137628548491 ...

  5. [Swift通天遁地]四、网络和线程-(5)解析网络请求数据:String(字符串)、Data(二进制数据)和JSON数据

    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(shanqingyongzhi)➤博客园地址:山青咏芝(https://www.cnblogs. ...

  6. 对于Mobile模块化的概念认知(小白)

    最近刚刚学习了Mobile的一些基础知识,把它整理一下方便自己的学习 那什么是Mobile呢? 自己的理解是将一个项目中共同的部分抽出来,这样就形成了Mobile模块. 为什么要使用Mobile呢? ...

  7. javascript 获取时间

    Js获取当前日期时间及其它操作 var myDate = new Date();myDate.getYear();        //获取当前年份(2位)myDate.getFullYear();   ...

  8. jQuery使用手册,【新手必备】

    jQuery是一款同prototype一样优秀js开发库类,特别是对css和XPath的支持,使我们写js变得更加方便!如果你不是个js高手又想写出优 秀的js效果,jQuery可以帮你达到目的!   ...

  9. iOS - UITableView 多选功能实现

    :自定义Cell中的代码 #import <UIKit/UIKit.h> @interface TestCell : UITableViewCell @property(nonatomic ...

  10. JS——预解析

    1.排查语法错误 <script> console.log(1; </script> 2.变量提升和函数整体提升 <script> console.log(n1); ...