由于子项目比较多,子项目都是通过嵌套的方式实现的。就会导致子页面加载比较慢,影响客户体验
实现思路(AI搜的--!):
1、通过spring boot缓存实现静态资源缓存
2、在gateway过滤器,对静态资源进行缓存
直接上代码:
- <dependency>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-starter-cacheartifactId>
- 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
- * 创建时间: 2023/11/15 10:19
- * 功能描述:静态资源缓存
- */
- @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
synchronizedList = Collections.synchronizedList(new ArrayList<>()); -
- public StaticResourceFilter(WebClient webClient, CacheManager cacheManager) {
- this.webClient = webClient;
- this.cacheManager = cacheManager;
- }
-
- @Override
- public Mono
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");
-
- // 尝试从缓存中获取静态资源
- 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");
- // 根据文件后缀设置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;
- }
-
- // 这里假设缓存的内容是字节数组,您可以根据实际情况进行调整
- DataBuffer dataBuffer = response.bufferFactory().wrap((byte[]) cachedResource);
- return response.writeWith(Mono.just(dataBuffer));
- }
- // 如果缓存不存在,则继续请求下游服务获取资源,并将其缓存起来
- return chain.filter(exchange).then(Mono.fromRunnable(() -> {
- getResourceFromDownstream(staticResourcePath, cacheKey, cache);
- }));
- }
-
- // 继续处理其他过滤器或请求
- return chain.filter(exchange);
- }
-
- @Override
- public int getOrder() {
- return Ordered.HIGHEST_PRECEDENCE;
- }
-
- /**
- * 根据请求路径判断是否为静态资源请求
- *
- * @param staticResourcePath 请求路径
- */
- private boolean isStaticResource(String staticResourcePath) {
- Pattern pattern = Pattern.compile(STATIC_RESOURCE_PATTERN);
- Matcher matcher = pattern.matcher(staticResourcePath);
- return matcher.find();
- }
-
- /**
- * 请求下游服务静态资源的方法,这里只是一个示例,您需要根据实际情况实现此方法
- *
- * @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);
- // 处理响应数据
- mono.subscribe(res -> {
- synchronizedList.remove(staticResourcePath);
- cache.put(cacheKey, res);
- }, error -> {
- log.error("请求下游服务静态资源失败:{},\n错误详情:{}", staticResourcePath, error.toString());
- });
- }
-
- /**
- * 获取静态资源地址
- *
- * @param uri uri
- * @return 静态资源地址
- */
- private String getUrl(URI uri) {
- String path = uri.getPath();
- String host = uri.getHost();
- int port = uri.getPort();
-
- // 下游服务的地址是
- String downstreamUrl = String.format("http://%s:%s%s", host, port, path);
- return downstreamUrl;
- }
- }