• Springboot 2.x 静态资源配置


    一、静态资源配置原理

    Springboot 2.x 对于静态资源的配置都是由 WebMvcAutoConfiguration 这个类完成的,我们这里选取 Springboot-2.3.7.RELEASE 这个版本来探究一下 Springboot 底层对于静态资源是如何进行配置的

    首先来到 WebMvcAutoConfiguration 这个配置类,该类的声明如下

    // 配置中各个组件没有依赖关系,为了加快效率,设置 proxyBeanMethods=false ,其默认值是 true
    @Configuration(proxyBeanMethods = false)
    // 当前是否是 Web 环境,并且类型是否是 SERVLET 类型的
    @ConditionalOnWebApplication(type = Type.SERVLET)
    // 系统中包含 Servlet、DispatcherServlet、WebMvcConfigurer 这几个类
    @ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class})
    // 容器中不包含 WebMvcConfigurationSupport 这个组件
    @ConditionalOnMissingBean({WebMvcConfigurationSupport.class})
    // 自动配置排序,数值越低,优先级越高
    @AutoConfigureOrder(-2147483638)
    // 自动配置在 DispatcherServletAutoConfiguration、TaskExecutionAutoConfiguration 、ValidationAutoConfiguration 之后
    @AutoConfigureAfter({DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class})
    public class WebMvcAutoConfiguration {
        public static final String DEFAULT_PREFIX = "";
        public static final String DEFAULT_SUFFIX = "";
        private static final String[] SERVLET_LOCATIONS = new String[]{"/"};
    
        public WebMvcAutoConfiguration() {
        }
    	
        ....注册各种组件
    	
    }
    

    如果 WebMvcAutoConfiguration 上的条件注解都满足的情况下才会执行该类里面的各种行为,在该类中我们可以发现存在一个静态内部类 WebMvcAutoConfigurationAdapter ,该类的具体声明如下

    // 配置中各个组件没有依赖关系,为了加快效率,设置 proxyBeanMethods=false ,proxyBeanMethods 默认值是 true
    @Configuration(proxyBeanMethods = false)
    // 向容器中注册组件 EnableWebMvcConfiguration
    @Import({WebMvcAutoConfiguration.EnableWebMvcConfiguration.class})
    // 开启 WebMvcProperties、ResourceProperties 类上的 @ConfigurationProperties 注解,并且将这两个类注入 IOC 容器中
    @EnableConfigurationProperties({WebMvcProperties.class, ResourceProperties.class})
    // 排序
    @Order(0)
    public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer {
    	private static final Log logger = LogFactory.getLog(WebMvcConfigurer.class);
    	// 1、静态资源配置类 ----> 详细见代码块一
    	private final ResourceProperties resourceProperties;
    	final WebMvcAutoConfiguration.ResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer;
    
    	public void addResourceHandlers(ResourceHandlerRegistry registry) {
    		// 2、如果配置了 spring.resources.add-mappings=false ,那么 Springboot 就不会对静态资源和 webjars 进行自动配置
    		// spring.resources.add-mappings 的默认值是 true,它就是一个是否开启 Springboot 对静态资源配置的开关,可以在
    		// application.properties 中配置 debug=true ,然后就可以查看到 debug 级别的日志了
    		if (!this.resourceProperties.isAddMappings()) {
    			logger.debug("Default resource handling disabled");
    		} else {
    			// 3、获取缓存时间
    			Duration cachePeriod = this.resourceProperties.getCache().getPeriod();
    			// 4、获取缓存控制对象
    			CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();
    			// 5、webjars 的映射规则 /webjars/** ----> classpath:/META-INF/resources/webjars/
    			// 也就是比如我们访问 http://localhost:8080/webjars/aaa.js ,实际上就是访问当前项目类路径下
    			// /META-INF/resources/webjars/aaa.js 这个资源
    			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));
    			}
    			// 6、staticPathPattern 默认值是 /** ,也可以在 application.properties 中配置 spring.mvc.static-path-pattern 来修改 Springboot 默认值
    			String staticPathPattern = this.mvcProperties.getStaticPathPattern();
    			// 7、静态资源映射规则
    			if (!registry.hasMappingForPattern(staticPathPattern)) {
    				this.customizeResourceHandlerRegistration(
    				registry.addResourceHandler(new String[]{staticPathPattern})
    				// 8、静态资源映射路径 ----> 详细见代码块二
    				.addResourceLocations(WebMvcAutoConfiguration.getResourceLocations(this.resourceProperties.getStaticLocations()))
    				.setCachePeriod(this.getSeconds(cachePeriod))
    				.setCacheControl(cacheControl));
    			}
    		}
    	}
    }

    代码块一、静态资源配置类

    // 1、将 application.properties 中 spring.resources 开头的配置项与 ResourceProperties 类的属性进行绑定
    // 如果该类中有属性没有匹配到值,则抛出异常
    @ConfigurationProperties(prefix = "spring.resources",ignoreUnknownFields = false)
    public class ResourceProperties {
    	// 2、Springboot 默认的静态资源路径
        private static final String[] CLASSPATH_RESOURCE_LOCATIONS = new String[]{
    		"classpath:/META-INF/resources/", 
    		"classpath:/resources/", 
    		"classpath:/static/", 
    		"classpath:/public/"
    	};
        private String[] staticLocations;
        private boolean addMappings;
        private final ResourceProperties.Chain chain;
        private final ResourceProperties.Cache cache;
    
        public ResourceProperties() {
    		// 2、Springboot 默认的静态资源路径
            this.staticLocations = CLASSPATH_RESOURCE_LOCATIONS;
    		// 3、addMappings 默认值为 true,也就是 application.properties 中不配置
    		// spring.resources.add-mappings 选项,那么就使用 Springboot 的默认值 true
            this.addMappings = true;
            this.chain = new ResourceProperties.Chain();
            this.cache = new ResourceProperties.Cache();
        }
    
        public String[] getStaticLocations() {
            return this.staticLocations;
        }
    	
    	...........
    	
    }

    代码块二、WebMvcAutoConfiguration.getResourceLocations(this.resourceProperties.getStaticLocations())

    this.resourceProperties.getStaticLocations():获取与 ResourceProperties 绑定的静态资源路径, Springboot 默认的静态资源路径如下:

    private static final String[] CLASSPATH_RESOURCE_LOCATIONS = new String[]{
    	"classpath:/META-INF/resources/", 
    	"classpath:/resources/", 
    	"classpath:/static/", 
    	"classpath:/public/"
    }
    

    如果我们手动在 application.properties 中配置了 spring.resources.static-locations ,那么它会覆盖 Springboot 的默认值

     

    二、总结

    1、Springboot webjars 的默认映射规则 /webjars/** ----> classpath:/META-INF/resources/webjars/

    2、Springboot 静态资源的默认映射规则 /** ----> { classpath:/META-INF/resources、classpath:/resources/、classpath:/static/、classpath:/public/ }

    3、可以通过修改 application.properties 配置文件中的配置项来改变 Springboot 默认的配置规则,或者手动注册组件的方式来额外增加配置规则(与默认规则一同生效)

     

    三、案例

    1、webjars : 以依赖的方式引入 CSS、JS 等

    登录 webjars 官网

    https://www.webjars.org/

    选择你需要的资源,这里以 js 为例

    引入后的 webjars 依赖如下

    由于 webjars 的映射规则是 /webjars/** ----> classpath:/META-INF/resources/webjars/

    如果我想访问上图中的 classpath:/META-INF/resources/webjars/jquery/3.5.1/jquery.js 这个资源

    那么浏览器只需要访问 http://localhost:8080/webjars/jquery/3.5.1/jquery.js 即可

     

    2、静态资源

    Springboot 对静态资源的默认映射规则是 /** ----> { classpath:/META-INF/resources、classpath:/resources/、classpath:/static/、classpath:/public/ }

    例如浏览器发起请求 http://localhost:8080/aaa.txt ,那么就会去 classpath:/META-INF/resources、classpath:/resources/、classpath:/static/、classpath:/public/ 这几个目录中寻找有没有 aaa.txt 这个资源,如果有就返回结果,没有显示 404 

    3、自定义对静态资源的处理

    方式一、修改 application.properties 配置文件的方式

    注意:如果在配置文件中进行如下配置,则 springboot 默认配置将被覆盖,原先默认的静态路径访问前缀 /** 和默认的静态资源文件目录都将失效

    # 该配置项的默认值是 true,如果设置为 false 则代表关闭 Springboot 对 webjars 和静态资源的配置
    # 如果配置了该项的话,可以开启 debug 日志级别,控制台可以看到禁用了 Springboot 的默认配置
    spring.resources.add-mappings=false
    # 开启 debug 级别的日志信息
    debug=true
    
    # 修改静态资源访问前缀,配置了该选项之后,比如你想访问静态资源文件夹下的 aaa.txt,需要带上 bluefatty 前缀
    # 例如:http://localhost:8080/bluefatty/aaa.txt 就是访问静态资源文件夹下的 aaa.txt
    # 配置了该配置项之后,Springboot 默认的首页访问将失效
    spring.mvc.static-path-pattern=/bluefatty/**
    
    # 修改 Springboot 默认的静态资源文件夹,启用了该配置之后 Springboot 默认的静态资源文件夹将失效
    spring.resources.static-locations=classpath:/META-INF/resources02/,
                                      classpath:/resources02/,
                                      classpath:/static02/,
                                      classpath:/public02/,
                                      file:D://xiaomaomao/

    方式二、代码注册的方式

    注意:如果使用 WebMvcConfigurer 进行自定义规则,那么原先 Springboot 默认的配置和我们自定义的配置将一同起效

    如果你不想使用配置文件,我们还可以通过代码的方式来进行自定义,具体步骤如下

    自定义一个配置类 xxxWebMvcConfigurerAdapter extends WebMvcConfigurerAdapter(或者实现 WebMvcConfigurer ,其实是一个意思,因为 WebMvcConfigurerAdapter 实现了 WebMvcConfigurer 接口)

    @Configuration
    public class MyWebMvcConfigurerAdapter extends WebMvcConfigurerAdapter {
        @Override
        public void addResourceHandlers(ResourceHandlerRegistry registry){
            registry.addResourceHandler("/**")
                    // 1、src/main/webapp/ 路径下
                    .addResourceLocations("resources/", "static/", "public/",
                            "META-INF/resources/")
                    // 2、src/main/resources/ 路径下
                    .addResourceLocations("classpath:resources/", "classpath:static/",
                            "classpath:public/", "classpath:META-INF/resources/")
                    // 3、绝对路径
                    .addResourceLocations("file:D://xiaomaomao/");
        }
    }
    

    上面的配置有三种路径方式 static/ (无前缀)、带有 classpath 前缀、绝对路径,这里来简单说明一下

    1、无前缀 ----> "文档根目录"(一般指代 src/main/webapp 目录),例如 localhost:8080/index.html 定位至 src/main/webapp/static/index.html

    2、存在前缀 classpath -----> 类路径(一般指代 src/main/resources 目录)

    3、存在前缀 file:// -----> 文件系统路径("绝对路径")

     

  • 相关阅读:
    模板方法模式
    组合模式
    JS API文档
    支持 @connect写法
    PHP word导入题库
    go 复制文件和创建目录
    go文件写入
    go 文件读取
    gin连接mysql数据库
    gin多数据格式返回结果
  • 原文地址:https://www.cnblogs.com/xiaomaomao/p/14278402.html
Copyright © 2020-2023  润新知