由于子項(xiàng)目比較多,子項(xiàng)目都是通過(guò)嵌套的方式實(shí)現(xiàn)的。就會(huì)導(dǎo)致子頁(yè)面加載比較慢,影響客戶體驗(yàn)
實(shí)現(xiàn)思路(AI搜的--!):
1、通過(guò)spring boot緩存實(shí)現(xiàn)靜態(tài)資源緩存
2、在gateway過(guò)濾器,對(duì)靜態(tài)資源進(jìn)行緩存文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-774737.html
直接上代碼:文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-774737.html
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
package com.xxx.filter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.support.SimpleValueWrapper;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author Wang
* 創(chuàng)建時(shí)間: 2023/11/15 10:19
* 功能描述:靜態(tài)資源緩存
*/
@Slf4j
@Component
public class StaticResourceFilter implements GlobalFilter, Ordered {
private static final String STATIC_RESOURCE_PATTERN = "\\.(html|css|js|png|jpg|jpeg|gif|woff2|woff)$";
private final WebClient webClient;
private final CacheManager cacheManager;
List<String> synchronizedList = Collections.synchronizedList(new ArrayList<>());
public StaticResourceFilter(WebClient webClient, CacheManager cacheManager) {
this.webClient = webClient;
this.cacheManager = cacheManager;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
URI uriInfo = request.getURI();
String staticResourcePath = getUrl(uriInfo);
if (isStaticResource(staticResourcePath) && !synchronizedList.contains(staticResourcePath)) {
//Route route = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR);
String cacheKey = request.getURI().toString();
Cache cache = cacheManager.getCache("staticResources");
// 嘗試從緩存中獲取靜態(tài)資源
Object cachedResource = cache.get(cacheKey);
if (cachedResource != null) {
if (cachedResource instanceof SimpleValueWrapper) {
cachedResource = ((SimpleValueWrapper) cachedResource).get();
}
// 如果緩存中存在,直接返回緩存的資源
ServerHttpResponse response = exchange.getResponse();
HttpHeaders headers = response.getHeaders();
String fileSuffix = staticResourcePath.replaceAll(".*(\\.[a-zA-Z0-9]+)$", "$1");
// 根據(jù)文件后綴設(shè)置MIME類型
switch (fileSuffix) {
case ".html":
headers.setContentType(MediaType.TEXT_HTML);
break;
case ".js":
headers.set(HttpHeaders.CONTENT_TYPE, "application/javascript");
break;
case ".css":
headers.set(HttpHeaders.CONTENT_TYPE, "text/css");
break;
case ".png":
headers.setContentType(MediaType.IMAGE_PNG);
break;
case ".jpg":
case ".jpeg":
headers.setContentType(MediaType.IMAGE_JPEG);
break;
case ".woff":
headers.set(HttpHeaders.CONTENT_TYPE, "application/font-woff");
break;
case ".woff2":
headers.set(HttpHeaders.CONTENT_TYPE, "application/font-woff2");
break;
case ".ttf":
headers.set(HttpHeaders.CONTENT_TYPE, "application/x-font-ttf");
break;
case ".eot":
headers.set(HttpHeaders.CONTENT_TYPE, "application/vnd.ms-fontobject");
break;
default:
headers.setContentType(MediaType.ALL);
break;
}
// 這里假設(shè)緩存的內(nèi)容是字節(jié)數(shù)組,您可以根據(jù)實(shí)際情況進(jìn)行調(diào)整
DataBuffer dataBuffer = response.bufferFactory().wrap((byte[]) cachedResource);
return response.writeWith(Mono.just(dataBuffer));
}
// 如果緩存不存在,則繼續(xù)請(qǐng)求下游服務(wù)獲取資源,并將其緩存起來(lái)
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
getResourceFromDownstream(staticResourcePath, cacheKey, cache);
}));
}
// 繼續(xù)處理其他過(guò)濾器或請(qǐng)求
return chain.filter(exchange);
}
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
/**
* 根據(jù)請(qǐng)求路徑判斷是否為靜態(tài)資源請(qǐng)求
*
* @param staticResourcePath 請(qǐng)求路徑
*/
private boolean isStaticResource(String staticResourcePath) {
Pattern pattern = Pattern.compile(STATIC_RESOURCE_PATTERN);
Matcher matcher = pattern.matcher(staticResourcePath);
return matcher.find();
}
/**
* 請(qǐng)求下游服務(wù)靜態(tài)資源的方法,這里只是一個(gè)示例,您需要根據(jù)實(shí)際情況實(shí)現(xiàn)此方法
*
* @param cache 緩存
* @param staticResourcePath URL
* @param cacheKey 緩存Key
*/
private void getResourceFromDownstream(String staticResourcePath, String cacheKey, Cache cache) {
synchronizedList.add(staticResourcePath);
Mono<byte[]> mono = webClient.get().uri(staticResourcePath).retrieve().bodyToMono(byte[].class);
// 處理響應(yīng)數(shù)據(jù)
mono.subscribe(res -> {
synchronizedList.remove(staticResourcePath);
cache.put(cacheKey, res);
}, error -> {
log.error("請(qǐng)求下游服務(wù)靜態(tài)資源失?。簕},\n錯(cuò)誤詳情:{}", staticResourcePath, error.toString());
});
}
/**
* 獲取靜態(tài)資源地址
*
* @param uri uri
* @return 靜態(tài)資源地址
*/
private String getUrl(URI uri) {
String path = uri.getPath();
String host = uri.getHost();
int port = uri.getPort();
// 下游服務(wù)的地址是
String downstreamUrl = String.format("http://%s:%s%s", host, port, path);
return downstreamUrl;
}
}
到了這里,關(guān)于基于spring gateway 的靜態(tài)資源緩存實(shí)現(xiàn)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!