日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 前端技术 > javascript >内容正文

javascript

Spring Boot 静态资源访问原理解析

發(fā)布時(shí)間:2023/11/29 javascript 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Spring Boot 静态资源访问原理解析 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

一、前言

  springboot配置靜態(tài)資源方式是多種多樣,接下來(lái)我會(huì)介紹其中幾種方式,并解析一下其中的原理。

二、使用properties屬性進(jìn)行配置

  應(yīng)該說(shuō)?spring.mvc.static-path-pattern 和?spring.resources.static-locations這兩屬性是成對(duì)使用的,如果不明白其中的原理,總會(huì)出現(xiàn)資源404的情況。首先收一下spring.mvc.static-path-pattern代表的是一個(gè)Ant Path路徑,例如resources/**,表示當(dāng)你的路徑中存在resources/**的時(shí)候才會(huì)處理請(qǐng)求。比如我們?cè)L問(wèn)“http://localhost:8080/resources/xxx.js”時(shí),很顯然,springboot邏輯中會(huì)根據(jù)模式匹配對(duì)url進(jìn)行匹配,匹配命中后,是如何再定位到具體的資源的呢?這時(shí)候spring.resources.static-locations的配置就起作用了。

  忘記說(shuō)了,在springboot中spring.mvc.static-path-pattern的默認(rèn)值是/**,spring.resources.static-locations的默認(rèn)值是classpath:/static,classpath:/public,classpath:/resources,classpath:/META-INF/resources,servlet context:/,springboot中相關(guān)的ResourceHttpRequestHandler就會(huì)去spring.resources.static-locations配置的所有路徑中尋找資源文件。

  所以我之前才說(shuō)spring.mvc.static-path-pattern 和?spring.resources.static-locations這兩屬性是成對(duì)使用的。

三、springboot中默認(rèn)對(duì)靜態(tài)資源的處理

  調(diào)試過(guò)程中,通過(guò)查看?org.springframework.web.servlet.DispatcherServlet中的handlerMappings變量,我們發(fā)現(xiàn)有一個(gè)很顯眼的?resourceHandlerMapping?,這個(gè)是springboot為我們提供的一個(gè)默認(rèn)的靜態(tài)資源handler,通過(guò)全文搜索發(fā)現(xiàn)出現(xiàn)在org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport這個(gè)類(lèi)中,也就是這個(gè)類(lèi)包含了@EnableWebMvc注解中的大多數(shù)功能,更多的擴(kuò)展功能請(qǐng)參考o(jì)rg.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration。

  resourceHandlerMapping?的定義如下。

/*** Return a handler mapping ordered at Integer.MAX_VALUE-1 with mapped* resource handlers. To configure resource handling, override* {@link #addResourceHandlers}.*/ @Bean public HandlerMapping resourceHandlerMapping() {ResourceHandlerRegistry registry = new ResourceHandlerRegistry(this.applicationContext,this.servletContext, mvcContentNegotiationManager());addResourceHandlers(registry);AbstractHandlerMapping handlerMapping = registry.getHandlerMapping();if (handlerMapping != null) {handlerMapping.setPathMatcher(mvcPathMatcher());handlerMapping.setUrlPathHelper(mvcUrlPathHelper());handlerMapping.setInterceptors(new ResourceUrlProviderExposingInterceptor(mvcResourceUrlProvider()));handlerMapping.setCorsConfigurations(getCorsConfigurations());}else {handlerMapping = new EmptyHandlerMapping();}return handlerMapping; }

  請(qǐng)大家先記住ResourceHandlerRegistry這個(gè)類(lèi)。

 ? ?首先看一下addResourceHandlers(registry);這個(gè)方法,父類(lèi)DelegatingWebMvcConfiguration做了實(shí)現(xiàn),如下。

private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite(); @Override protected void addResourceHandlers(ResourceHandlerRegistry registry) {this.configurers.addResourceHandlers(registry); }

  其中WebMvcConfigurerComposite是操作了WebMvcConfigurer類(lèi)型的對(duì)象的集合。在org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration這個(gè)springmvc的自動(dòng)配置類(lèi)中,有一個(gè)WebMvcConfigurer的實(shí)現(xiàn)類(lèi),如下。

// Defined as a nested config to ensure WebMvcConfigurerAdapter is not read when not // on the classpath @Configuration @Import(EnableWebMvcConfiguration.class) @EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class }) public static class WebMvcAutoConfigurationAdapter extends WebMvcConfigurerAdapter {...@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {if (!this.resourceProperties.isAddMappings()) {logger.debug("Default resource handling disabled");return;}Integer cachePeriod = this.resourceProperties.getCachePeriod();if (!registry.hasMappingForPattern("/webjars/**")) {customizeResourceHandlerRegistration(registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/").setCachePeriod(cachePeriod));} String staticPathPattern = this.mvcProperties.getStaticPathPattern();if (!registry.hasMappingForPattern(staticPathPattern)) {customizeResourceHandlerRegistration(registry.addResourceHandler(staticPathPattern).addResourceLocations(this.resourceProperties.getStaticLocations()).setCachePeriod(cachePeriod));}}... }

  上面的addResourceHandlers方法中,增加了默認(rèn)的mapping pattern =?/webjars/** ,默認(rèn)的resource location是classpath:/META-INF/resources/webjars/。正是這里的配置,我們?cè)诩蓅wagger的時(shí)候,就可以正常訪問(wèn)到swagger webjars中的js文件了。其中紅色的代碼部分就是用戶(hù)可以自定義的默認(rèn)靜態(tài)資源訪問(wèn)方式,并通過(guò)ResourceHandlerRegistry對(duì)象進(jìn)行注冊(cè)。接著看一下mvcProperties和resourceProperties對(duì)應(yīng)的類(lèi)吧。

@ConfigurationProperties("spring.mvc") public class WebMvcProperties {.../*** Path pattern used for static resources.*/private String staticPathPattern = "/**";... }

  WebMvcProperties類(lèi)中的staticPathPattern field 對(duì)應(yīng)了spring.mvc.static-path-pattern這個(gè)屬性,可以看到默認(rèn)值是 "/**"。

