以前写项目,静态资源一般都是放在webapp文件夹下,使用spring initializer创建的项目根本没有webapp文件夹,但spring boot有自己的映射规则。且看分析。
一、之前所说的配置文件访问路径
- 规则1:之前说配置文件可以放置的位置:"classpath:/META-INF/resources/",
"classpath:/resources/",
"classpath:/static/",
"classpath:/public/"。
来源自类ResourceProperties自身的一个final属性。
// 所以当前spring.resources前缀的配置可以设定与静态资源相关的参数,比如缓存时间什么的!
@ConfigurationProperties(
prefix = "spring.resources",
ignoreUnknownFields = false
)
public class ResourceProperties {
private static final String[] CLASSPATH_RESOURCE_LOCATIONS
= new String[]{"classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/"};
}
二、另外
在spring boot的spring mvc中,相关配置都在WebMvcAutoConfiguration类里面,这也就是我们之前提到过的类自动装载类。
他有一个addResourceHandler即资源处理方法。
@Configuration
@ConditionalOnWebApplication(
type = Type.SERVLET
)
@ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class})
@ConditionalOnMissingBean({WebMvcConfigurationSupport.class})
@AutoConfigureOrder(-2147483638)
@AutoConfigureAfter({DispatcherServletAutoConfiguration.class,
TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class})
public class WebMvcAutoConfiguration {
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
} else {
Duration cachePeriod = this.resourceProperties.getCache().getPeriod();
CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();
if (!registry.hasMappingForPattern("/webjars/**")) {
this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{"/webjars/**"})
.addResourceLocations(new String[]{"classpath:/META-INF/resources/webjars/"})
.setCachePeriod(this
.getSeconds(cachePeriod)).setCacheControl(cacheControl));
}
String staticPathPattern = this.mvcProperties.getStaticPathPattern();
if (!registry.hasMappingForPattern(staticPathPattern)) {
this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{staticPathPattern})
.addResourceLocations(getResourceLocations(this.resourceProperties.getStaticLocations()))
.setCachePeriod(this.getSeconds(cachePeriod))
.setCacheControl(cacheControl));
}
}
}
}
- 规则2:所有
webjars/**
都去classpath:/META-INF/resources/webjars/
路径找资源。
if (!registry.hasMappingForPattern("/webjars/**")) {
this.customizeResourceHandlerRegistration(
registry
.addResourceHandler(new String[]{"/webjars/**"})
.addResourceLocations(new String[]{"classpath:/META-INF/resources/webjars/"})
.setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl)
);
}
那么何为webjars?即以jar包的方式导入静态文件。可以试试google webjars,可以进入网站https://www.webjars.org/导包。比如我已经导入的jquery包
org.webjars
jquery
3.4.1
可以看到引入的webjars:
启动spring boot直接访问localhost:8080/webjars/jquery/3.4.1/jquery.js就可以访问到这个js文件。
方法的源码向下看
String staticPathPattern = this.mvcProperties.getStaticPathPattern();
if (!registry.hasMappingForPattern(staticPathPattern)) {
this.customizeResourceHandlerRegistration(
registry.addResourceHandler(new String[]{staticPathPattern})
.addResourceLocations(getResourceLocations(this.resourceProperties.getStaticLocations()))
.setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl));
}
上述源码可以看出
staticPathPattern
与getResourceLocations(this.resourceProperties.getStaticLocations())
是映射的。
那么两者的默认值是什么呢?
ctrl点进去:可以看到this表示的WebMvcProperties类中的无参构造函数中this.staticPathPattern = "/**";
。所以其对应/**。
同样ctrl点击后面的获取路径的方法:同样来到ResourceProperties类中。
public class ResourceProperties {
private static final String[] CLASSPATH_RESOURCE_LOCATIONS
= new String[]{"classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/"};
private String[] staticLocations;
public ResourceProperties() {
this.staticLocations = CLASSPATH_RESOURCE_LOCATIONS;
this.addMappings = true;
this.chain = new ResourceProperties.Chain();
this.cache = new ResourceProperties.Cache();
}
}
其默认构造函数将CLASSPATH_RESOURCE_LOCATIONS赋予staticLocations。所以没有特殊配置,其默认值和第final属性是一样的!
- 规则3:/**映射{"classpath:/META-INF/resources/",
"classpath:/resources/",
"classpath:/static/",
"classpath:/public/"}
我已经在项目文件夹下创建了对应的文件夹!
三、欢迎页面
同样在WebMvcAutoConfiguration类里面的方法
public class WebMvcAutoConfiguration {
private Optional getWelcomePage() {
String[] locations = getResourceLocations(this.resourceProperties.getStaticLocations());
return Arrays.stream(locations).map(this::getIndexHtml).filter(this::isReadable).findFirst();
}
private Resource getIndexHtml(String location) {
return this.resourceLoader.getResource(location + "index.html");
}
}
其中this.resourceProperties.getStaticLocations()获取的还是ResourceProperties类中的那个final属性中的路径,然后后面使用java 1.8中的流遍历将对应的路径和index.html结合获取首页地址。所以我们可以试试数组中的随便一份路径的文件夹下面创建一个index.html。
然后直接访问localhost:8080就可以访问到欢迎页面了!我已在public文件夹下面创建。
四、页面图标
在WebMvcAutoConfiguration类的最后有一个静态内部类叫做FaviconConfiguration用来配置页面图标的。
道理和前面差不多,不讲了。想要更换页面图标,只要将一个favicon.ico文件移到上述final属性所有的文件夹之一即可!