mirror of
https://gitee.com/dromara/hutool.git
synced 2025-04-24 18:04:54 +08:00
add code
This commit is contained in:
parent
7dd8eced41
commit
ec966de41c
@ -23,9 +23,11 @@ import org.dromara.hutool.core.io.file.PathUtil;
|
||||
import org.dromara.hutool.core.io.resource.Resource;
|
||||
import org.dromara.hutool.core.io.stream.FastByteArrayOutputStream;
|
||||
import org.dromara.hutool.core.io.stream.LimitedInputStream;
|
||||
import org.dromara.hutool.core.lang.Assert;
|
||||
import org.dromara.hutool.core.net.url.URLUtil;
|
||||
import org.dromara.hutool.core.text.CharUtil;
|
||||
import org.dromara.hutool.core.text.StrUtil;
|
||||
import org.dromara.hutool.core.util.ByteUtil;
|
||||
import org.dromara.hutool.core.text.CharUtil;
|
||||
import org.dromara.hutool.core.util.CharsetUtil;
|
||||
import org.dromara.hutool.core.util.ObjUtil;
|
||||
|
||||
@ -37,6 +39,7 @@ import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipInputStream;
|
||||
@ -985,6 +988,32 @@ public class ZipUtil {
|
||||
return fileNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取对应URL路径的jar文件,支持包括file://xxx这类路径<br>
|
||||
* 来自:org.springframework.core.io.support.PathMatchingResourcePatternResolver#getJarFile
|
||||
*
|
||||
* @param jarFileUrl jar文件路径
|
||||
* @return {@link JarFile}
|
||||
* @throws IORuntimeException IO异常
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public static JarFile ofJar(String jarFileUrl) throws IORuntimeException{
|
||||
Assert.notBlank(jarFileUrl, "Jar file url is blank!");
|
||||
|
||||
if(jarFileUrl.startsWith(URLUtil.FILE_URL_PREFIX)){
|
||||
try{
|
||||
jarFileUrl = URLUtil.toURI(jarFileUrl).getSchemeSpecificPart();
|
||||
} catch (final HutoolException e){
|
||||
jarFileUrl = jarFileUrl.substring(URLUtil.FILE_URL_PREFIX.length());
|
||||
}
|
||||
}
|
||||
try {
|
||||
return new JarFile(jarFileUrl);
|
||||
} catch (final IOException e) {
|
||||
throw new IORuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------- Private method start
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* 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.io.resource;
|
||||
|
||||
import org.dromara.hutool.core.compress.ZipUtil;
|
||||
import org.dromara.hutool.core.io.IORuntimeException;
|
||||
import org.dromara.hutool.core.net.url.URLUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.JarURLConnection;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
/**
|
||||
* Jar包资源对象
|
||||
*
|
||||
* @author looly
|
||||
*/
|
||||
public class JarResource extends UrlResource {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param uri JAR的URI
|
||||
*/
|
||||
public JarResource(final URI uri) {
|
||||
super(uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param url JAR的URL
|
||||
*/
|
||||
public JarResource(final URL url) {
|
||||
super(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param url JAR的URL
|
||||
* @param name 资源名称
|
||||
*/
|
||||
public JarResource(final URL url, final String name) {
|
||||
super(url, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取URL对应的{@link JarFile}对象
|
||||
*
|
||||
* @return {@link JarFile}
|
||||
* @throws IORuntimeException IO异常
|
||||
*/
|
||||
public JarFile getJarFile() throws IORuntimeException {
|
||||
try {
|
||||
return doGetJarFile();
|
||||
} catch (final IOException e) {
|
||||
throw new IORuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取{@link JarFile}<br>
|
||||
* 首席按通过openConnection方式获取,如果得到的不是{@link JarURLConnection},<br>
|
||||
* 则尝试去除WAR、JAR等协议分隔符,裁剪分隔符前段来直接获取{@link JarFile}。
|
||||
*
|
||||
* @return {@link JarFile}
|
||||
* @throws IOException IO异常
|
||||
*/
|
||||
private JarFile doGetJarFile() throws IOException {
|
||||
final URLConnection con = getUrl().openConnection();
|
||||
if (con instanceof JarURLConnection) {
|
||||
final JarURLConnection jarCon = (JarURLConnection) con;
|
||||
return jarCon.getJarFile();
|
||||
} else {
|
||||
final String urlFile = getUrl().getFile();
|
||||
int separatorIndex = urlFile.indexOf(URLUtil.WAR_URL_SEPARATOR);
|
||||
if (separatorIndex == -1) {
|
||||
separatorIndex = urlFile.indexOf(URLUtil.JAR_URL_SEPARATOR);
|
||||
}
|
||||
if (separatorIndex != -1) {
|
||||
return ZipUtil.ofJar(urlFile.substring(0, separatorIndex));
|
||||
} else {
|
||||
return new JarFile(urlFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -53,9 +53,9 @@ public class MultiResource implements Resource, Iterable<Resource>, Iterator<Res
|
||||
* @param resources 资源列表
|
||||
*/
|
||||
public MultiResource(final Collection<Resource> resources) {
|
||||
if(resources instanceof List) {
|
||||
this.resources = (List<Resource>)resources;
|
||||
}else {
|
||||
if (resources instanceof List) {
|
||||
this.resources = (List<Resource>) resources;
|
||||
} else {
|
||||
this.resources = ListUtil.of(resources);
|
||||
}
|
||||
}
|
||||
@ -138,6 +138,7 @@ public class MultiResource implements Resource, Iterable<Resource>, Iterator<Res
|
||||
|
||||
/**
|
||||
* 增加资源
|
||||
*
|
||||
* @param resource 资源
|
||||
* @return this
|
||||
*/
|
||||
@ -146,4 +147,16 @@ public class MultiResource implements Resource, Iterable<Resource>, Iterator<Res
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加多个资源
|
||||
*
|
||||
* @param iterable 资源列表
|
||||
* @return this
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public MultiResource addAll(final Iterable<? extends Resource> iterable) {
|
||||
iterable.forEach((this::add));
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,167 @@
|
||||
/*
|
||||
* 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.io.resource;
|
||||
|
||||
import org.dromara.hutool.core.collection.iter.EnumerationIter;
|
||||
import org.dromara.hutool.core.compress.ZipUtil;
|
||||
import org.dromara.hutool.core.io.IORuntimeException;
|
||||
import org.dromara.hutool.core.io.IoUtil;
|
||||
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.IOException;
|
||||
import java.net.JarURLConnection;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.zip.ZipException;
|
||||
|
||||
public class ResourceFinder {
|
||||
|
||||
private final ClassLoader classLoader;
|
||||
private final AntPathMatcher pathMatcher;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param classLoader 类加载器,用于定义查找资源的范围
|
||||
*/
|
||||
public ResourceFinder(final ClassLoader classLoader) {
|
||||
this.classLoader = classLoader;
|
||||
this.pathMatcher = new AntPathMatcher();
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找给定表达式对应的资源
|
||||
*
|
||||
* @param locationPattern 路径表达式
|
||||
* @return {@link MultiResource}
|
||||
*/
|
||||
public MultiResource find(final String locationPattern) {
|
||||
// 根目录
|
||||
final String rootDirPath = determineRootDir(locationPattern);
|
||||
// 子表达式
|
||||
final String subPattern = locationPattern.substring(rootDirPath.length());
|
||||
|
||||
final MultiResource result = new MultiResource();
|
||||
// 遍历根目录下所有资源,并过滤保留符合条件的资源
|
||||
for (final Resource rootResource : ResourceUtil.getResources(rootDirPath, classLoader)) {
|
||||
if (URLUtil.isJarURL(rootResource.getUrl())) {
|
||||
try {
|
||||
result.addAll(findInJar(rootResource, subPattern));
|
||||
} catch (final IOException e) {
|
||||
throw new IORuntimeException(e);
|
||||
}
|
||||
} else {
|
||||
result.addAll(findInDir(rootResource, subPattern));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找jar包中的资源
|
||||
*
|
||||
* @param rootResource 根资源,为jar包文件
|
||||
* @param subPattern 子表达式,如 *.xml
|
||||
* @return 符合条件的资源
|
||||
* @throws IOException IO异常
|
||||
*/
|
||||
protected MultiResource findInJar(final Resource 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;
|
||||
|
||||
if (conn instanceof JarURLConnection) {
|
||||
final JarURLConnection jarCon = (JarURLConnection) conn;
|
||||
URLUtil.useCachesIfNecessary(jarCon);
|
||||
jarFile = jarCon.getJarFile();
|
||||
final JarEntry jarEntry = jarCon.getJarEntry();
|
||||
rootEntryPath = (jarEntry != null ? jarEntry.getName() : StrUtil.EMPTY);
|
||||
closeJarFile = !jarCon.getUseCaches();
|
||||
} else {
|
||||
//
|
||||
final String urlFile = rootDirURL.getFile();
|
||||
try {
|
||||
int separatorIndex = urlFile.indexOf(URLUtil.WAR_URL_SEPARATOR);
|
||||
if (separatorIndex == -1) {
|
||||
separatorIndex = urlFile.indexOf(URLUtil.JAR_URL_SEPARATOR);
|
||||
}
|
||||
if (separatorIndex != -1) {
|
||||
jarFileUrl = urlFile.substring(0, separatorIndex);
|
||||
rootEntryPath = urlFile.substring(separatorIndex + 2); // both separators are 2 chars
|
||||
jarFile = ZipUtil.ofJar(jarFileUrl);
|
||||
} else {
|
||||
jarFile = new JarFile(urlFile);
|
||||
rootEntryPath = StrUtil.EMPTY;
|
||||
}
|
||||
closeJarFile = true;
|
||||
} catch (final ZipException ex) {
|
||||
return new MultiResource();
|
||||
}
|
||||
}
|
||||
|
||||
rootEntryPath = StrUtil.addSuffixIfNot(rootEntryPath, StrUtil.SLASH);
|
||||
// 遍历jar中的entry,筛选之
|
||||
final MultiResource result = new MultiResource();
|
||||
|
||||
try {
|
||||
String entryPath;
|
||||
for (final JarEntry entry : new EnumerationIter<>(jarFile.entries())) {
|
||||
entryPath = entry.getName();
|
||||
if (entryPath.startsWith(rootEntryPath)) {
|
||||
final String relativePath = entryPath.substring(rootEntryPath.length());
|
||||
if (pathMatcher.match(subPattern, relativePath)) {
|
||||
result.add(new UrlResource(URLUtil.getURL(rootDirURL, relativePath)));
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (closeJarFile) {
|
||||
IoUtil.closeQuietly(jarFile);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected MultiResource findInDir(final Resource rootResource, final String subPattern) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据给定的路径表达式,找到跟路径<br>
|
||||
* 根路径即不包含表达式的路径,如 "/WEB-INF/*.xml" 返回 "/WEB-INF/"
|
||||
*
|
||||
* @param location 路径表达式
|
||||
*/
|
||||
protected String determineRootDir(final String location) {
|
||||
final int prefixEnd = location.indexOf(':') + 1;
|
||||
int rootDirEnd = location.length();
|
||||
while (rootDirEnd > prefixEnd && pathMatcher.isPattern(location.substring(prefixEnd, rootDirEnd))) {
|
||||
rootDirEnd = location.lastIndexOf(CharUtil.SLASH, rootDirEnd - 2) + 1;
|
||||
}
|
||||
if (rootDirEnd == 0) {
|
||||
rootDirEnd = prefixEnd;
|
||||
}
|
||||
return location.substring(0, rootDirEnd);
|
||||
}
|
||||
}
|
@ -12,22 +12,23 @@
|
||||
|
||||
package org.dromara.hutool.core.io.resource;
|
||||
|
||||
import org.dromara.hutool.core.io.IORuntimeException;
|
||||
import org.dromara.hutool.core.io.file.FileUtil;
|
||||
import org.dromara.hutool.core.io.file.FileNameUtil;
|
||||
import org.dromara.hutool.core.net.NetUtil;
|
||||
import org.dromara.hutool.core.util.ObjUtil;
|
||||
import org.dromara.hutool.core.io.file.FileUtil;
|
||||
import org.dromara.hutool.core.net.url.URLUtil;
|
||||
import org.dromara.hutool.core.util.ObjUtil;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.io.Serializable;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* URL资源访问类
|
||||
* @author Looly
|
||||
*
|
||||
* @author Looly
|
||||
*/
|
||||
public class UrlResource implements Resource, Serializable{
|
||||
public class UrlResource implements Resource, Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
protected URL url;
|
||||
@ -35,8 +36,10 @@ public class UrlResource implements Resource, Serializable{
|
||||
protected String name;
|
||||
|
||||
//-------------------------------------------------------------------------------------- Constructor start
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param uri URI
|
||||
* @since 5.7.21
|
||||
*/
|
||||
@ -46,6 +49,7 @@ public class UrlResource implements Resource, Serializable{
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param url URL
|
||||
*/
|
||||
public UrlResource(final URL url) {
|
||||
@ -54,12 +58,13 @@ public class UrlResource implements Resource, Serializable{
|
||||
|
||||
/**
|
||||
* 构造
|
||||
* @param url URL,允许为空
|
||||
*
|
||||
* @param url URL,允许为空
|
||||
* @param name 资源名称
|
||||
*/
|
||||
public UrlResource(final URL url, final String name) {
|
||||
this.url = url;
|
||||
if(null != url && URLUtil.URL_PROTOCOL_FILE.equals(url.getProtocol())){
|
||||
if (null != url && URLUtil.URL_PROTOCOL_FILE.equals(url.getProtocol())) {
|
||||
this.lastModified = FileUtil.file(url).lastModified();
|
||||
}
|
||||
this.name = ObjUtil.defaultIfNull(name, () -> (null != url ? FileNameUtil.getName(url.getPath()) : null));
|
||||
@ -73,7 +78,7 @@ public class UrlResource implements Resource, Serializable{
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL getUrl(){
|
||||
public URL getUrl() {
|
||||
return this.url;
|
||||
}
|
||||
|
||||
@ -83,8 +88,8 @@ public class UrlResource implements Resource, Serializable{
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getStream() throws NoResourceException{
|
||||
if(null == this.url){
|
||||
public InputStream getStream() throws NoResourceException {
|
||||
if (null == this.url) {
|
||||
throw new NoResourceException("Resource URL is null!");
|
||||
}
|
||||
return URLUtil.getStream(url);
|
||||
@ -98,18 +103,31 @@ public class UrlResource implements Resource, Serializable{
|
||||
|
||||
/**
|
||||
* 获得File
|
||||
*
|
||||
* @return {@link File}
|
||||
*/
|
||||
public File getFile(){
|
||||
public File getFile() {
|
||||
return FileUtil.file(this.url);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回路径
|
||||
*
|
||||
* @return 返回URL路径
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return (null == this.url) ? "null" : this.url.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取相对于本资源的资源
|
||||
*
|
||||
* @param relativePath 相对路径
|
||||
* @return 子资源
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public UrlResource createRelative(final String relativePath) {
|
||||
return new UrlResource(URLUtil.getURL(getUrl(), relativePath));
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ import org.dromara.hutool.core.classloader.ClassLoaderUtil;
|
||||
import org.dromara.hutool.core.lang.Assert;
|
||||
import org.dromara.hutool.core.reflect.method.MethodUtil;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
@ -37,6 +38,7 @@ public class VfsResource implements Resource {
|
||||
private static final Method VIRTUAL_FILE_METHOD_GET_LAST_MODIFIED;
|
||||
private static final Method VIRTUAL_FILE_METHOD_TO_URL;
|
||||
private static final Method VIRTUAL_FILE_METHOD_GET_NAME;
|
||||
private static final Method VIRTUAL_FILE_METHOD_GET_PHYSICAL_FILE;
|
||||
|
||||
static {
|
||||
final Class<?> virtualFile = ClassLoaderUtil.loadClass(VFS3_PKG + "VirtualFile");
|
||||
@ -47,6 +49,7 @@ public class VfsResource implements Resource {
|
||||
VIRTUAL_FILE_METHOD_GET_LAST_MODIFIED = virtualFile.getMethod("getLastModified");
|
||||
VIRTUAL_FILE_METHOD_TO_URL = virtualFile.getMethod("toURL");
|
||||
VIRTUAL_FILE_METHOD_GET_NAME = virtualFile.getMethod("getName");
|
||||
VIRTUAL_FILE_METHOD_GET_PHYSICAL_FILE = virtualFile.getMethod("getPhysicalFile");
|
||||
} catch (final NoSuchMethodException ex) {
|
||||
throw new IllegalStateException("Could not detect JBoss VFS infrastructure", ex);
|
||||
}
|
||||
@ -117,4 +120,14 @@ public class VfsResource implements Resource {
|
||||
return MethodUtil.invoke(virtualFile, VIRTUAL_FILE_METHOD_GET_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取物理文件对象
|
||||
*
|
||||
* @return 物理文件对象
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public File getFile(){
|
||||
return MethodUtil.invoke(virtualFile, VIRTUAL_FILE_METHOD_GET_PHYSICAL_FILE);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -20,7 +20,6 @@ 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;
|
||||
import org.dromara.hutool.core.net.NetUtil;
|
||||
import org.dromara.hutool.core.text.StrUtil;
|
||||
import org.dromara.hutool.core.util.CharsetUtil;
|
||||
|
||||
@ -28,17 +27,9 @@ import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.JarURLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.net.URLStreamHandler;
|
||||
import java.net.*;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Map;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
/**
|
||||
* URL(Uniform Resource Locator)统一资源定位符相关工具类
|
||||
@ -52,10 +43,11 @@ import java.util.jar.JarFile;
|
||||
* protocol :// hostname[:port] / path / [:parameters][?query]#fragment
|
||||
* </pre>
|
||||
*
|
||||
* @author xiaoleilu
|
||||
* @author looly
|
||||
*/
|
||||
public class URLUtil {
|
||||
|
||||
// region const
|
||||
/**
|
||||
* 针对ClassPath路径的伪协议前缀(兼容Spring): "classpath:"
|
||||
*/
|
||||
@ -108,6 +100,7 @@ public class URLUtil {
|
||||
* WAR路径及内部文件路径分界符
|
||||
*/
|
||||
public static final String WAR_URL_SEPARATOR = "*/";
|
||||
// endregion
|
||||
|
||||
/**
|
||||
* 将{@link URI}转换为{@link URL}
|
||||
@ -215,6 +208,8 @@ public class URLUtil {
|
||||
}
|
||||
}
|
||||
|
||||
// region getURL
|
||||
|
||||
/**
|
||||
* 获得URL
|
||||
*
|
||||
@ -243,14 +238,34 @@ public class URLUtil {
|
||||
*
|
||||
* @param file URL对应的文件对象
|
||||
* @return URL
|
||||
* @throws HutoolException MalformedURLException
|
||||
* @throws IORuntimeException URL格式错误
|
||||
*/
|
||||
public static URL getURL(final File file) {
|
||||
Assert.notNull(file, "File is null !");
|
||||
try {
|
||||
return file.toURI().toURL();
|
||||
} catch (final MalformedURLException e) {
|
||||
throw new HutoolException(e, "Error occured when get URL!");
|
||||
throw new IORuntimeException(e, "Error occurred when get URL!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取相对于给定URL的新的URL<br>
|
||||
* 来自:org.springframework.core.io.UrlResource#createRelativeURL
|
||||
*
|
||||
* @param url 基础URL
|
||||
* @param relativePath 相对路径
|
||||
* @return 相对于URL的子路径URL
|
||||
* @throws IORuntimeException URL格式错误
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public static URL getURL(final URL url, String relativePath) throws HutoolException {
|
||||
// # 在文件路径中合法,但是在URL中非法,此处转义
|
||||
relativePath = StrUtil.replace(StrUtil.removePrefix(relativePath, StrUtil.SLASH), "#", "%23");
|
||||
try {
|
||||
return new URL(url, relativePath);
|
||||
} catch (final MalformedURLException e) {
|
||||
throw new IORuntimeException(e, "Error occurred when get URL!");
|
||||
}
|
||||
}
|
||||
|
||||
@ -259,7 +274,7 @@ public class URLUtil {
|
||||
*
|
||||
* @param files URL对应的文件对象
|
||||
* @return URL
|
||||
* @throws HutoolException MalformedURLException
|
||||
* @throws IORuntimeException URL格式错误
|
||||
*/
|
||||
public static URL[] getURLs(final File... files) {
|
||||
final URL[] urls = new URL[files.length];
|
||||
@ -268,11 +283,12 @@ public class URLUtil {
|
||||
urls[i] = files[i].toURI().toURL();
|
||||
}
|
||||
} catch (final MalformedURLException e) {
|
||||
throw new HutoolException(e, "Error occured when get URL!");
|
||||
throw new IORuntimeException(e, "Error occurred when get URL!");
|
||||
}
|
||||
|
||||
return urls;
|
||||
}
|
||||
// endregion
|
||||
|
||||
/**
|
||||
* 获取URL中域名部分,只保留URL中的协议(Protocol)、Host,其它为null。
|
||||
@ -351,6 +367,8 @@ public class URLUtil {
|
||||
return (null != path) ? path : url.getPath();
|
||||
}
|
||||
|
||||
// region toURI
|
||||
|
||||
/**
|
||||
* 转URL为URI
|
||||
*
|
||||
@ -409,6 +427,7 @@ public class URLUtil {
|
||||
throw new HutoolException(e);
|
||||
}
|
||||
}
|
||||
// endregion
|
||||
|
||||
/**
|
||||
* 提供的URL是否为文件<br>
|
||||
@ -482,21 +501,7 @@ public class URLUtil {
|
||||
return IoUtil.toReader(getStream(url), charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从URL中获取JarFile
|
||||
*
|
||||
* @param url URL
|
||||
* @return JarFile
|
||||
* @since 4.1.5
|
||||
*/
|
||||
public static JarFile getJarFile(final URL url) {
|
||||
try {
|
||||
final JarURLConnection urlConnection = (JarURLConnection) url.openConnection();
|
||||
return urlConnection.getJarFile();
|
||||
} catch (final IOException e) {
|
||||
throw new IORuntimeException(e);
|
||||
}
|
||||
}
|
||||
// region normalize
|
||||
|
||||
/**
|
||||
* 标准化URL字符串,包括:
|
||||
@ -593,6 +598,7 @@ public class URLUtil {
|
||||
}
|
||||
return protocol + domain + StrUtil.emptyIfNull(path) + StrUtil.emptyIfNull(params);
|
||||
}
|
||||
// endregion
|
||||
|
||||
/**
|
||||
* 将Map形式的Form表单数据转换为Url参数形式<br>
|
||||
@ -611,31 +617,7 @@ public class URLUtil {
|
||||
return UrlQuery.of(paramMap).build(charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定URL对应资源的内容长度,对于Http,其长度使用Content-Length头决定。
|
||||
*
|
||||
* @param url URL
|
||||
* @return 内容长度,未知返回-1
|
||||
* @throws IORuntimeException IO异常
|
||||
* @since 5.3.4
|
||||
*/
|
||||
public static long getContentLength(final URL url) throws IORuntimeException {
|
||||
if (null == url) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
URLConnection conn = null;
|
||||
try {
|
||||
conn = url.openConnection();
|
||||
return conn.getContentLengthLong();
|
||||
} catch (final IOException e) {
|
||||
throw new IORuntimeException(e);
|
||||
} finally {
|
||||
if (conn instanceof HttpURLConnection) {
|
||||
((HttpURLConnection) conn).disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
// region getDataUri
|
||||
|
||||
/**
|
||||
* Data URI Scheme封装,数据格式为Base64。data URI scheme 允许我们使用内联(inline-code)的方式在网页中包含数据,<br>
|
||||
@ -708,6 +690,7 @@ public class URLUtil {
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
// endregion
|
||||
|
||||
/**
|
||||
* 获取URL对应数据长度
|
||||
@ -732,16 +715,21 @@ public class URLUtil {
|
||||
} else {
|
||||
// 如果资源打在jar包中或来自网络,使用网络请求长度
|
||||
// issue#3226, 来自Spring的AbstractFileResolvingResource
|
||||
URLConnection conn = null;
|
||||
try {
|
||||
final URLConnection con = url.openConnection();
|
||||
useCachesIfNecessary(con);
|
||||
if (con instanceof HttpURLConnection) {
|
||||
final HttpURLConnection httpCon = (HttpURLConnection) con;
|
||||
conn = url.openConnection();
|
||||
useCachesIfNecessary(conn);
|
||||
if (conn instanceof HttpURLConnection) {
|
||||
final HttpURLConnection httpCon = (HttpURLConnection) conn;
|
||||
httpCon.setRequestMethod("HEAD");
|
||||
}
|
||||
return con.getContentLengthLong();
|
||||
return conn.getContentLengthLong();
|
||||
} catch (final IOException e) {
|
||||
throw new IORuntimeException(e);
|
||||
} finally {
|
||||
if (conn instanceof HttpURLConnection) {
|
||||
((HttpURLConnection) conn).disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,14 +16,13 @@ import org.dromara.hutool.core.classloader.ClassLoaderUtil;
|
||||
import org.dromara.hutool.core.collection.CollUtil;
|
||||
import org.dromara.hutool.core.collection.iter.EnumerationIter;
|
||||
import org.dromara.hutool.core.exception.ExceptionUtil;
|
||||
import org.dromara.hutool.core.exception.HutoolException;
|
||||
import org.dromara.hutool.core.io.IORuntimeException;
|
||||
import org.dromara.hutool.core.io.file.FileNameUtil;
|
||||
import org.dromara.hutool.core.io.resource.JarResource;
|
||||
import org.dromara.hutool.core.io.resource.ResourceUtil;
|
||||
import org.dromara.hutool.core.net.url.URLDecoder;
|
||||
import org.dromara.hutool.core.net.url.URLUtil;
|
||||
import org.dromara.hutool.core.text.StrUtil;
|
||||
import org.dromara.hutool.core.text.CharUtil;
|
||||
import org.dromara.hutool.core.text.StrUtil;
|
||||
import org.dromara.hutool.core.util.CharsetUtil;
|
||||
import org.dromara.hutool.core.util.SystemUtil;
|
||||
|
||||
@ -268,7 +267,7 @@ public class ClassScanner implements Serializable {
|
||||
scanFile(new File(URLDecoder.decode(url.getFile(), this.charset)), null);
|
||||
break;
|
||||
case "jar":
|
||||
scanJar(URLUtil.getJarFile(url));
|
||||
scanJar(new JarResource(url).getJarFile());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -350,7 +350,7 @@ public class AntPathMatcher {
|
||||
pos += skipped;
|
||||
skipped = skipSegment(path, pos, pattDir);
|
||||
if (skipped < pattDir.length()) {
|
||||
return (skipped > 0 || (pattDir.length() > 0 && isWildcardChar(pattDir.charAt(0))));
|
||||
return (skipped > 0 || (!pattDir.isEmpty() && isWildcardChar(pattDir.charAt(0))));
|
||||
}
|
||||
pos += skipped;
|
||||
}
|
||||
@ -657,9 +657,9 @@ public class AntPathMatcher {
|
||||
|
||||
|
||||
/**
|
||||
* Tests whether or not a string matches against a pattern via a {@link Pattern}.
|
||||
* Tests whether a string matches against a pattern via a {@link Pattern}.
|
||||
* <p>The pattern may contain special characters: '*' means zero or more characters; '?' means one and
|
||||
* only one character; '{' and '}' indicate a URI template pattern. For example <tt>/users/{user}</tt>.
|
||||
* only one character; '{' and '}' indicate a URI template pattern. For example {@code /users/{user}}.
|
||||
*/
|
||||
protected static class AntPathStringMatcher {
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user