@ConfigurationProperties(prefix = "spring.resources", ignoreUnknownFields = false) public class ResourceProperties implements ResourceLoaderAware {.....private static final String[] SERVLET_RESOURCE_LOCATIONS = { "/" };private static final String[] CLASSPATH_RESOURCE_LOCATIONS = {"classpath:/META-INF/resources/", "classpath:/resources/","classpath:/static/", "classpath:/public/" };private static final String[] RESOURCE_LOCATIONS;static {RESOURCE_LOCATIONS = new String[CLASSPATH_RESOURCE_LOCATIONS.length+ SERVLET_RESOURCE_LOCATIONS.length];System.arraycopy(SERVLET_RESOURCE_LOCATIONS, 0, RESOURCE_LOCATIONS, 0,SERVLET_RESOURCE_LOCATIONS.length);System.arraycopy(CLASSPATH_RESOURCE_LOCATIONS, 0, RESOURCE_LOCATIONS,SERVLET_RESOURCE_LOCATIONS.length, CLASSPATH_RESOURCE_LOCATIONS.length);}private String[] staticLocations = RESOURCE_LOCATIONS;...... }

  ResourceProperties中staticLocations field 對(duì)應(yīng)了?spring.resources.static-locations 這個(gè)屬性。可以看到默認(rèn)值是classpath:[/META-INF/resources/, /resources/, /static/, /public/], servlet context:/

四、靜態(tài)資源的Bean配置

  在了解了springboot默認(rèn)資源的配置的原理(即?spring.mvc.static-path-pattern 和?spring.resources.static-locations),我們可以增加一個(gè)WebMvcConfigurer類(lèi)型的bean,來(lái)添加靜態(tài)資源的訪問(wèn)方式,還記得上面說(shuō)的“請(qǐng)記住ResourceHandlerRegistry這個(gè)類(lèi)“,下面就用到了哦。

@Configuration public class ResourceWebMvcConfigurer extends WebMvcConfigurerAdapter {@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("/resources/**").addResourceLocations("classpath:/public-resources/").setCacheControl(CacheControl.maxAge(1, TimeUnit.HOURS).cachePublic());} }

  那么當(dāng)訪問(wèn)路徑中包含"resources/**"的時(shí)候,resource handler就會(huì)去classpath:/public-resources目錄下尋找了。

五、靜態(tài)資源的查找

  參考?org.springframework.web.servlet.resource.ResourceHttpRequestHandler,ResourceHttpRequestHandler中通過(guò)org.springframework.web.servlet.resource.PathResourceResolver進(jìn)行查找。

  舉個(gè)例子,下圖是springboot打包之后的目錄結(jié)構(gòu),現(xiàn)在想要通過(guò)url訪問(wèn)application.properties文件,springboot默認(rèn)的靜態(tài)文件配置可以嗎?當(dāng)然需要用事實(shí)來(lái)說(shuō)話了。

  ?

?  我們已經(jīng)知道,默認(rèn)的resource locations中有個(gè) servlet-context:/,訪問(wèn)你的url是http://localhost:8080/工程名/application.properties,調(diào)試一下PathResourceResolver,結(jié)果如下。

  

  

  發(fā)現(xiàn)servlet-context的根路徑如上圖所示,查看一下這個(gè)路徑對(duì)應(yīng)的目錄,發(fā)現(xiàn)什么都沒(méi)有,所以很顯然無(wú)法找到我們要找的文件了。畢竟一般使用springboot都是jar項(xiàng)目,servlet-context path下沒(méi)有用戶(hù)自定義的資源。

?六、其他方式

  在Servlet3協(xié)議規(guī)范中,包含在JAR文件/META-INFO/resources/路徑下的資源可以直接訪問(wèn)了。如果將springboot項(xiàng)目打包成war包,可以配置一個(gè)默認(rèn)的servlet。在WebMvcConfigurationSupport中已經(jīng)定義好了,不過(guò)默認(rèn)是一個(gè)EmptyHandlerMapping。

/*** Return a handler mapping ordered at Integer.MAX_VALUE with a mapped* default servlet handler. To configure "default" Servlet handling,* override {@link #configureDefaultServletHandling}.*/ @Bean public HandlerMapping defaultServletHandlerMapping() {DefaultServletHandlerConfigurer configurer = new DefaultServletHandlerConfigurer(servletContext);configureDefaultServletHandling(configurer);AbstractHandlerMapping handlerMapping = configurer.getHandlerMapping();handlerMapping = handlerMapping != null ? handlerMapping : new EmptyHandlerMapping();return handlerMapping; }

  可以通過(guò)自定義一個(gè)WebMvcConfigurer類(lèi)型的bean,改寫(xiě)configureDefaultServletHandling 方法,如下。

@Configuration public class MyWebConfigurer extends WebMvcConfigurerAdapter {@Overridepublic void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {configurer.enable();} }

  這樣就設(shè)置了一個(gè)默認(rèn)的servlet,在加載靜態(tài)資源的時(shí)候就會(huì)按照servelt方式去加載了。

?

  就先分享這么多了,更多分享請(qǐng)關(guān)注我們的技術(shù)公眾號(hào)吧!!!

總結(jié)

以上是生活随笔為你收集整理的Spring Boot 静态资源访问原理解析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。