Spring boot web app项目

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ZYC88888/article/details/84317004

static和templates部分参考博客:https://blog.csdn.net/wangb_java/article/details/71775637

热部署参考博客:https://www.cnblogs.com/cx-code/p/8686453.html

静态页面

spring boot项目只有src目录,没有webapp目录,会将静态访问(html/图片等)映射到其自动配置的静态目录,如下

/static

/public

/resources

/META-INF/resources

SpringBoot里面没有我们之前常规web开发的WebContent(WebApp),它只有src目录

在src/main/resources下面有两个文件夹,static和templates   springboot默认  static中放静态页面,而templates中放动态页面

扫描二维码关注公众号,回复: 4349601 查看本文章

静态页面:

 这里我们直接在static放一个hello.html,然后直接输入http://localhost:8080/hello.html便能成功访问

spring boot程序的static目录默认在resources/static目录, 打包为jar的时候,会把static目录打包进去,这样会存在一些问题:

  • static文件过多,造成jar包体积过大
  • 临时修改不方便

查看官方文档,可以发现,static其实是可以外置的。

1 直接修改配置文件

spring.resources.static-locations=file:///E://resources/static

2、自定义Configuration方法

@Configuration
public class StaticResourceConfiguration extends WebMvcConfigurerAdapter {
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/**").addResourceLocations("file:/path/to/my/dropbox/");
    }
}

 3、打包

修改pom,增加如下配置

<build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <finalName>workflow</finalName>
                </configuration>
            </plugin>
        </plugins>
        <resources>
            <resource>
                <directory>src/main/webapp</directory>
                <!--注意此次必须要放在此目录下才能被访问到 -->
                <targetPath>META-INF/resources</targetPath>
                <includes>
                    <include>**/**</include>
                </includes>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>true</filtering>
                <includes>
                    <include>**/*</include>
                </includes>
            </resource>
            <resource>
                <directory>src/main/java</directory>
                <excludes>
                    <exclude>**/*.java</exclude>
                </excludes>
            </resource>
        </resources>

    </build>

1. 默认情况下, 网页存放于static目录下, 默认的"/"指向的是~/resouces/static/index.html文
2. 如果引入了thymeleaf, 则默认指向的地址为~/resouces/templates/index.html

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>

3.  在引入thymeleaf后, 如果仍需要访问~/static/index.html, 则可以使用重定向 , 

return "redirect:/index.html"
代码样例:

  

  import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    
    @Controller
    public class HomeCtrl {
    
        @GetMapping("/")
        public String homePage(Model model, HttpServletRequest request, HttpServletResponse response) throws IOException {
            return "/index";
        }
    
        @RequestMapping("/static")
        public String navigatorToStatic() {
            return "redirect:/static.html";
        }


    

<!DOCTYPE html>
    <html>
    <head>
        <script src="webjars/jquery/3.1.1/jquery.min.js"></script>
        <script src="webjars/bootstrap/3.3.7/js/bootstrap.min.js"></script>
        <link rel="stylesheet" href="webjars/bootstrap/3.3.7/css/bootstrap.min.css" />
    </head>
    <body>
    <div class="container"><br/>
        <div class="alert alert-success">
            Hello, <strong>BootStarp & WebJars!</strong>
        </div>
    </div>
    </body>
    </html>

在web开发中,静态资源的访问是必不可少的,如:图片、js、css 等资源的访问。

spring Boot 对静态资源访问提供了很好的支持,基本使用默认配置就能满足开发需求。

一、默认静态资源映射

Spring Boot 对静态资源映射提供了默认配置

Spring Boot 默认将 /** 所有访问映射到以下目录:

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

如:在resources目录下新建 public、resources、static 三个目录,并分别放入 a.jpg b.jpg c.jpg 图片

目录

浏览器分别访问:

http://localhost:8080/a.jpg
http://localhost:8080/b.jpg
http://localhost:8080/c.jpg

均能正常访问相应的图片资源。那么说明,Spring Boot 默认会挨个从 public resources static 里面找是否存在相应的资源,如果有则直接返回。

二、自定义静态资源映射

在实际开发中,可能需要自定义静态资源访问路径,那么可以继承WebMvcConfigurerAdapter来实现。

第一种方式:静态资源配置类

package com.sam.demo.conf;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

/**
 * 配置静态资源映射
 * @author sam
 * @since 2017/7/16
 */
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        //将所有/static/** 访问都映射到classpath:/static/ 目录下
        registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
    }
}

