Fetch the repository succeeded.
插件已添加配置:
resources:
static-locations: classpath:static/
当主程序 以dev模式启动插件时, 可以正常通过 /static-plugin/插件id/xxx 访问插件中的静态资源:
但是在 prod 模式启动后, 通过上述路径访问提示 资源未找到
我看dev模式下是好的, prod模式下就是不行, 只能临时用下面的方法解决了~
@DY
@Api("生产模式-静态资源")
@RequestMapping("/")
public class CommonResourceController {
private static final Logger logger = LoggerFactory.getLogger(CommonResourceController.class);
@GetMapping("/static/{file}")
@ApiOperation("获取静态资源")
public String resource(@PathVariable(name = "file", required = true) String file) {
ServletRequestAttributes requestConext = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
try {
ServletOutputStream sos = requestConext.getResponse().getOutputStream();
requestConext.getResponse().setCharacterEncoding(StandardCharsets.UTF_8.name());
final String path = "static/" + file;
//类加载器不同,配置和静态资源都被隔离
InputStream ins = PluginContextHolder.getPluginClassLoader().getResourceAsStream(path);
IOUtils.copy(ins, sos);
ins.close();
} catch (Exception e) {
e.printStackTrace();
logger.error("读取静态资源失败: /static/" + file);
}
//返回404
requestConext.getResponse().setStatus(HttpServletResponse.SC_NOT_FOUND);
return null;
}
}
访问效果:
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。
我也碰到了不能访问静态文件的问题,我的原因是加了自定义的server.servlet.context-path,但是这个框架在PluginStaticResourceResolver中没处理自定义context-path的情况,导致pluginId获取错误。
我的解决方式是使用我自定义PluginStaticResourceResolver,处理下这个情况就行。
改动如下:
@Configuration
public class PluginConfig {
@Bean
public PluginStaticResourceWebMvcConfigurer pluginWebResourceResolver(PluginStaticResourceConfig resourceConfig) {
return new PluginStaticResourceWebMvcConfigurer(resourceConfig);
}
@Bean
public PluginLaunchInvolved pluginLaunchInvolved() {
return new PluginLaunchInvolved() {
@Override
public void after(PluginInsideInfo pluginInsideInfo, ClassLoader classLoader, SpringPluginHook pluginHook)
throws Exception
{
InsidePluginDescriptor descriptor = pluginInsideInfo.getPluginDescriptor();
// 使用自定义的PluginStaticResourceResolver的静态方法
PluginStaticResourceResolver.parse(descriptor, classLoader, pluginHook.getWebConfig());
}
@Override
public void close(PluginInsideInfo pluginInsideInfo, ClassLoader classLoader) throws Exception {
InsidePluginDescriptor descriptor = pluginInsideInfo.getPluginDescriptor();
String pluginId = descriptor.getPluginId();
// 使用自定义的PluginStaticResourceResolver的静态方法
PluginStaticResourceResolver.remove(pluginId);
}
};
}
public static class PluginStaticResourceWebMvcConfigurer
extends com.gitee.starblues.spring.web.PluginStaticResourceWebMvcConfigurer
{
private final PluginStaticResourceConfig resourceConfig;
public PluginStaticResourceWebMvcConfigurer(PluginStaticResourceConfig resourceConfig) {
super(resourceConfig);
this.resourceConfig = resourceConfig;
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
String pathPattern = "/" + resourceConfig.getPathPrefix() + "/**";
ResourceHandlerRegistration resourceHandlerRegistration = registry.addResourceHandler(pathPattern);
CacheControl cacheControl = resourceConfig.getCacheControl();
if(cacheControl != null) {
resourceHandlerRegistration.setCacheControl(cacheControl);
}
else {
resourceHandlerRegistration.setCacheControl(CacheControl.noStore());
}
// 此处的PluginStaticResourceResolver使用的是自定义的
resourceHandlerRegistration
.resourceChain(false)
.addResolver(new PluginStaticResourceResolver(resourceConfig));
}
}
}
import com.gitee.starblues.core.descriptor.PluginDescriptor;
import com.gitee.starblues.spring.WebConfig;
import com.gitee.starblues.spring.web.PluginResource;
import com.gitee.starblues.spring.web.PluginStaticResourceConfig;
import com.gitee.starblues.utils.MsgUtils;
import com.gitee.starblues.utils.ObjectUtils;
import com.gitee.starblues.utils.UrlUtils;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.FileUrlResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.resource.AbstractResourceResolver;
import org.springframework.web.servlet.resource.ResourceResolverChain;
public class PluginStaticResourceResolver extends AbstractResourceResolver {
private final static Logger logger = LoggerFactory.getLogger(PluginStaticResourceResolver.class);
private final static String RESOLVED_RESOURCE_CACHE_KEY_PREFIX = "resolvedPluginResource:";
private final static Map<String, PluginStaticResource> PLUGIN_RESOURCE_MAP = new ConcurrentHashMap<>();
private final PluginStaticResourceConfig config;
public PluginStaticResourceResolver(PluginStaticResourceConfig config) {
this.config = config;
}
@Override
protected Resource resolveResourceInternal(HttpServletRequest request,
String requestPath, List<? extends Resource> locations,
ResourceResolverChain chain)
{
if(request != null) {
String requestUri = request.getRequestURI();
String formatUri = UrlUtils.format(requestUri);
// 此处添加处理contextPath的逻辑
if(!Objects.equals("/", request.getContextPath())) {
formatUri = formatUri.replaceFirst(request.getContextPath().replaceFirst("/", ""), "");
}
// fix https://gitee.com/starblues/springboot-plugin-framework-parent/issues/I53T9W
requestPath = UrlUtils.format(formatUri.replaceFirst(config.getPathPrefix(), ""));
}
int startOffset = requestPath.indexOf("/");
String pluginId = null;
String partialPath = null;
if(startOffset == -1) {
pluginId = requestPath;
partialPath = config.getIndexPageName();
}
else {
pluginId = requestPath.substring(0, startOffset);
partialPath = requestPath.substring(startOffset + 1);
}
PluginStaticResource pluginResource = PLUGIN_RESOURCE_MAP.get(pluginId);
if(pluginResource == null) {
return chain.resolveResource(request, requestPath, locations);
}
String key = computeKey(request, requestPath);
// 先判断缓存中是否存在。
Resource resource = pluginResource.getCacheResource(key);
if(resource != null) {
return resource;
}
resource = findResource(pluginResource, partialPath);
if(resource != null) {
pluginResource.putCacheResource(key, resource);
return resource;
}
else {
// 尝试获取首页页面
String indexPageName = config.getIndexPageName();
if(ObjectUtils.isEmpty(indexPageName)) {
indexPageName = PluginStaticResourceConfig.DEFAULT_INDEX_PAGE_NAME;
}
if(partialPath.lastIndexOf(".") > -1) {
// 存在后缀
return null;
}
// 查找第一级节点,找不到则读取根index.html
if(partialPath.contains(UrlUtils.PATH_SEPARATOR)) {
partialPath = partialPath.substring(0, partialPath.indexOf(UrlUtils.PATH_SEPARATOR));
}
// 第一级节点
resource = findResource(pluginResource, UrlUtils.joiningUrlPath(partialPath, indexPageName));
if(resource != null) {
return resource;
}
// 根节点
return findResource(pluginResource, UrlUtils.joiningUrlPath(UrlUtils.PATH_SEPARATOR, indexPageName));
}
}
// 其余代码拷贝框架自带的PluginStaticResourceResolver的方法即可
// 由于框架自带的PluginStaticResourceResolver很多方法都是私有方法,因此没采用继承,使用直接复制的方式
Sign in to comment