This commit is contained in:
Looly 2023-10-22 23:58:55 +08:00
parent ec966de41c
commit da00aa3969
6 changed files with 159 additions and 85 deletions

View File

@ -14,13 +14,16 @@ package org.dromara.hutool.core.io.resource;
import org.dromara.hutool.core.collection.iter.EnumerationIter;
import org.dromara.hutool.core.compress.ZipUtil;
import org.dromara.hutool.core.exception.HutoolException;
import org.dromara.hutool.core.io.IORuntimeException;
import org.dromara.hutool.core.io.IoUtil;
import org.dromara.hutool.core.io.file.FileUtil;
import org.dromara.hutool.core.net.url.URLUtil;
import org.dromara.hutool.core.text.AntPathMatcher;
import org.dromara.hutool.core.text.CharUtil;
import org.dromara.hutool.core.text.StrUtil;
import java.io.File;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
@ -59,14 +62,18 @@ public class ResourceFinder {
final MultiResource result = new MultiResource();
// 遍历根目录下所有资源并过滤保留符合条件的资源
for (final Resource rootResource : ResourceUtil.getResources(rootDirPath, classLoader)) {
if (URLUtil.isJarURL(rootResource.getUrl())) {
if (rootResource instanceof JarResource) {
// 在jar包中
try {
result.addAll(findInJar(rootResource, subPattern));
result.addAll(findInJar((JarResource) rootResource, subPattern));
} catch (final IOException e) {
throw new IORuntimeException(e);
}
} else if (rootResource instanceof FileResource) {
// 文件夹中
result.addAll(findInDir((FileResource) rootResource, subPattern));
} else {
result.addAll(findInDir(rootResource, subPattern));
throw new HutoolException("Unsupported resource type: {}", rootResource.getClass().getName());
}
}
@ -81,12 +88,11 @@ public class ResourceFinder {
* @return 符合条件的资源
* @throws IOException IO异常
*/
protected MultiResource findInJar(final Resource rootResource, final String subPattern) throws IOException {
protected MultiResource findInJar(final JarResource rootResource, final String subPattern) throws IOException {
final URL rootDirURL = rootResource.getUrl();
final URLConnection conn = rootDirURL.openConnection();
final JarFile jarFile;
final String jarFileUrl;
String rootEntryPath;
final boolean closeJarFile;
@ -98,7 +104,7 @@ public class ResourceFinder {
rootEntryPath = (jarEntry != null ? jarEntry.getName() : StrUtil.EMPTY);
closeJarFile = !jarCon.getUseCaches();
} else {
//
// 去除子路径后重新获取jar文件
final String urlFile = rootDirURL.getFile();
try {
int separatorIndex = urlFile.indexOf(URLUtil.WAR_URL_SEPARATOR);
@ -106,7 +112,7 @@ public class ResourceFinder {
separatorIndex = urlFile.indexOf(URLUtil.JAR_URL_SEPARATOR);
}
if (separatorIndex != -1) {
jarFileUrl = urlFile.substring(0, separatorIndex);
final String jarFileUrl = urlFile.substring(0, separatorIndex);
rootEntryPath = urlFile.substring(separatorIndex + 2); // both separators are 2 chars
jarFile = ZipUtil.ofJar(jarFileUrl);
} else {
@ -130,7 +136,7 @@ public class ResourceFinder {
if (entryPath.startsWith(rootEntryPath)) {
final String relativePath = entryPath.substring(rootEntryPath.length());
if (pathMatcher.match(subPattern, relativePath)) {
result.add(new UrlResource(URLUtil.getURL(rootDirURL, relativePath)));
result.add(ResourceUtil.getResource(URLUtil.getURL(rootDirURL, relativePath)));
}
}
}
@ -143,8 +149,23 @@ public class ResourceFinder {
return result;
}
protected MultiResource findInDir(final Resource rootResource, final String subPattern) {
/**
* 遍历目录查找指定表达式匹配的文件列表
*
* @param resource 文件资源
* @param subPattern 子表达式
* @return 满足条件的文件
*/
protected MultiResource findInDir(final FileResource resource, final String subPattern) {
final MultiResource result = new MultiResource();
final File rootDir = resource.getFile();
FileUtil.walkFiles(rootDir, (file -> {
if (pathMatcher.match(subPattern, file.getName())) {
result.add(new FileResource(file));
}
}));
return result;
}
/**

View File

@ -17,6 +17,7 @@ import org.dromara.hutool.core.collection.iter.IterUtil;
import org.dromara.hutool.core.io.file.FileUtil;
import org.dromara.hutool.core.io.IORuntimeException;
import org.dromara.hutool.core.lang.Assert;
import org.dromara.hutool.core.net.url.UrlProtocolUtil;
import org.dromara.hutool.core.util.CharsetUtil;
import org.dromara.hutool.core.classloader.ClassLoaderUtil;
import org.dromara.hutool.core.text.StrUtil;
@ -253,6 +254,11 @@ public class ResourceUtil {
* @since 6.0.0
*/
public static Resource getResource(final URL url) {
if(UrlProtocolUtil.isJarURL(url)){
return new JarResource(url);
} else if(UrlProtocolUtil.isFileURL(url)){
return new FileResource(url.getFile());
}
return new UrlResource(url);
}

View File

@ -15,6 +15,7 @@ package org.dromara.hutool.core.io.resource;
import org.dromara.hutool.core.io.file.FileNameUtil;
import org.dromara.hutool.core.io.file.FileUtil;
import org.dromara.hutool.core.net.url.URLUtil;
import org.dromara.hutool.core.net.url.UrlProtocolUtil;
import org.dromara.hutool.core.util.ObjUtil;
import java.io.File;
@ -64,7 +65,7 @@ public class UrlResource implements Resource, Serializable {
*/
public UrlResource(final URL url, final String name) {
this.url = url;
if (null != url && URLUtil.URL_PROTOCOL_FILE.equals(url.getProtocol())) {
if (null != url && UrlProtocolUtil.URL_PROTOCOL_FILE.equals(url.getProtocol())) {
this.lastModified = FileUtil.file(url).lastModified();
}
this.name = ObjUtil.defaultIfNull(name, () -> (null != url ? FileNameUtil.getName(url.getPath()) : null));

View File

@ -16,7 +16,6 @@ import org.dromara.hutool.core.classloader.ClassLoaderUtil;
import org.dromara.hutool.core.exception.HutoolException;
import org.dromara.hutool.core.io.IORuntimeException;
import org.dromara.hutool.core.io.IoUtil;
import org.dromara.hutool.core.io.file.FileNameUtil;
import org.dromara.hutool.core.io.file.FileUtil;
import org.dromara.hutool.core.io.resource.ResourceUtil;
import org.dromara.hutool.core.lang.Assert;
@ -64,34 +63,6 @@ public class URLUtil {
* URL 前缀表示war: "war:"
*/
public static final String WAR_URL_PREFIX = "war:";
/**
* URL 协议表示文件: "file"
*/
public static final String URL_PROTOCOL_FILE = "file";
/**
* URL 协议表示Jar文件: "jar"
*/
public static final String URL_PROTOCOL_JAR = "jar";
/**
* URL 协议表示zip文件: "zip"
*/
public static final String URL_PROTOCOL_ZIP = "zip";
/**
* URL 协议表示WebSphere文件: "wsjar"
*/
public static final String URL_PROTOCOL_WSJAR = "wsjar";
/**
* URL 协议表示JBoss zip文件: "vfszip"
*/
public static final String URL_PROTOCOL_VFSZIP = "vfszip";
/**
* URL 协议表示JBoss文件: "vfsfile"
*/
public static final String URL_PROTOCOL_VFSFILE = "vfsfile";
/**
* URL 协议表示JBoss VFS资源: "vfs"
*/
public static final String URL_PROTOCOL_VFS = "vfs";
/**
* Jar路径以及内部文件路径的分界符: "!/"
*/
@ -429,50 +400,6 @@ public class URLUtil {
}
// endregion
/**
* 提供的URL是否为文件<br>
* 文件协议包括"file", "vfsfile" "vfs".
*
* @param url {@link URL}
* @return 是否为文件
* @since 3.0.9
*/
public static boolean isFileURL(final URL url) {
Assert.notNull(url, "URL must be not null");
final String protocol = url.getProtocol();
return (URL_PROTOCOL_FILE.equals(protocol) || //
URL_PROTOCOL_VFSFILE.equals(protocol) || //
URL_PROTOCOL_VFS.equals(protocol));
}
/**
* 提供的URL是否为jar包URL 协议包括 "jar", "zip", "vfszip" "wsjar".
*
* @param url {@link URL}
* @return 是否为jar包URL
*/
public static boolean isJarURL(final URL url) {
Assert.notNull(url, "URL must be not null");
final String protocol = url.getProtocol();
return (URL_PROTOCOL_JAR.equals(protocol) || //
URL_PROTOCOL_ZIP.equals(protocol) || //
URL_PROTOCOL_VFSZIP.equals(protocol) || //
URL_PROTOCOL_WSJAR.equals(protocol));
}
/**
* 提供的URL是否为Jar文件URL 判断依据为file协议且扩展名为.jar
*
* @param url the URL to check
* @return whether the URL has been identified as a JAR file URL
* @since 4.1
*/
public static boolean isJarFileURL(final URL url) {
Assert.notNull(url, "URL must be not null");
return (URL_PROTOCOL_FILE.equals(url.getProtocol()) && //
url.getPath().toLowerCase().endsWith(FileNameUtil.EXT_JAR));
}
/**
* 从URL中获取流
*
@ -704,7 +631,7 @@ public class URLUtil {
* @since 6.0.0
*/
public static long size(final URL url) {
if (URLUtil.isFileURL(url)) {
if (UrlProtocolUtil.isFileOrVfsURL(url)) {
// 如果资源以独立文件形式存在尝试获取文件长度
final File file = FileUtil.file(url);
final long length = file.length();

View File

@ -0,0 +1,119 @@
/*
* Copyright (c) 2023. looly(loolly@aliyun.com)
* Hutool is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* https://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
package org.dromara.hutool.core.net.url;
import org.dromara.hutool.core.io.file.FileNameUtil;
import org.dromara.hutool.core.lang.Assert;
import java.net.URL;
public class UrlProtocolUtil {
/**
* URL 协议表示文件: "file"
*/
public static final String URL_PROTOCOL_FILE = "file";
/**
* URL 协议表示Jar文件: "jar"
*/
public static final String URL_PROTOCOL_JAR = "jar";
/**
* URL 协议表示zip文件: "zip"
*/
public static final String URL_PROTOCOL_ZIP = "zip";
/**
* URL 协议表示WebSphere文件: "wsjar"
*/
public static final String URL_PROTOCOL_WSJAR = "wsjar";
/**
* URL 协议表示JBoss zip文件: "vfszip"
*/
public static final String URL_PROTOCOL_VFSZIP = "vfszip";
/**
* URL 协议表示JBoss文件: "vfsfile"
*/
public static final String URL_PROTOCOL_VFSFILE = "vfsfile";
/**
* URL 协议表示JBoss VFS资源: "vfs"
*/
public static final String URL_PROTOCOL_VFS = "vfs";
/**
* 提供的URL是否为文件<br>
* 文件协议包括"file", "vfsfile" "vfs".
*
* @param url {@link URL}
* @return 是否为文件
* @since 3.0.9
*/
public static boolean isFileOrVfsURL(final URL url) {
Assert.notNull(url, "URL must be not null");
return isFileURL(url) || isVfsURL(url);
}
/**
* 提供的URL是否为文件<br>
* 文件协议包括"file".
*
* @param url {@link URL}
* @return 是否为文件
* @since 6.0.0
*/
public static boolean isFileURL(final URL url) {
Assert.notNull(url, "URL must be not null");
final String protocol = url.getProtocol();
return URL_PROTOCOL_FILE.equals(protocol);
}
/**
* 提供的URL是否为文件<br>
* 文件协议包括"vfsfile" "vfs".
*
* @param url {@link URL}
* @return 是否为文件
* @since 6.0.0
*/
public static boolean isVfsURL(final URL url) {
Assert.notNull(url, "URL must be not null");
final String protocol = url.getProtocol();
return (URL_PROTOCOL_VFSFILE.equals(protocol) || //
URL_PROTOCOL_VFS.equals(protocol));
}
/**
* 提供的URL是否为jar包URL 协议包括 "jar", "zip", "vfszip" "wsjar".
*
* @param url {@link URL}
* @return 是否为jar包URL
*/
public static boolean isJarURL(final URL url) {
Assert.notNull(url, "URL must be not null");
final String protocol = url.getProtocol();
return (URL_PROTOCOL_JAR.equals(protocol) || //
URL_PROTOCOL_ZIP.equals(protocol) || //
URL_PROTOCOL_VFSZIP.equals(protocol) || //
URL_PROTOCOL_WSJAR.equals(protocol));
}
/**
* 提供的URL是否为Jar文件URL 判断依据为file协议且扩展名为.jar
*
* @param url the URL to check
* @return whether the URL has been identified as a JAR file URL
* @since 4.1
*/
public static boolean isJarFileURL(final URL url) {
Assert.notNull(url, "URL must be not null");
return (URL_PROTOCOL_FILE.equals(url.getProtocol()) && //
url.getPath().toLowerCase().endsWith(FileNameUtil.EXT_JAR));
}
}

View File

@ -190,7 +190,7 @@ public final class Props extends Properties implements TypeGetter<CharSequence>
* @since 5.5.2
*/
public void load(final URL url) {
load(new UrlResource(url));
load(ResourceUtil.getResource(url));
}
/**