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 版本。

进行测试:

静态资源目录

image-20210309222539476

进行测试的时候,由于之前项目引入了手写的sarter,里面有个拦截器,对所有资源进行拦截,导致访问不到静态资源,需要方向。

image-20210309222653020

由于静态资源默认的映射是/**,为了方便拦截器放行,这里可以自定义。

spring:
  mvc:
    static-path-pattern: /res/**
image-20210309222908415

官网也说明了,可以自定义静态资源路径

spring:
  mvc:
    static-path-pattern: /res/**   ##这里是加的请求的路径
  resources:
    static-locations: [classpath:/test/]  ## 这里是隐射的路径
image-20210309223917217

注意,这里数组只写一个的话,会把其他几个路径覆盖掉。

webjar

      <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>jquery</artifactId>
            <version>3.5.1</version>
        </dependency>

image-20210309224235934

进行测试

http://localhost:8888/webjars/jquery/3.5.1/webjars-requirejs.js

2、欢迎页支持

  • 静态资源路径下 index.html

    • 可以配置静态资源路径
    • 但是不可以配置静态资源的访问前缀。否则导致 index.html不能被默

image-20210309225953756

要注释掉下面配置,因为在源码中,有了判断,不然不生效

#spring:
#  mvc:
#    static-path-pattern: /res/**

3、自定义 Favicon

favicon.ico 放在静态资源目录下即可。

image-20210310133507481

源码

  • 因为springboot自动配置的原因,引入了很多自动配置类,所以先找到入口WebMvcAutoConfigurationimage-20210309233224925

  • 查看这个配置类生效的前提条件,其中发现了 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);
		}

image-20210310134321545

image-20210310134420044

注:如果请求的静态资源和请求的接口是同一个路径,则优先处理接口

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");
		}
	}

image-20210310133939693

注:如果这里配置了静态资源路径,会导致欢迎页失效,如果没有失效,则请重定向到Index.html

posted @ 2021-03-11 15:15  天宇轩-王  阅读(505)  评论(3编辑  收藏  举报