Static Resources

    这个选项提供了一个方便的方法,从基于资源的位置列表中提供静态资源。

    在下一个例子中,给定一个以 /resources开头的请求,相对路径被用来寻找和提供相对于 Web 应用根下的 /public/static下classpath 的静态资源。这些资源在未来一年内到期,以确保最大限度地利用浏览器的缓存,并减少浏览器的 HTTP 请求。Last-Modified信息是从 Resource#lastModified中推导出来的,因此 HTTP 条件请求支持 Last-Modified标头。

    下面的列表显示了如何用 Java 配置来做:

    1. @Configuration
    2. @EnableWebMvc
    3. public class WebConfig implements WebMvcConfigurer {
    4. @Override
    5. public void addResourceHandlers(ResourceHandlerRegistry registry) {
    6. // 含义是拦截 /resources 开头的请求
    7. registry.addResourceHandler("/resources/**")
    8. // 然后在这些指定的目录下去查找
    9. // 没有前缀的话,这默认为 webapp 目录
    10. // 这里有后面的 / 和没有含义区别是非常大的
    11. .addResourceLocations("/public", "classpath:/static/")
    12. .setCacheControl(CacheControl.maxAge(Duration.ofDays(365)));
    13. }
    14. }

    比如下图:
    image.png

    所以总结如下:

    • 如果没有任何前缀,默认是 webapp 目录下,如果加了前缀就是具体的 Resource 规则
    • 如果没有后缀的 / :则表示,需要写上这个目录才能访问到具体的资源
    • 如果有后缀的 /:则表示,不用写目录(如果写了,反而定位不到资源了),如果多个相同配置下都有同名的资源

      1. .addResourceLocations("/public/", "classpath:/static/")
      2. 然后访问:http://localhost:8080/resources/1.html
      3. 定位的资源是以这里的顺序来定位的,上图 public 下也有 1.html 所以会优先返回 public 下的资源

    下面的例子显示了如何在 XML 中实现同样的配置:

    1. <mvc:resources mapping="/resources/**"
    2. location="/public, classpath:/static/"
    3. cache-period="31556926" />

    请参见 静态资源的 HTTP 缓存支持

    资源处理程序还支持一 个ResourceResolver 实现和 ResourceTransformer 实现的链,你可以用它来 创建一个工具链来处理优化的资源

    你可以使用 VersionResourceResolver 来处理基于从内容计算的 MD5 哈希值、固定的应用程序版本或其他的版本资源 URL。ContentVersionStrategy(MD5 哈希值)是一个很好的选择 — 但有一些明显的例外,比如与模块加载器一起使用的 JavaScript 资源。

    下面的例子显示了如何在 Java 配置中使用 VersionResourceResolver:

    1. @Configuration
    2. @EnableWebMvc
    3. public class WebConfig implements WebMvcConfigurer {
    4. @Override
    5. public void addResourceHandlers(ResourceHandlerRegistry registry) {
    6. registry.addResourceHandler("/resources/**")
    7. .addResourceLocations("/public/")
    8. .resourceChain(true)
    9. .addResolver(new VersionResourceResolver().addContentVersionStrategy("/**"));
    10. }
    11. }

    对应的 xml 配置

    1. <mvc:resources mapping="/resources/**" location="/public/">
    2. <mvc:resource-chain resource-cache="true">
    3. <mvc:resolvers>
    4. <mvc:version-resolver>
    5. <mvc:content-version-strategy patterns="/**"/>
    6. </mvc:version-resolver>
    7. </mvc:resolvers>
    8. </mvc:resource-chain>
    9. </mvc:resources>

    然后你可以使用 ResourceUrlProvider 重写 URL,并应用完整的解析器和转换器链 — 例如,插入版本。MVC 配置提供了一个 ResourceUrlProvider bean,这样它就可以被注入到其他地方。你也可以用 ResourceUrlEncodingFilter 使重写透明化,用于 Thymeleaf、JSPs、FreeMarker 和其他具有依赖 HttpServletResponse#encodeURL 的 URL 标签。

    注意,当同时使用 EncodedResourceResolver(例如,用于服务 gzipped 或 brotli 编码的资源)和 VersionResourceResolver 时,你必须按照这个顺序注册它们。这可以确保基于内容的版本总是在未编码文件的基础上被可靠地计算出来。

    WebJars 也通过 WebJarsResourceResolver 来支持,当 classpath上有 org.webjars:webjars-locator-core库时,它就会自动注册。该解析器可以重写 URL,以包括 jar 的版本,也可以与传入的没有版本的 URL 相匹配,例如,从 /jquery/jquery.min.js/jquery/1.2.0/jquery.min.js

    :::tips 对于这个解析器的 ResourceUrlEncodingFilter 之类附加优化的还没搞明白怎么生效。 可能需要用到的时候再去看源码了 :::

    :::info 基于 ResourceHandlerRegistry 的 Java 配置为细粒度控制提供了进一步的选项,例如最后修改的行为和优化的资源解析。 :::