【Spring Boot 六】 静态资源处理
这篇文章本来不是很想写的,因为SpringBoot支持的静态资源处理感觉在实际开发中不会有太大的作用,因为SpringBoot做到的静态资源处理,Nginx可以做到,而且可以做得更好,因为SpringBoot支持这样的功能,所以谱写一下SpringBoot的静态资源处理吧。
spring Boot 默认为我们提供了静态资源处理,使用 WebMvcAutoConfiguration 中的配置各种属性。
建议大家使用Spring Boot的默认配置方式,如果需要特殊处理的再通过配置进行修改。
如果想要自己完全控制WebMVC,就需要在@Configuration注解的配置类上增加@EnableWebMvc(@SpringBootApplication 注解的程序入口类已经包含@Configuration),增加该注解以后WebMvcAutoConfiguration中配置就不会生效,你需要自己来配置需要的每一项。这种情况下的配置还是要多看一下WebMvcAutoConfiguration类。
我们既然是快速使用Spring Boot,并不想过多的自己再重新配置。本文还是主要针对Spring Boot的默认处理方式,部分配置在application 配置文件中(.properties 或 .yml)
默认资源映射
我们在启动应用的时候,可以在控制台中看到如下信息:
1 2 3 |
2017-08-24 08:43:27.633 INFO 8112 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] 2017-08-24 08:43:27.633 INFO 8112 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] 2017-08-24 08:43:27.664 INFO 8112 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] |
其中默认配置的 /** 映射到 /static (或/public、/resources、/META-INF/resources)
其中默认配置的 /webjars/** 映射到 classpath:/META-INF/resources/webjars/
PS:上面的 static、public、resources 等目录都在 classpath: 下面(如 src/main/resources/static;src/main/resources/META-INF/resources)。
如果我按如下结构存放相同名称的图片,那么Spring Boot 读取图片的优先级是怎样的呢?
当我们访问:http://localhost:8080/1.jpg 的时候,显示哪张图片?
优先级顺序为:META/resources > resources > static > public
自定义资源映射
上面我们介绍了Spring Boot 的默认资源映射,一般够用了,那我们如何自定义目录?
这些资源都是打包在jar包中的,然后实际应用中,我们还有很多资源是在管理系统中动态维护的,并不可能在程序包中,对于这种随意指定目录的资源,如何访问?
自定义目录
以增加 /myres/* 映射到 classpath:/myres/* 为例的代码处理为:
实现类继承 WebMvcConfigurerAdapter 并重写方法 addResourceHandlers (对于 WebMvcConfigurerAdapter 上篇介绍拦截器的文章中已经有提到)
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 41 42 43 44 45 46 47 48 49 50 51 52 |
package com.spring.boot.interceptor; 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; /** * MyWebAppConfigurer * Created by XJH on 2017/8/23. */ @Configuration public class MyWebAppConfigurer extends WebMvcConfigurerAdapter { /** * 拦截器链 * * @param registry InterceptorRegistry */ @Override public void addInterceptors(InterceptorRegistry registry) { // 多个拦截器组成一个拦截器链 // addPathPatterns 用于添加拦截规则 // excludePathPatterns 用户排除拦截 registry.addInterceptor(new MyInterceptor1()).addPathPatterns("/**"); registry.addInterceptor(new MyInterceptor2()).addPathPatterns("/**"); super.addInterceptors(registry); } /** * 静态资源 * * @param registry ResourceHandlerRegistry */ @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { // 自定义目录 registry.addResourceHandler("/myres/**").addResourceLocations("classpath:/myres/"); // 自定义目录 // 访问myres根目录下的fengjing.jpg 的URL为 http://localhost:8080/fengjing.jpg (/** 会覆盖系统默认的配置) // registry.addResourceHandler("/**").addResourceLocations("classpath:/myres/").addResourceLocations("classpath:/static/"); // 使用外部目录 // 可以直接使用addResourceLocations 指定磁盘绝对路径,同样可以配置多个位置,注意路径写法需要加上file: // registry.addResourceHandler("/myimgs/**").addResourceLocations("file:E:/myimgs/"); super.addResourceHandlers(registry); } } |
访问myres 文件夹中的fengjing.jpg 图片的地址为 http://localhost:8080/myres/1.jpg
这样使用代码的方式自定义目录映射,并不影响Spring Boot的默认映射,可以同时使用。
如果我们将/myres/* 修改为 /* 与默认的相同时,则会覆盖系统的配置,可以多次使用 addResourceLocations 添加目录,优先级先添加的高于后添加的。
其中 addResourceLocations 的参数是动参,可以这样写 addResourceLocations(“classpath:/img1/”, “classpath:/img2/”, “classpath:/img3/”);
使用外部目录
上面代码中已经提到,如果我们要指定一个绝对路径的文件夹(如 E:/myimgs/ ),则只需要使用 addResourceLocations 指定即可。
通过配置文件配置
上面是使用代码来定义静态资源的映射,其实Spring Boot也为我们提供了可以直接在 application.properties(或.yml)中配置的方法。
配置方法如下:
1 2 3 4 5 6 |
#静态资源处理 # 默认值为 /** spring.mvc.static-path-pattern= # 默认值为 classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/ #这里设置要指向的路径,多个使用英文逗号隔开, spring.resources.static-locations= |
使用 spring.mvc.static-path-pattern 可以重新定义pattern,如修改为 /myres/** ,则访问static 等目录下的1.jpg文件应该为 http://localhost:8080/myres/1.jpg ,修改之前为 http://localhost:8080/1.jpg
使用 spring.resources.static-locations 可以重新定义 pattern 所指向的路径,支持 classpath: 和 file: (上面已经做过说明)
注意 spring.mvc.static-path-pattern 只可以定义一个,目前不支持多个逗号分割的方式。
页面中使用
上面几个例子中也已经说明了怎么访问静态资源,其实在页面中使用不管是jsp还是freemarker,并没有什么特殊之处,也我们平时开发web项目一样即可。
使用webjars
先说一下什么是webjars?我们在Web开发中,前端页面中用了越来越多的js或CSS,如jQuery等等,平时我们是将这些Web资源拷贝到Java的目录下,这种通过人工方式拷贝可能会产生版本误差,拷贝版本错误,前端页面就无法正确展示。
WebJars 就是为了解决这种问题衍生的,将这些Web前端资源打包成Java的Jar包,然后借助Maven这些依赖库的管理,保证这些Web资源版本唯一性。
WebJars 就是将js, css 等资源文件放到 classpath:/META-INF/resources/webjars/ 中,然后打包成jar 发布到maven仓库中。
简单应用
以jquery为例,文件存放结构为:
1 2 3 4 |
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 |
Spring Boot 默认将 /webjars/** 映射到 classpath:/META-INF/resources/webjars/ ,结合我们上面讲到的访问资源的规则,便可以得知我们在JSP页面中引入jquery.js的方法为:
<script type="text/javascript" src="${pageContext.request.contextPath }/webjars/jquery/2.1.4/jquery.js"></script>
想实现这样,我们只需要在pom.xml 文件中添加jquery的webjars 依赖即可,如下:
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>2.1.4</version>
</dependency>
总结
有这么多方式来管理我们的资源文件,但是我们在实际的开发中基本用不上,这些静态文件根本不会放在服务器处理,一个文件从几k到几十K甚至几百K一两M,服务器带宽低一点的访问一个页面几秒钟甚至十几秒几分钟之久。
所以,在我们实际的开发中,我们将静态文件交给nginx处理,我们可以有静态文件服务器,图片服务器,视频服务器(举个例子:阿里云的OSS对象存储)等等,来进行负载均衡,从而减轻服务器的压力。
如果一定想用springboot的静态资源处理,那么我建议使用建webjars的方式,通过动态版本号(webjars-locator 的方式)来使用(因为第三方库在项目开发中变动频率很小,即便是变动也是版本号的修改)。
成功不是将来才有的,而是从决定去做的那一刻起,持续累积而成。
发表评论