重启项目,访问:http://localhost:8080/static/c.jpg 能正常访问static目录下的c.jpg图片资源。

第二种方式:在application.properties配置

在application.properties中添加配置:

spring.mvc.static-path-pattern=/static/**

重启项目,访问:http://localhost:8080/static/c.jpg 同样能正常访问static目录下的c.jpg图片资源。

注意:通过spring.mvc.static-path-pattern这种方式配置,会使Spring Boot的默认配置失效,也就是说,/public /resources 等默认配置不能使用。

配置中配置了静态模式为/static/,就只能通过/static/来访问。

理论说明:

当前,Spring毫无疑问已经成为java后台对象管理标准框架,除了通过IOC能够管理我们的自定义对象的生命周期之外还提供了众多功能繁复的可配置功能模块。但同时带来了复杂的配置项,这对初学者而言简直是一种灾难。于是SpringBoot应运而生,Springboot的出现大大简化了配置,主要表现在消除了web.xml和依赖注入配置的整合,处处遵循规约大于配置的思想,将初学者在繁杂的配置项中解放出来,专注于业务的实现,而不需要去关注太底层的实现。当然,也可以自己手动添加Web.xml,因为对于高端玩家而言,很多时候配置项还是很有必要的。这篇博客不涉及具体的技术细节,只是从一个开发者的角度梳理下我的使用模式。

springboot提供了一套完整的web开发流程。前端到后台,再到数据库一条龙。使用spring开发一个web工程有两条路线:

1-前后端完全分离

这种方式前端开发和后端开发完全分离,只需要协商好接口就行,前端负责开发页面并调用后端接口展示数据。后端只负责提供rest接口;

2-使用springboot自带的模板

springboot支持多种主流后端模板:

· Thymeleaf
· FreeMarker
· Velocity
· Groovy
· Mustache
· JSP
需要注意的是,虽然Spring MVC支持JSP,但是Spring Boot不建议使用JSP,因为在使用嵌入式servlet容器时,有一些使用限制。2010年后Velocity停止更新,所以这两个都不建议使用。以上几个模板springboot可以同时支持,什么叫同时支持?简而言之,springboot项目中可以同时共存多个模板,需要做的仅仅是在pom文件中进入相关模板引擎的jar包就可以了,springboot根据模板的后缀名来决定由哪种模板引擎来解析这个动态页面。

    • Thymeleaf : .html
    • freemaker : .ftl
    • jsp : jsp

        所以一个页面的控制器的实现方式可能如下所示:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

@Controller //标示为controller层

public class FreeMarkerIndexController {

  @RequestMapping("/freemarkerindexController")//请求路径,会去templates下去寻找freemarkerindex

  public String freemarkerindexController(Map<String, Object> result) {

    System.out.println("hello world");//在控制台输出打印hello world

    result.put("name""wangwu");//添加姓名

    result.put("sex", 1);//添加性别

    List<String> list = new ArrayList<String>();//创建一个无序集合

    list.add("zhangsan");//添加张三

    list.add("lisi");//添加李四

    result.put("userlist", list);//添加结果

    return "freemarkerindex";//返回templates的结果

  }

}

  该请求用来处理类似于:http://localhost:8080/freemarkerindex请求,但是相应的页面模板可以随便使用,例如你想使用jsp解析这个名为freemarkerindex这个模板,那么就在resources/templates目录下创建名为freemarkerindex.jsp的模板文件就可以了,springboot会根据controller找到请求要返回的模板文件,然后在templates目录下找到相应的模板文件,并且根据后缀名来判断使用哪一种模板引擎来即系这个模板文件,最终将解析完成之后的模板文件返回(实际上,解析完成的模板文件已经是一个纯html静态页面了)。

注意这些模板都是后端模板,有别于前端模板(如angular)。

前端模板:前端模板通常是通过模板提供的js根据模板规定的语法规则解析html中的模板标记;

后端模板:类似于前端,一个页面请求到达之后,后端模板引擎根据特定的语法规则解析模板中的内容,将数据填充到模板中,最终返回给浏览器的实际上已经是一个完整的html页面了。

用IDE创建的Springboot web工程可能如图做所示:

      

会发现,springboot的工程中并没有传统java web项目中的WEB-INF目录以及下面的web.xml文件,这让人一头雾水,以前做java web无论使用什么框架还没见过不写web.xml的。

那么某些情况下可能有必须使用web.xml这种场景,例如tomcat版本兼容性问题,有些版本的tomcat并不支持springboot开发的web应用,或者之前老项目想要迁移到springboot上来,完全摒弃web.xml可能不太现实。那么如何在springboot中使用原来的web.xml方式来配置servlet呢?

1-首先先在java/webapp/WEB-INF/下面加入web.xml

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

<?xml version="1.0" encoding="UTF-8"?> 

<web-app xmlns="http://java.sun.com/xml/ns/javaee" 

         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 

         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 

                      http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" 

         version="2.5"

    <context-param> 

        <param-name>contextConfigLocation</param-name> 

        <param-value>com.robbie.SpringBootTraditionalApplication</param-value> 

    </context-param> 

    <listener> 

        <listener-class>org.springframework.boot.legacy.context.web.SpringBootContextLoaderListener</listener-class

    </listener> 

    <servlet> 

        <servlet-name>appServlet</servlet-name> 

        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class

        <init-param> 

            <param-name>contextAttribute</param-name> 

            <param-value>org.springframework.web.context.WebApplicationContext.ROOT</param-value> 

        </init-param> 

        <load-on-startup>1</load-on-startup> 

    </servlet> 

    <servlet-mapping> 

        <servlet-name>appServlet</servlet-name> 

        <url-pattern>/</url-pattern> 

    </servlet-mapping> 

</web-app> 

2-将代码中有关Servlet的所有配置全部去掉

例如SpringBootServletInitializer来初始化Servlet,也不能用FilterRegistrationBean和ServletRegistrationBean注册Filter和Servlet,统统迁移到web.xml中的。

3-编写前端页面/模板

Springboot默认的静态资源路径和模板页面路径并不是传统的WEB-INF同目录下。而是resource/static和resource/template下面。下面是springboot默认的页面路径和传统的java web页面路径:

静态web页面请求可能为:http://localhost:8080/example/index.html

动态web页面请求可能为:http://localhost:8080/example/jsp/index.jsp

无论是基于springboot框架的web工程还是传统的使用servlet的web工程请求的方式其实没有什么本质区别,区别在于这两种方式中静态文件和动态文件存放在位置不同:

基于Springboot:静态资源放在resource/static目录下;动态资源放啊在resource/templates目录下;

不基于springboot框架:静态资源和动态资源存放目录结构的组织有自己决定,并没有强制要求必须放在那个目录下面。通常将静态资源放在和WEB-INF同目录下

个人觉得,既然已经选择使用springboot,那就入乡随俗,尽量使用springboot里面规约使用方式,不要生硬的搞出一些很别扭的东西出来。发散的有点远了,回到文章刚开始提到的两种web开发思想:前后盾完全分离和使用模板开发;这里主要介绍下前后端分离这种方式的开发。

1-前后端分离开发

使用这种方式开发web项目,后端全部开发成rest API,前端交给专业的前端开发工程师去开发,后端和前端之前完全解耦,前端工程师可以根据自己的喜好选择前端开发框架,例如angular、react、vue等。

静态资源存放路径:src\main\resources\static\index.html

静态资源访问路径:http://localhost:8080/index.html

js、css、图片等静态资源的访问方式阈值类似;

动态请求全部按照restAPI的方式进行进行响应。

2-使用模板开发

@RequestMapping(value="/")
public String defaultHandler(){
    return "thymeleaf";
}

这个例子的是意思是对于所有的请求都将会返回名为thymeleaf的模板文件。  

2. 预备知识

2.1 Servlet 3

我们可以先来看一下 jquery webjar 的包结构:

jquery-3.1.0.jar
    └─ META-INF
        └─ resources
            └─ webjars
                └─ jquery
                    └─ 3.1.0
                        └─ jquery.js

拿 Servlet 3 举例,应用打成 war 后,Jar(包括 WebJars)会被放在 WEB-INF/lib 目录下,而 Servlet 3 允许直接访问 WEB-INF/lib 下 jar 中的 /META-INF/resources 目录下的资源。简单来说就是 WEB-INF/lib/{\*.jar}/META-INF/resources下的资源可以被直接访问。

图片

所以对于 Servlet 3,直接使用 http://localhost:8080/webjars/jquery/3.1.0/jquery.js 即可访问到 webjar 中的 jquery.js,而不用做其它的配置。

那么如何在 Spring MVC 中访问 webjars 呢?或者说,Spring MVC 如何处理静态资源?

2.2 Spring MVC

Spring MVC 的入口是 DispatcherServlet,所有的请求都会汇集于该类,而后分发给不同的处理类。如果不做额外的配置,是无法访问静态资源的。

图片

如果想让 Dispatcher Servlet 直接可以访问到静态资源,最简单的方法当然是交给默认的 Servlet。

图片

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }
}

这种情况下 Spring MVC 对资源的处理与 Servlet 方式相同。

3. 基础

我们可以通过很简单的配置使得 Spring MVC 有能力处理对静态资源进行处理。

在 Spring MVC 中,资源的查找、处理使用的是责任链设计模式(Filter Chain):

图片

其思路为如果当前 resolver 找不到资源,则转交给下一个 resolver 处理。 当前 resolver 找到资源则立即返回给上级 resovler(如果存在),此时上级 resolver 又可以选择对资源进一步处理或再次返回给它的上级(如果存在)。

配置方法为重写 WebMvcConfigurerAdapter 类的 addResourceHandlers。

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
    @Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("/webjars/**")
                .addResourceLocations(
                        "classpath:/META-INF/resources/webjars/");
}

通过这样的配置,就成功添加了一个 PathResourceResolver

图片

该 resolver 的作用是将 url 为 /webjars/** 的请求映射到 classpath:/META-INF/resources/webjars/

比如请求 http://localhost:8080/webjars/jquery/3.1.0/jquery.js 时, Spring MVC 会查找路径为 classpath:/META-INF/resources/webjars/jquery/3.1.0/jquery.js 的资源文件。

4. 进阶

4.1 为静态资源添加版本号

为了简单起见,我们假设静态资源存放在 classpath:/static,且映射的 url 为 /static

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {

    // 映射 /static 的请求到 classpath 下的 static 目录

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

比如,请求 /static/style.css, 则会直接查找 classpath:/static/style.css

我们刚才说到,这段代码实际上是添加了一个 PathResourceResolver,来完成对资源的查找,那么我们是不是可以继续向 Resolver Chain 添加更多的 Resource Resolver,从而实现对静态资源更多样化的处理呢?

答案是肯定的,接下来,我们添加 VersionResourceResolver。

图片

VersionResourceResolver 可以为资源添加版本号。其所作的工作如下:首先使用下一个 resolver 获取资源,如果找到资源则返回,不做其它处理;如果 下一个 resolver 找不到资源,则尝试去掉 url 中的 version 信息,重新调用下一个 resolver 处理,然后无论下一个 resolver 能否处理,都返回其结果。

版本号的策略有两种,下面分别阐述。

4.1.1 指定版本号

指定固定值作为版本号,比如:

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
   registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static")
           // resourceChain(false) 的作用后面会讲解
           .resourceChain(false)
           // 添加 VersionResourceResolver,且指定版本号
           .addResolver(new VersionResourceResolver()
               .addFixedVersionStrategy("1.0.0", "/**"));
}

这样,在请求资源时,加上 /1.0.0 前缀,即 http://localhost:8080/static/1.0.0/style.css 也可正确访问。

VersionResourceResolver 在处理该请求时,首先使用 PathResourceResolver 按照配置的映射关系 "/static/**" => "classpath:/static" 处理,即查找文件 classpath:/static/1.0.0/style.css。由于该文件不存在,VersionResourceResolver 尝试去掉版本号 1.0.0,然后再次查找 classpath:/static/style.css,找到文件,直接返回。

4.1.2 使用 MD5 作为版本号

除了指定版本号,也可以使用资源的 MD5 作为其版本号,配置方法为:

@Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/static/**")
                .addResourceLocations("classpath:/static/")
                .resourceChain(false)
                .addResolver(new VersionResourceResolver()
                    .addContentVersionStrategy("/**"));
    }

这样,请求资源时,加上资源的 md5,即 http://localhost:8080/static/style-dfbe630979d120fe54a50593f2621225.css 也可正确访问。

由于使用资源的 MD5 作为版本号,是 VersionResourceResolver 的其中一种策略,因此与指定版本号的处理方式相同,不再阐述。

4.2 gzip 压缩

很多时候,为了降低传输的数据量,可以对资源进行压缩。比如可以将 style.css 压缩成 style.css.gz,但是如何让 Spring MVC 在处理对 style.css 的请求时能正确返回 style.css.gz 呢?

为了解决这个问题,我们可以继续添加一个 Resource Resolver —— GzipResourceResolver。

图片

GzipResourceResolver 用来查找资源的压缩版本,它首先使用下一个 Resource Resolver 查找资源,如果可以找到,则再尝试查找该资源的 gzip 版本。如果存在 gzip 版本则返回 gzip 版本的资源,否则返回非 gzip 版本的资源。

比如对于如下的资源:

static
    └─ style.css
    └─ style.css.gz (使用 gzip 压缩)

在请求 /static/style.css 时,会先使用 PathResourceResolver 查找 style.css,找到后则再次查找 style.css.gz。这里该文件是存在的,因此会返回 style.css.gz 的内容。

PS: 请求头中的 Content-Encoding 要包含 gzip

配置 GzipResourceResolver 很简单:

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
   registry.addResourceHandler("/static/**")
           .addResourceLocations("classpath:/static/")
           .resourceChain(false)
           .addResolver(new GzipResourceResolver())
           .addResolver(new VersionResourceResolver().addContentVersionStrategy("/**"));
           
}

4.3 chain cache

从上面的情况可以看出,Spring MVC 会对资源进行较多的处理。如果每一次请求都做这些处理,无疑会降低服务器的性能。为了避免这种情况,这时可以添加 CachingResourceResolver 来解决这种问题。

图片

CachingResourceResolver 用于缓存其它 Resource Resolver 查找到的资源。因此 CachingResourceResolver 会被放在最外层。请求先到达 CachingResourceResolver,尝试在缓存中查找,如果找到,则直接返回,如果找不到,则依次调用后面的 resolver,直到有一个 resolver 能够找到资源,CachingResourceResolver 将找到的资源缓存起来,下次请求同样的资源时,就可以从缓存中取了。

可能有人会担心缓存资源会占用太多的内存。但实际上并没有资源内容,仅仅是对资源的路径(或者说资源的抽象)进行了缓存。

开启缓存的方法很简单:

.requestChain(true)

前面的例子中都选择关闭 chain cache,原因是缓存的存在会增加调试的难度。因此开发时可以考虑关闭该功能。

4.4 省略 webjar 版本

AbstractResourceResolver 的子类一共有 5 个,我们已经提到了 4 个。最后一个是 WebJarsResourceResolver。

图片

WebJarsResourceResolver 并不需要手动添加。WebJarsResourceResolver 依赖了 webjars-locator 包,因此当添加了 webjars-locator 依赖时,Spring MVC 会自动添加 WebJarsResourceResolver。

<dependency>
    <groupId>org.webjars</groupId>
    <artifactId>webjars-locator</artifactId>
    <version>0.32</version>
</dependency>

WebJarsResourceResolver 的作用是可以省略 webjar 的版本。比如对于请求 http://localhost:8080/webjars/jquery/3.1.0/jquery.js 省略版本号 3.1.10 直接使用 http://localhost:8080/webjars/jquery/jquery.js 也可访问。

至此所有 Spring MVC 提供的 ResourceResolver 都讲完了。Spring MVC 提供的这 4 个 ResourceResolver 基本够用,如果不能满足业务需求,也可以自定义 ResourceResolver 来满足需求。

4.5 Transformer

实际上,除了 ResourceResolver,Spring MVC 还支持修改资源内容,即 Resource Transformer。

图片

可用的 Resource Transformer 有以下几个:

图片

他们的功能依次为:

  • AppCacheManifestTransformer: 帮助处理 HTML5 离线应用的 AppCache 清单内的文件
  • CachingResourceTransformer: 缓存其它 transfomer 的结果,作用同 CachingResourceResolver
  • CssLinkResourceTransformer: 处理 css 文件中的链接,为其加上版本号
  • ResourceTransformerSupport: 抽象类,自定义 transfomer 时继承

我们拿 CssLinkResourceTransformer 举例。 它会将 css 文件中的 @import 或 url() 函数中的资源路径自动转换为包含版本号的路径。

配置方法为:

registry.addResourceHandler("/static/**")
                .addResourceLocations("classpath:/static/")
                .resourceChain(false)
                .addResolver(new VersionResourceResolver().addContentVersionStrategy("/**"))
                .addTransformer(new CssLinkResourceTransformer());

当我们在 style.css 中通过 @import "style-other.css"; 导入了另一个 css 文件,则 transformer 会自动将该 style.css 内部的 css 文件路径地址转换为: @import "style-other-d41d8cd98f00b204e9800998ecf8427e.css"

4.6 Http 缓存

为了避免客户端重复获取资源,HTTP/1.1 规范中定义了 Cache-Control 头。几乎所有浏览器都实现了支持 Cache-Control

配置方法如下:

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
   registry.addResourceHandler("/static/**")
           .addResourceLocations("classpath:/static/")
           .setCacheControl(CacheControl
                   .maxAge(10, TimeUnit.MINUTES)
                   .cachePrivate());
}

当请求 /static/style.css 时,返回的头信息中会多两条信息:

Cache-Control:max-age=600, private
Last-Modified:Sun, 04 Oct 2016 15:08:22 GMT

浏览器会将该信息连同资源储存起来,当再次请求该资源时,会取出 Last-Modified 并添加到在请求头 If-Modified-Since 中:

If-Modified-Since:Sun, 04 Oct 2016 15:08:22 GMT

Spring MVC 在收到请求,发现存在 If-Modified-Since,会提取出来该值,并与资源的修改时间比较,如果发现没有改变,则仅仅返回状态码 304,无需传递资源内容。浏览器收到状态码 304,明白资源从上次请求到现在未被改变,http 缓存依旧可用。

http 缓存的更多用法参见 这里

5. 使用 Spring Boot 配置

众所周知,使用 Spring MVC 搭建 Web 服务,不仅要编写不少的代码或 XML 配置,如果开发人员使用不同的 IDE,还要配置这些 IDE 使其得以被正确运行。

为了解决这些问题,spring.io 平台提供了 Spring Boot。Spring Boot 采用 约定优于配置 的理念,在整合已有的 Spring 组件的同时,提供了大量的默认配置。得益于这些默认配置,使用 Spring Boot,只需要编写一个 pom.xml,再加上一个 java 类,就可以跑起来一个 web 服务,如果使用 groovy,一个类文件就能跑起来 web 服务。正是由于 spring boot 带来的这种便捷的特性,被广泛应用在微服务的场景中。

现在,Spring Boot 已经非常成熟了,最好的教程当然是官方文档

项目的创建可以为普通 maven 项目,当然还可以使用 spring.io 提供的 在线创建 Spring Boot 项目 的服务创建简项目或者。当然,也可以查看本文的示例代码。

强烈推荐 看下 WebMvcAutoConfiguration 这个类,它为 Spring Boot 提供了大量的 Web 服务的默认配置。这些配置包括但不局限于:设置了主页、webjars配置、静态资源位置等。这些配置对于我们使用配置 Web 服务很有借鉴意义。

ps: 想要使用默认配置,无需使用 @EnaleWebMvc 注解。使用了 @EnableWebMvc 注解后 WebMvcAutoConfiguration 提供的默认配置会失效,必须提供全部配置。

最后,我们使用 spring boot 提供的编写配置文件的方式,实现上面使用代码才能完成的功能。

# application.properties

# 设置静态资源的存放地址
spring.resources.static-locations=classpath:/resources 

# 开启 chain cache
spring.resources.chain.cache=true

# 开启 gzip
spring.resources.chain.gzipped=true

# 指定版本号
spring.resources.chain.strategy.fixed.enabled=true
spring.resources.chain.strategy.fixed.paths=/static  
spring.resources.chain.strategy.fixed.version=1.0.0

# 使用 MD5 作为版本号
spring.resources.chain.strategy.content.enable=true
spring.resources.chain.strategy.content.paths=/**

# http 缓存过期时间
spring.resources.cachePeriod=60 

最后介绍一下如何查看这些配置的技巧:

通过查看 ResourceProperties 这个类可以看到,该类顶部有一个注解 @ConfigurationProperties(prefix = "spring.resources", ignoreUnknownFields = false)

ConfigurationProperties 是用来注入值的,prefix = "spring.resources" 表示前缀。比如我们配置文件中的 spring.resources.static-locations=classpath:/resources 这个配置,去掉 spring.resources 这个前缀,剩下的为 static-locations ,则它的值 classpath:/resources 会被注入到 ConfigurationProperties 类的 staticLocations 成员变量中。通过这种方法,我们就能通过编写配置文件改变类的状态而无需编写代码。当然,如何使用这些配置的关键还是要知道这些成员变量的作用。

6. 总结

本文从一个新的技术点 webjars 出发,探讨了 Spring MVC 对静态资源的处理,紧接着又了解了 Spring Boot 的配置技巧。

示例代码:下载

7. 参考

https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching?hl=zh-cn#cache-control
http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#mvc-config-static-resources
http://qiita.com/kazuki43zoo/items/e12a72d4ac4de418ee37
http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-spring-mvc-static-content

猜你喜欢

转载自blog.csdn.net/ZYC88888/article/details/84317004