文档地址
静态资源目录及访问
(1)静态资源目录
By default, Spring Boot serves static content from a directory called /static (or /public or /resources or /META-INF/resources) in the classpath or from the root of the ServletContext. It uses the ResourceHttpRequestHandler from Spring MVC so that you can modify that behavior by adding your own WebMvcConfigurer and overriding the addResourceHandlers method.
大意:默认情况下,Spring Boot服务的静态内容来自类路径中的/static(或/public或/resources或/META-INF/resources)目录,或者来自ServletContext的根目录。它使用了来自Spring MVC的ResourceHttpRequestHandler,这样你就可以通过添加你自己的WebMvcConfigurer和覆盖addResourceHandlers方法来修改该行为。
By default, resources are mapped on /, but you can tune that with the spring.mvc.static-path-pattern property. For instance, relocating all resources to /resources/ can be achieved as follows:
大意:默认情况下,资源映射到/**上,但是你可以使用spring.mvc对其进行调优。static-path-pattern财产。例如,重新定位所有资源到/resources/**可以实现如下:
spring.mvc.static-path-pattern=/resources/**
By default, resources are mapped on /, but you can tune that with the spring.mvc.static-path-pattern property. For instance, relocating all resources to /resources/ can be achieved as follows:
大意:您还可以使用spring.resources自定义静态资源位置。Static-locations属性(用目录位置列表替换默认值)。根Servlet上下文路径“/”也会自动添加为一个位置。
注意:spring.mvc.static-locations 已过期,用下面这个。
spring:
web:
resources:
static-locations:
(2)访问
使用默认的静态资源访问规则:
访问
:只要资源放在上面对应的路径中,则 当前项目根路径/+静态资源名
原理:请求进来,先去找Controller看能不能处理。不能处理的所有请求又都交给静态资源处理器。如果静态资源也找不到,则报404.
如果自定义了静态资源的位置则:
访问路径:当前项目+ static-path-pattern+静态资源名称
在SpringBoot中的配置原理
WebMvcAutoConfiguration:
@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 {
WebMvcAutoConfigurationAdapter:
@Configuration(proxyBeanMethods = false)
@Import(EnableWebMvcConfiguration.class)
@EnableConfigurationProperties({ WebMvcProperties.class, WebProperties.class })
@Order(0)
public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer, ServletContextAware {
一共涉及到两个Properties类:
@ConfigurationProperties(prefix = "spring.mvc")
public class WebMvcProperties {
@ConfigurationProperties("spring.web")
public class WebProperties {
WebMvcAutoConfigurationAdapter 配置类中有一个构造函数如下:
//有参构造器的所有参数都会从容器中确定
// WebProperties
// WebMvcProperties 获取所有和spring.mvc绑定的所有的值的对象
// ListableBeanFactory beanFactory Spring的beanFactory
// ObjectProvider<HttpMessageConverters> messageConvertersProvider 找到所有的HttpMessageConverters
//ResourceHandlerRegistrationCustomizer 找到 资源处理器的自定义器
// dispatcherServletPath
// servletRegistrations
public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer, ServletContextAware {
private static final Log logger = LogFactory.getLog(WebMvcConfigurer.class);
private final Resources resourceProperties;
private final WebMvcProperties mvcProperties;
private final ListableBeanFactory beanFactory;
private final ObjectProvider<HttpMessageConverters> messageConvertersProvider;
private final ObjectProvider<DispatcherServletPath> dispatcherServletPath;
private final ObjectProvider<ServletRegistrationBean<?>> servletRegistrations;
private final WebMvcAutoConfiguration.ResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer;
private ServletContext servletContext;
public WebMvcAutoConfigurationAdapter(WebProperties webProperties, WebMvcProperties mvcProperties, ListableBeanFactory beanFactory, ObjectProvider<HttpMessageConverters> messageConvertersProvider, ObjectProvider<WebMvcAutoConfiguration.ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider, ObjectProvider<DispatcherServletPath> dispatcherServletPath, ObjectProvider<ServletRegistrationBean<?>> servletRegistrations) {
this.resourceProperties = webProperties.getResources();
this.mvcProperties = mvcProperties;
this.beanFactory = beanFactory;
this.messageConvertersProvider = messageConvertersProvider;
this.resourceHandlerRegistrationCustomizer = (WebMvcAutoConfiguration.ResourceHandlerRegistrationCustomizer)resourceHandlerRegistrationCustomizerProvider.getIfAvailable();
this.dispatcherServletPath = dispatcherServletPath;
this.servletRegistrations = servletRegistrations;
this.mvcProperties.checkConfiguration();
}
静态资源的默认处理规则:
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
} else {
this.addResourceHandler(registry, "/webjars/**", "classpath:/META-INF/resources/webjars/");
this.addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> {
registration.addResourceLocations(this.resourceProperties.getStaticLocations());
if (this.servletContext != null) {
ServletContextResource resource = new ServletContextResource(this.servletContext, "/");
registration.addResourceLocations(new Resource[]{resource});
}
});
}
}
有一个方法:
registration.addResourceLocations(this.resourceProperties.getStaticLocations());
找到一个私有的数组:就是内置的静态资源路径
public static class Resources {
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = new String[]{"classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/"};
private String[] staticLocations;