SpringBoot的静态资源处理
测试
1、静态资源访问
官网说明如下:
默认情况下,Spring Boot 从 Classpath 中名为
/static
(或/public
或/resources
或/META-INF/resources
)的目录或ServletContext
的根目录中提供静态内容。它使用 Spring MVC 中的ResourceHttpRequestHandler
,因此您可以通过添加自己的WebMvcConfigurer
并覆盖addResourceHandlers
方法来修改该行为。在独立的 Web 应用程序中,还启用了容器中的默认 servlet,并将其用作后备,如果 Spring 决定不处理
ServletContext
的根,则从ServletContext
的根开始提供内容。在大多数情况下,这不会发生(除非您修改默认的 MVC 配置),因为 Spring 始终可以通过DispatcherServlet
处理请求。默认情况下,资源 Map 在
/**
上,但是您可以使用spring.mvc.static-path-pattern
属性对其进行调整。例如,将所有资源重定位到/resources/**
可以实现如下:spring.mvc.static-path-pattern=/resources/**
您还可以使用
spring.resources.static-locations
属性来自定义静态资源位置(用目录位置列表替换默认值)。根 Servlet 上下文路径"/"
也会自动添加为位置。除了前面提到的“标准”静态资源位置以外,还对Webjars content进行了特殊处理。如果 jar 文件以 Webjars 格式打包,则从 jar 文件提供带有
/webjars/**
路径的任何资源。如果您的应用程序打包为 jar,则不要使用
src/main/webapp
目录。尽管此目录是一个通用标准,但它仅在 war 打包中有效,并且在生成 jar 时,大多数构建工具都将其忽略。Spring Boot 还支持 Spring MVC 提供的高级资源处理功能,允许使用案例,例如缓存清除静态资源或对 Webjars 使用版本无关的 URL。
要对 Webjar 使用版本无关的 URL,请添加
webjars-locator-core
依赖项。然后声明您的 Webjar。以 jQuery 为例,在"/webjars/jquery/x.y.z/jquery.min.js"
中添加"/webjars/jquery/jquery.min.js"
结果。其中x.y.z
是 Webjar 版本。
进行测试:
静态资源目录
进行测试的时候,由于之前项目引入了手写的sarter,里面有个拦截器,对所有资源进行拦截,导致访问不到静态资源,需要方向。
由于静态资源默认的映射是/**
,为了方便拦截器放行,这里可以自定义。
spring:
mvc:
static-path-pattern: /res/**
官网也说明了,可以自定义静态资源路径
spring:
mvc:
static-path-pattern: /res/** ##这里是加的请求的路径
resources:
static-locations: [classpath:/test/] ## 这里是隐射的路径
注意,这里数组只写一个的话,会把其他几个路径覆盖掉。
webjar
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.5.1</version>
</dependency>
进行测试
http://localhost:8888/webjars/jquery/3.5.1/webjars-requirejs.js
2、欢迎页支持
-
静态资源路径下 index.html
-
- 可以配置静态资源路径
- 但是不可以配置静态资源的访问前缀。否则导致 index.html不能被默
要注释掉下面配置,因为在源码中,有了判断,不然不生效
#spring:
# mvc:
# static-path-pattern: /res/**
3、自定义 Favicon
favicon.ico 放在静态资源目录下即可。
源码
-
因为springboot自动配置的原因,引入了很多自动配置类,所以先找到入口WebMvcAutoConfiguration
-
查看这个配置类生效的前提条件,其中发现了 WebMvcConfigurationSupport.class.
@Configuration(proxyBeanMethods = false) @ConditionalOnWebApplication(type = Type.SERVLET) @ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class }) @ConditionalOnMissingBean(WebMvcConfigurationSupport.class) @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10) @AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class }) public class WebMvcAutoConfiguration {
如果自己全部接管mvc的,可以使用@EnableWebMvc这个注解,它其实会往IOC容器注入DelegatingWebMvcConfiguration,它继承了WebMvcConfigurationSupport。
-
都是在容器中找WebMvcAutoConfigurationAdapter这个类
//有参构造器所有参数的值都会从容器中确定 //ResourceProperties resourceProperties;获取和spring.resources绑定的所有的值的对象 //WebMvcProperties mvcProperties 获取和spring.mvc绑定的所有的值的对象 //ListableBeanFactory beanFactory Spring的beanFactory //HttpMessageConverters 找到所有的HttpMessageConverters //ResourceHandlerRegistrationCustomizer 找到 资源处理器的自定义器。========= //DispatcherServletPath //ServletRegistrationBean 给应用注册Servlet、Filter.... public WebMvcAutoConfigurationAdapter(WebProperties webProperties, WebMvcProperties mvcProperties, ListableBeanFactory beanFactory, ObjectProvider<HttpMessageConverters> messageConvertersProvider, ObjectProvider<ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider, ObjectProvider<DispatcherServletPath> dispatcherServletPath, ObjectProvider<ServletRegistrationBean<?>> servletRegistrations) { this.mvcProperties = mvcProperties; this.beanFactory = beanFactory; this.messageConvertersProvider = messageConvertersProvider; this.resourceHandlerRegistrationCustomizer = resourceHandlerRegistrationCustomizerProvider.getIfAvailable(); this.dispatcherServletPath = dispatcherServletPath; this.servletRegistrations = servletRegistrations; this.mvcProperties.checkConfiguration(); }
资源处理的默认规则
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
super.addResourceHandlers(registry);
//如果在yaml里面配置的false,则静态资源全部失效
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
return;
}
ServletContext servletContext = getServletContext();
//这里配置的就是webjars资源映射
addResourceHandler(registry, "/webjars/**", "classpath:/META-INF/resources/webjars/");
//这里配置的就是静态资源映射,这里可以看下面的图
addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> {
registration.addResourceLocations(this.resourceProperties.getStaticLocations());
if (servletContext != null) {
registration.addResourceLocations(new ServletContextResource(servletContext, SERVLET_LOCATION));
}
});
}
private void addResourceHandler(ResourceHandlerRegistry registry, String pattern, String... locations) {
addResourceHandler(registry, pattern, (registration) -> registration.addResourceLocations(locations));
}
private void addResourceHandler(ResourceHandlerRegistry registry, String pattern,
Consumer<ResourceHandlerRegistration> customizer) {
if (registry.hasMappingForPattern(pattern)) {
return;
}
ResourceHandlerRegistration registration = registry.addResourceHandler(pattern);
customizer.accept(registration);
registration.setCachePeriod(getSeconds(this.resourceProperties.getCache().getPeriod()));
registration.setCacheControl(this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl());
customizeResourceHandlerRegistration(registration);
}
注:如果请求的静态资源和请求的接口是同一个路径,则优先处理接口
3、欢迎页的处理规则
@Bean
public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext,
FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) {
WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping(
new TemplateAvailabilityProviders(applicationContext), applicationContext, getWelcomePage(),
this.mvcProperties.getStaticPathPattern());
welcomePageHandlerMapping.setInterceptors(getInterceptors(mvcConversionService, mvcResourceUrlProvider));
welcomePageHandlerMapping.setCorsConfigurations(getCorsConfigurations());
return welcomePageHandlerMapping;
}
WelcomePageHandlerMapping(TemplateAvailabilityProviders templateAvailabilityProviders,
ApplicationContext applicationContext, Resource welcomePage, String staticPathPattern) {
if (welcomePage != null && "/**".equals(staticPathPattern)) {
logger.info("Adding welcome page: " + welcomePage);
setRootViewName("forward:index.html");
}
else if (welcomeTemplateExists(templateAvailabilityProviders, applicationContext)) {
logger.info("Adding welcome page template: index");
setRootViewName("index");
}
}
注:如果这里配置了静态资源路径,会导致欢迎页失效,如果没有失效,则请重定向到Index.html