静态资源访问
静态资源访问
静态资源只要放到类路径下:/static
,/public
,/resources
,/MATE-INF/resources
目录下,我们访问静态资源的时候就不需要加路径,直接在默认的根目录就可以访问。
默认的访问策略:如果访问的路径Controller可以处理,那么就会使用Controller路径映射处理,没有的话就会使用访问路径在静态资源目录下查找有无对应的静态资源,如果依然没有,就会出现404错误。
默认情况下,资源映射在 上/**
,但您可以使用该spring.mvc.static-path-pattern
属性对其进行调整。
spring:
mvc:
static-path-pattern: /res/**
还可以使用该spring.web.resources.static-locations
属性自定义静态资源位置(将默认值替换为目录位置列表)。根 Servlet 上下文路径"/"
也会自动添加为位置。
spring:
web:
resources:
static-locations: [classpath:/haha/]
前面提到的“标准”静态资源位置之外,我们还可以使用Webjars来导入一些静态库,比如Jquery。
将Jquery依赖导入到pom.xml文件中
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.6.0</version>
</dependency>
然后可以通过静态路径访问该Jquery文件
为什么说默认情况下我们把静态文件放在上面四个目录SpringBoot就会把这些作为静态资源处理
我们可以通过源码查看得出结论:
public void setStaticLocations(String[] staticLocations) {
this.staticLocations = appendSlashIfNecessary(staticLocations);
this.customized = true;
}
欢迎页设置
- 在静态资源目录下建立一个index.html
- 使用Controller来建立index的访问映射
自定义 Favicon
将favicon.icon放置到静态资源目录下即可
静态资源配置原理
SpringBoot启动就会默认加载很多自动配置类,比如AopAutoConfiguration,SpringMVC的自动配置类是WebMvcAutoConfiguration,我们还需要根据该类的@Conditional条件注解,查看该类是否生效
@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 {
}
当我们容器中存在Servlet
,DispatcherServlet
,WebMvcConfigurer
类,没有WebMvcConfigurationSupport
类的时候生效。然后还定义的加载顺序,通过@AutoConfigureOrder
和@AutoConfigureAfter
来定义。通过查看该类,可以发现配置大量的组建
与静态资源有关的是一个静态内部类 WebMvcAutoConfigurationAdapter
的自动配置类
@Configuration(proxyBeanMethods = false)//这是一个配置类
@Import(EnableWebMvcConfiguration.class)//导入一个类
@EnableConfigurationProperties({ WebMvcProperties.class,
org.springframework.boot.autoconfigure.web.ResourceProperties.class, WebProperties.class })//加载Properties属性类文件
@Order(0)
public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer, ServletContextAware {
}
WebMvcProperties
与配置文件中的spring.mvc
绑定
ResourceProperties
与配置文件中的spring.resources
绑定
WebProperties
与配置文件中的spring.web
绑定
这个静态内部类只有一个构造器
public WebMvcAutoConfigurationAdapter(
//获取和spring.resources绑定的所有的值的对象
org.springframework.boot.autoconfigure.web.ResourceProperties resourceProperties,
//获取和spring.web绑定的所有的值的对象
WebProperties webProperties,
//获取和spring.mvc绑定的所有值和对象
WebMvcProperties mvcProperties,
//Spring的对象工厂
ListableBeanFactory beanFactory,
//找到所有的HttpMessageConverters
ObjectProvider<HttpMessageConverters> messageConvertersProvider,
//找到资源处理器的自定义器
ObjectProvider<ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider,
//dispatcherServletPath
ObjectProvider<DispatcherServletPath> dispatcherServletPath,
//ServletRegistrationBean给应用注册Servlet、Filter等
ObjectProvider<ServletRegistrationBean<?>> servletRegistrations) {
this.resourceProperties = resourceProperties.hasBeenCustomized() ? resourceProperties
: webProperties.getResources();
this.mvcProperties = mvcProperties;
this.beanFactory = beanFactory;
this.messageConvertersProvider = messageConvertersProvider;
this.resourceHandlerRegistrationCustomizer = resourceHandlerRegistrationCustomizerProvider.getIfAvailable();
this.dispatcherServletPath = dispatcherServletPath;
this.servletRegistrations = servletRegistrations;
this.mvcProperties.checkConfiguration();
}
所有的参数都会从容器中获取。
资源的默认处理规则
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
return;
}
addResourceHandler(registry, "/webjars/**", "classpath:/META-INF/resources/webjars/");
addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> {
registration.addResourceLocations(this.resourceProperties.getStaticLocations());
if (this.servletContext != null) {
ServletContextResource resource = new ServletContextResource(this.servletContext, SERVLET_LOCATION);
registration.addResourceLocations(resource);
}
});
}
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());
registration.setUseLastModified(this.resourceProperties.getCache().isUseLastModified());
customizeResourceHandlerRegistration(registration);
}
第一步,静态资源是否启用
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
return;
}
是否启用静态资源规则,我们可以通过属性设置,在WebProperties中设置,默认是true,可以在配置文件中进行设置不启用。
spring:
web:
resources:
add-mappings: false
第二步Webjars有关设置
addResourceHandler(registry, "/webjars/**", "classpath:/META-INF/resources/webjars/");
里面设置了Webjars默认的访问路径classpath:/META-INF/resources/webjars/
第三步设置默认的静态资源设置
addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> {
registration.addResourceLocations(this.resourceProperties.getStaticLocations());
if (this.servletContext != null) {
ServletContextResource resource = new ServletContextResource(this.servletContext, SERVLET_LOCATION);
registration.addResourceLocations(resource);
}
});
首选加载路径,默认情况下是这四个路径:
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = { "classpath:/META-INF/resources/",
"classpath:/resources/", "classpath:/static/", "classpath:/public/" };
在2.6.7版本中,有一个变化就是对addResourceHandler
进行了重载
private void addResourceHandler(ResourceHandlerRegistry registry, String pattern, String... locations) {
addResourceHandler(registry, pattern, (registration) -> registration.addResourceLocations(locations));
}
//会进行缓存有关设置,默认单位是s
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());
registration.setUseLastModified(this.resourceProperties.getCache().isUseLastModified());
customizeResourceHandlerRegistration(registration);
}
//缓存单位
@DurationUnit(ChronoUnit.SECONDS)
private Duration period;
spring:
web:
resources:
cache:
period: 1000
对资源进行访问的时候可以看到有关缓存的情况
欢迎页的处理规则
@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");
}
//否则通过Controller处理
else if (welcomeTemplateExists(templateAvailabilityProviders, applicationContext)) {
logger.info("Adding welcome page template: index");
//视图访问
setRootViewName("index");
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?