diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8be224144..dbb114a61 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -22,6 +22,7 @@
* 【core 】 SpringUtil增加publishEvent重载(pr#2139@Github)
* 【core 】 DateUtil增加rangeContains、rangeNotContains(pr#537@Gitee)
* 【core 】 Resource增加isModified默认方法
+* 【core 】 增加VfsResource
### 🐞Bug修复
* 【core 】 修复ChineseDate农历获取正月出现数组越界BUG(issue#2112@Github)
diff --git a/hutool-core/src/main/java/cn/hutool/core/io/resource/UrlResource.java b/hutool-core/src/main/java/cn/hutool/core/io/resource/UrlResource.java
index a6692e2cc..21f24b2ef 100644
--- a/hutool-core/src/main/java/cn/hutool/core/io/resource/UrlResource.java
+++ b/hutool-core/src/main/java/cn/hutool/core/io/resource/UrlResource.java
@@ -7,6 +7,7 @@ import cn.hutool.core.util.URLUtil;
import java.io.File;
import java.io.InputStream;
import java.io.Serializable;
+import java.net.URI;
import java.net.URL;
/**
@@ -22,6 +23,15 @@ public class UrlResource implements Resource, Serializable{
protected String name;
//-------------------------------------------------------------------------------------- Constructor start
+ /**
+ * 构造
+ * @param uri URI
+ * @since 5.7.21
+ */
+ public UrlResource(URI uri) {
+ this(URLUtil.url(uri), null);
+ }
+
/**
* 构造
* @param url URL
@@ -37,7 +47,7 @@ public class UrlResource implements Resource, Serializable{
*/
public UrlResource(URL url, String name) {
this.url = url;
- if(null != url && URLUtil.isFileURL(url)){
+ if(null != url && URLUtil.URL_PROTOCOL_FILE.equals(url.getProtocol())){
this.lastModified = FileUtil.file(url).lastModified();
}
this.name = ObjectUtil.defaultIfNull(name, () -> (null != url ? FileUtil.getName(url.getPath()) : null));
diff --git a/hutool-core/src/main/java/cn/hutool/core/io/resource/VfsResource.java b/hutool-core/src/main/java/cn/hutool/core/io/resource/VfsResource.java
new file mode 100755
index 000000000..2295d97c2
--- /dev/null
+++ b/hutool-core/src/main/java/cn/hutool/core/io/resource/VfsResource.java
@@ -0,0 +1,107 @@
+package cn.hutool.core.io.resource;
+
+import cn.hutool.core.lang.Assert;
+import cn.hutool.core.util.ClassLoaderUtil;
+import cn.hutool.core.util.ReflectUtil;
+
+import java.io.InputStream;
+import java.lang.reflect.Method;
+import java.net.URL;
+
+/**
+ * VFS资源封装
+ * 支持VFS 3.x on JBoss AS 6+,JBoss AS 7 and WildFly 8+
+ * 参考:org.springframework.core.io.VfsUtils
+ *
+ * @author looly, Spring
+ * @since 5.7.21
+ */
+public class VfsResource implements Resource {
+ private static final String VFS3_PKG = "org.jboss.vfs.";
+
+ private static final Method VIRTUAL_FILE_METHOD_EXISTS;
+ private static final Method VIRTUAL_FILE_METHOD_GET_INPUT_STREAM;
+ private static final Method VIRTUAL_FILE_METHOD_GET_SIZE;
+ 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;
+
+ static {
+ Class> virtualFile = ClassLoaderUtil.loadClass(VFS3_PKG + "VirtualFile");
+ try {
+ VIRTUAL_FILE_METHOD_EXISTS = virtualFile.getMethod("exists");
+ VIRTUAL_FILE_METHOD_GET_INPUT_STREAM = virtualFile.getMethod("openStream");
+ VIRTUAL_FILE_METHOD_GET_SIZE = virtualFile.getMethod("getSize");
+ 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");
+ } catch (NoSuchMethodException ex) {
+ throw new IllegalStateException("Could not detect JBoss VFS infrastructure", ex);
+ }
+ }
+
+ /**
+ * org.jboss.vfs.VirtualFile实例对象
+ */
+ private final Object virtualFile;
+ private final long lastModified;
+
+ /**
+ * 构造
+ *
+ * @param resource org.jboss.vfs.VirtualFile实例对象
+ */
+ public VfsResource(Object resource) {
+ Assert.notNull(resource, "VirtualFile must not be null");
+ this.virtualFile = resource;
+ this.lastModified = getLastModified();
+ }
+
+ /**
+ * VFS文件是否存在
+ *
+ * @return 文件是否存在
+ */
+ public boolean exists() {
+ return ReflectUtil.invoke(virtualFile, VIRTUAL_FILE_METHOD_EXISTS);
+ }
+
+ @Override
+ public String getName() {
+ return ReflectUtil.invoke(virtualFile, VIRTUAL_FILE_METHOD_GET_NAME);
+ }
+
+ @Override
+ public URL getUrl() {
+ return ReflectUtil.invoke(virtualFile, VIRTUAL_FILE_METHOD_TO_URL);
+ }
+
+ @Override
+ public InputStream getStream() {
+ return ReflectUtil.invoke(virtualFile, VIRTUAL_FILE_METHOD_GET_INPUT_STREAM);
+ }
+
+ @Override
+ public boolean isModified() {
+ return this.lastModified != getLastModified();
+ }
+
+ /**
+ * 获得VFS文件最后修改时间
+ *
+ * @return 最后修改时间
+ */
+ public long getLastModified() {
+ return ReflectUtil.invoke(virtualFile, VIRTUAL_FILE_METHOD_GET_LAST_MODIFIED);
+ }
+
+ /**
+ * 获取VFS文件大小
+ *
+ * @return VFS文件大小
+ */
+ public long size() {
+ return ReflectUtil.invoke(virtualFile, VIRTUAL_FILE_METHOD_GET_SIZE);
+ }
+
+}
diff --git a/hutool-core/src/main/java/cn/hutool/core/util/URLUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/URLUtil.java
index 90d424835..fde460ff2 100644
--- a/hutool-core/src/main/java/cn/hutool/core/util/URLUtil.java
+++ b/hutool-core/src/main/java/cn/hutool/core/util/URLUtil.java
@@ -95,6 +95,26 @@ public class URLUtil extends URLEncodeUtil {
*/
public static final String WAR_URL_SEPARATOR = "*/";
+ /**
+ * 将{@link URI}转换为{@link URL}
+ *
+ * @param uri {@link URI}
+ * @return URL对象
+ * @see URI#toURL()
+ * @throws UtilException {@link MalformedURLException}包装,URI格式有问题时抛出
+ * @since 5.7.21
+ */
+ public static URL url(URI uri) throws UtilException{
+ if(null == uri){
+ return null;
+ }
+ try {
+ return uri.toURL();
+ } catch (MalformedURLException e) {
+ throw new UtilException(e);
+ }
+ }
+
/**
* 通过一个字符串形式的URL地址创建URL对象
*
@@ -114,7 +134,9 @@ public class URLUtil extends URLEncodeUtil {
* @since 4.1.1
*/
public static URL url(String url, URLStreamHandler handler) {
- Assert.notNull(url, "URL must not be null");
+ if(null == url){
+ return null;
+ }
// 兼容Spring的ClassPath路径
if (url.startsWith(CLASSPATH_URL_PREFIX)) {
@@ -142,6 +164,9 @@ public class URLUtil extends URLEncodeUtil {
* @since 5.5.2
*/
public static URI getStringURI(CharSequence content) {
+ if(null == content){
+ return null;
+ }
final String contentStr = StrUtil.addPrefixIfNot(content, "string:///");
return URI.create(contentStr);
}