From 8a0e477f693fea71042df3bb5bca6df15d7cb8b1 Mon Sep 17 00:00:00 2001
From: Looly
Date: Thu, 21 Sep 2023 21:14:00 +0800
Subject: [PATCH] add session
---
.../hutool/core/cache/SimpleCache.java | 11 +
.../hutool/core/spi/ListServiceLoader.java | 39 +--
.../hutool/core/spi/MapServiceLoader.java | 21 +-
.../hutool/core/spi/ServiceLoader.java | 27 +-
.../hutool/extra/pinyin/PinyinUtil.java | 10 +
.../pinyin/engine/PinyinEngineFactory.java | 21 ++
.../HoubbEngine.java} | 8 +-
.../{houbbpinyin => houbb}/package-info.java | 2 +-
.../dromara/hutool/extra/ssh/Connector.java | 15 +-
.../extra/ssh/JschRuntimeException.java | 48 ---
.../org/dromara/hutool/extra/ssh/Session.java | 25 ++
.../hutool/extra/ssh/SshException.java | 85 ++++++
.../ganymed/GanymedSession.java} | 108 ++++---
.../ssh/{ => engine/jsch}/ChannelType.java | 2 +-
.../extra/ssh/engine/jsch/JschSession.java | 283 ++++++++++++++++++
.../{ => engine/jsch}/JschSessionPool.java | 2 +-
.../extra/ssh/{ => engine/jsch}/JschUtil.java | 44 +--
.../extra/ssh/{ => engine/jsch}/Sftp.java | 29 +-
.../extra/ssh/engine/jsch/package-info.java | 2 +-
.../extra/ssh/{ => engine/sshj}/SshjSftp.java | 2 +-
.../hutool/extra/tokenizer/TokenizerUtil.java | 10 +
.../engine/TokenizerEngineFactory.java | 25 +-
...ra.hutool.extra.pinyin.engine.PinyinEngine | 2 +-
.../org/dromara/hutool/extra/ftp/FtpTest.java | 2 +-
.../hutool/extra/pinyin/Bopomofo4jTest.java | 4 +-
.../hutool/extra/pinyin/HoubbPinyinTest.java | 4 +-
.../hutool/extra/pinyin/JpinyinTest.java | 4 +-
.../hutool/extra/pinyin/Pinyin4jTest.java | 4 +-
.../hutool/extra/pinyin/TinyPinyinTest.java | 4 +-
.../hutool/extra/ssh/JschUtilTest.java | 4 +-
.../dromara/hutool/extra/ssh/SftpTest.java | 1 +
.../extra/tokenizer/TokenizerUtilTest.java | 24 +-
.../org/dromara/hutool/http/HttpUtil.java | 31 +-
.../client/engine/ClientEngineFactory.java | 21 ++
.../http/client/HttpClient4EngineTest.java | 4 +-
.../http/client/HttpClient5EngineTest.java | 4 +-
.../hutool/http/client/Issue3240Test.java | 7 +-
.../hutool/http/client/IssueI7ZRJUTest.java | 2 +-
.../hutool/http/client/JdkEngineTest.java | 4 +-
39 files changed, 707 insertions(+), 238 deletions(-)
rename hutool-extra/src/main/java/org/dromara/hutool/extra/pinyin/engine/{houbbpinyin/HoubbPinyinEngine.java => houbb/HoubbEngine.java} (89%)
rename hutool-extra/src/main/java/org/dromara/hutool/extra/pinyin/engine/{houbbpinyin => houbb}/package-info.java (93%)
delete mode 100644 hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/JschRuntimeException.java
create mode 100644 hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/Session.java
create mode 100644 hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/SshException.java
rename hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/{GanymedUtil.java => engine/ganymed/GanymedSession.java} (52%)
rename hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/{ => engine/jsch}/ChannelType.java (96%)
create mode 100644 hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/engine/jsch/JschSession.java
rename hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/{ => engine/jsch}/JschSessionPool.java (98%)
rename hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/{ => engine/jsch}/JschUtil.java (93%)
rename hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/{ => engine/jsch}/Sftp.java (97%)
rename hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/{ => engine/sshj}/SshjSftp.java (99%)
diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/cache/SimpleCache.java b/hutool-core/src/main/java/org/dromara/hutool/core/cache/SimpleCache.java
index 14296a2d7..addc9fc91 100644
--- a/hutool-core/src/main/java/org/dromara/hutool/core/cache/SimpleCache.java
+++ b/hutool-core/src/main/java/org/dromara/hutool/core/cache/SimpleCache.java
@@ -21,6 +21,7 @@ import org.dromara.hutool.core.map.WeakConcurrentMap;
import java.io.Serializable;
import java.util.Iterator;
+import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.locks.Lock;
@@ -28,6 +29,7 @@ import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.function.Predicate;
+import java.util.stream.Collectors;
/**
* 简单缓存,无超时实现,默认使用{@link WeakConcurrentMap}实现缓存自动清理
@@ -212,4 +214,13 @@ public class SimpleCache implements Iterable>, Serializabl
}
});
}
+
+ /**
+ * 获取所有键
+ *
+ * @return 所有键
+ */
+ public List keys(){
+ return this.rawMap.keySet().stream().map(Mutable::get).collect(Collectors.toList());
+ }
}
diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/spi/ListServiceLoader.java b/hutool-core/src/main/java/org/dromara/hutool/core/spi/ListServiceLoader.java
index b07282c4c..a7e5495f0 100644
--- a/hutool-core/src/main/java/org/dromara/hutool/core/spi/ListServiceLoader.java
+++ b/hutool-core/src/main/java/org/dromara/hutool/core/spi/ListServiceLoader.java
@@ -14,6 +14,7 @@ package org.dromara.hutool.core.spi;
import org.dromara.hutool.core.cache.SimpleCache;
import org.dromara.hutool.core.classloader.ClassLoaderUtil;
+import org.dromara.hutool.core.collection.ListUtil;
import org.dromara.hutool.core.io.IORuntimeException;
import org.dromara.hutool.core.io.resource.MultiResource;
import org.dromara.hutool.core.io.resource.Resource;
@@ -24,10 +25,7 @@ import org.dromara.hutool.core.text.StrUtil;
import java.io.BufferedReader;
import java.io.IOException;
import java.nio.charset.Charset;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
+import java.util.*;
/**
* 列表类型的服务加载器,用于替换JDK提供的{@link java.util.ServiceLoader}
@@ -136,6 +134,11 @@ public class ListServiceLoader extends AbsServiceLoader {
return this.serviceNames.size();
}
+ @Override
+ public List getServiceNames(){
+ return ListUtil.view(this.serviceNames);
+ }
+
/**
* 获取指定服务的实现类
*
@@ -148,7 +151,12 @@ public class ListServiceLoader extends AbsServiceLoader {
return null;
}
- return ClassLoaderUtil.loadClass(serviceClassName);
+ return getServiceClass(serviceClassName);
+ }
+
+ @Override
+ public Class getServiceClass(final String serviceName) {
+ return ClassLoaderUtil.loadClass(serviceName);
}
/**
@@ -162,7 +170,12 @@ public class ListServiceLoader extends AbsServiceLoader {
if (null == serviceClassName) {
return null;
}
- return getServiceByName(serviceClassName);
+ return getService(serviceClassName);
+ }
+
+ @Override
+ public S getService(final String serviceName) {
+ return this.serviceCache.get(serviceName, () -> createService(serviceName));
}
@Override
@@ -177,7 +190,7 @@ public class ListServiceLoader extends AbsServiceLoader {
@Override
public S next() {
- return getServiceByName(nameIter.next());
+ return getService(nameIter.next());
}
};
}
@@ -223,7 +236,7 @@ public class ListServiceLoader extends AbsServiceLoader {
line = line.substring(0, ci);
}
line = StrUtil.trim(line);
- if (line.length() > 0) {
+ if (!line.isEmpty()) {
// 检查行
checkLine(resource, lineNo, line);
// 不覆盖模式
@@ -272,16 +285,6 @@ public class ListServiceLoader extends AbsServiceLoader {
throw new SPIException(this.serviceClass + ":" + resource.getUrl() + ":" + lineNo + ": " + msg);
}
- /**
- * 获取指定class名对应的服务,使用缓存,多次调用只返回相同的服务对象
- *
- * @param serviceClassName 服务名称
- * @return 服务对象
- */
- private S getServiceByName(final String serviceClassName) {
- return this.serviceCache.get(serviceClassName, () -> createService(serviceClassName));
- }
-
/**
* 创建服务,无缓存
*
diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/spi/MapServiceLoader.java b/hutool-core/src/main/java/org/dromara/hutool/core/spi/MapServiceLoader.java
index f9106efa9..10ee1ebfe 100644
--- a/hutool-core/src/main/java/org/dromara/hutool/core/spi/MapServiceLoader.java
+++ b/hutool-core/src/main/java/org/dromara/hutool/core/spi/MapServiceLoader.java
@@ -14,6 +14,7 @@ package org.dromara.hutool.core.spi;
import org.dromara.hutool.core.cache.SimpleCache;
import org.dromara.hutool.core.classloader.ClassLoaderUtil;
+import org.dromara.hutool.core.collection.ListUtil;
import org.dromara.hutool.core.io.resource.ResourceUtil;
import org.dromara.hutool.core.reflect.ConstructorUtil;
import org.dromara.hutool.core.text.StrUtil;
@@ -21,6 +22,7 @@ import org.dromara.hutool.core.text.StrUtil;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Iterator;
+import java.util.List;
import java.util.Properties;
/**
@@ -128,12 +130,12 @@ public class MapServiceLoader extends AbsServiceLoader {
return this.serviceProperties.size();
}
- /**
- * 获取指定服务的实现类
- *
- * @param serviceName 服务名称
- * @return 服务名称对应的实现类
- */
+ @Override
+ public List getServiceNames() {
+ return ListUtil.view(this.serviceCache.keys());
+ }
+
+ @Override
public Class getServiceClass(final String serviceName) {
final String serviceClassName = this.serviceProperties.getProperty(serviceName);
if (StrUtil.isBlank(serviceClassName)) {
@@ -143,12 +145,7 @@ public class MapServiceLoader extends AbsServiceLoader {
return ClassLoaderUtil.loadClass(serviceClassName);
}
- /**
- * 获取指定名称对应的服务,使用缓存,多次调用只返回相同的服务对象
- *
- * @param serviceName 服务名称
- * @return 服务对象
- */
+ @Override
public S getService(final String serviceName) {
return this.serviceCache.get(serviceName, () -> createService(serviceName));
}
diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/spi/ServiceLoader.java b/hutool-core/src/main/java/org/dromara/hutool/core/spi/ServiceLoader.java
index d4ae8a376..9ed71e499 100644
--- a/hutool-core/src/main/java/org/dromara/hutool/core/spi/ServiceLoader.java
+++ b/hutool-core/src/main/java/org/dromara/hutool/core/spi/ServiceLoader.java
@@ -12,6 +12,8 @@
package org.dromara.hutool.core.spi;
+import java.util.List;
+
/**
* SPI服务加载接口
* 用户实现此接口用于制定不同的服务加载方式
@@ -19,7 +21,7 @@ package org.dromara.hutool.core.spi;
* @param 服务对象类型
* @author looly
*/
-public interface ServiceLoader extends Iterable{
+public interface ServiceLoader extends Iterable {
/**
* 加载服务
@@ -32,4 +34,27 @@ public interface ServiceLoader extends Iterable{
* @return 总数
*/
int size();
+
+ /**
+ * 获取服务名称列表
+ *
+ * @return 服务名称列表
+ */
+ List getServiceNames();
+
+ /**
+ * 获取指定服务的实现类
+ *
+ * @param serviceName 服务名称
+ * @return 服务名称对应的实现类
+ */
+ Class getServiceClass(String serviceName);
+
+ /**
+ * 获取指定名称对应的服务
+ *
+ * @param serviceName 服务名称
+ * @return 服务对象
+ */
+ S getService(String serviceName);
}
diff --git a/hutool-extra/src/main/java/org/dromara/hutool/extra/pinyin/PinyinUtil.java b/hutool-extra/src/main/java/org/dromara/hutool/extra/pinyin/PinyinUtil.java
index 20e289245..6bfa00986 100644
--- a/hutool-extra/src/main/java/org/dromara/hutool/extra/pinyin/PinyinUtil.java
+++ b/hutool-extra/src/main/java/org/dromara/hutool/extra/pinyin/PinyinUtil.java
@@ -25,6 +25,16 @@ import org.dromara.hutool.extra.pinyin.engine.PinyinEngineFactory;
*/
public class PinyinUtil {
+ /**
+ * 创建拼音引擎
+ *
+ * @param engineName 引擎名称
+ * @return {@link PinyinEngine}
+ */
+ public static PinyinEngine createEngine(final String engineName) {
+ return PinyinEngineFactory.createEngine(engineName);
+ }
+
/**
* 获得全局单例的拼音引擎
*
diff --git a/hutool-extra/src/main/java/org/dromara/hutool/extra/pinyin/engine/PinyinEngineFactory.java b/hutool-extra/src/main/java/org/dromara/hutool/extra/pinyin/engine/PinyinEngineFactory.java
index 3a1099c5a..ee95c68fa 100644
--- a/hutool-extra/src/main/java/org/dromara/hutool/extra/pinyin/engine/PinyinEngineFactory.java
+++ b/hutool-extra/src/main/java/org/dromara/hutool/extra/pinyin/engine/PinyinEngineFactory.java
@@ -13,6 +13,7 @@
package org.dromara.hutool.extra.pinyin.engine;
import org.dromara.hutool.core.lang.Singleton;
+import org.dromara.hutool.core.spi.ServiceLoader;
import org.dromara.hutool.core.spi.SpiUtil;
import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.extra.pinyin.PinyinException;
@@ -47,6 +48,26 @@ public class PinyinEngineFactory {
return doCreateEngine();
}
+ /**
+ * 创建自定义引擎
+ *
+ * @param engineName 引擎名称,忽略大小写,如`Bopomofo4j`、`Houbb`、`JPinyin`、`Pinyin4j`、`TinyPinyin`
+ * @return 引擎
+ * @throws PinyinException 无对应名称的引擎
+ */
+ public static PinyinEngine createEngine(String engineName) throws PinyinException {
+ if (!StrUtil.endWithIgnoreCase(engineName, "Engine")) {
+ engineName = engineName + "Engine";
+ }
+ final ServiceLoader list = SpiUtil.loadList(PinyinEngine.class);
+ for (final String serviceName : list.getServiceNames()) {
+ if (StrUtil.endWithIgnoreCase(serviceName, engineName)) {
+ return list.getService(serviceName);
+ }
+ }
+ throw new PinyinException("No such engine named: " + engineName);
+ }
+
/**
* 根据用户引入的拼音引擎jar,自动创建对应的拼音引擎对象
* 推荐创建的引擎单例使用,此方法每次调用会返回新的引擎
diff --git a/hutool-extra/src/main/java/org/dromara/hutool/extra/pinyin/engine/houbbpinyin/HoubbPinyinEngine.java b/hutool-extra/src/main/java/org/dromara/hutool/extra/pinyin/engine/houbb/HoubbEngine.java
similarity index 89%
rename from hutool-extra/src/main/java/org/dromara/hutool/extra/pinyin/engine/houbbpinyin/HoubbPinyinEngine.java
rename to hutool-extra/src/main/java/org/dromara/hutool/extra/pinyin/engine/houbb/HoubbEngine.java
index 947659e34..70e36ae8d 100644
--- a/hutool-extra/src/main/java/org/dromara/hutool/extra/pinyin/engine/houbbpinyin/HoubbPinyinEngine.java
+++ b/hutool-extra/src/main/java/org/dromara/hutool/extra/pinyin/engine/houbb/HoubbEngine.java
@@ -10,7 +10,7 @@
* See the Mulan PSL v2 for more details.
*/
-package org.dromara.hutool.extra.pinyin.engine.houbbpinyin;
+package org.dromara.hutool.extra.pinyin.engine.houbb;
import org.dromara.hutool.extra.pinyin.engine.PinyinEngine;
import com.github.houbb.pinyin.constant.enums.PinyinStyleEnum;
@@ -35,7 +35,7 @@ import com.github.houbb.pinyin.util.PinyinHelper;
*
* @author looly
*/
-public class HoubbPinyinEngine implements PinyinEngine {
+public class HoubbEngine implements PinyinEngine {
/**
* 汉字拼音输出的格式
@@ -45,7 +45,7 @@ public class HoubbPinyinEngine implements PinyinEngine {
/**
* 构造
*/
- public HoubbPinyinEngine() {
+ public HoubbEngine() {
this(null);
}
@@ -54,7 +54,7 @@ public class HoubbPinyinEngine implements PinyinEngine {
*
* @param format 格式
*/
- public HoubbPinyinEngine(final PinyinStyleEnum format) {
+ public HoubbEngine(final PinyinStyleEnum format) {
init(format);
}
diff --git a/hutool-extra/src/main/java/org/dromara/hutool/extra/pinyin/engine/houbbpinyin/package-info.java b/hutool-extra/src/main/java/org/dromara/hutool/extra/pinyin/engine/houbb/package-info.java
similarity index 93%
rename from hutool-extra/src/main/java/org/dromara/hutool/extra/pinyin/engine/houbbpinyin/package-info.java
rename to hutool-extra/src/main/java/org/dromara/hutool/extra/pinyin/engine/houbb/package-info.java
index e18a8e74a..3ddde54b9 100644
--- a/hutool-extra/src/main/java/org/dromara/hutool/extra/pinyin/engine/houbbpinyin/package-info.java
+++ b/hutool-extra/src/main/java/org/dromara/hutool/extra/pinyin/engine/houbb/package-info.java
@@ -29,4 +29,4 @@
*
* @author looly
*/
-package org.dromara.hutool.extra.pinyin.engine.houbbpinyin;
+package org.dromara.hutool.extra.pinyin.engine.houbb;
diff --git a/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/Connector.java b/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/Connector.java
index 010c8b23e..d7b712f3d 100644
--- a/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/Connector.java
+++ b/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/Connector.java
@@ -15,13 +15,12 @@ package org.dromara.hutool.extra.ssh;
/**
* 连接者对象,提供一些连接的基本信息
*
- * @author Luxiaolei
- *
+ * @author looly
*/
public class Connector {
private String host;
private int port;
- private String user;
+ private String user = "root";
private String password;
private String group;
@@ -34,9 +33,9 @@ public class Connector {
/**
* 构造
*
- * @param user 用户名
+ * @param user 用户名
* @param password 密码
- * @param group 组
+ * @param group 组
*/
public Connector(final String user, final String password, final String group) {
this.user = user;
@@ -47,9 +46,9 @@ public class Connector {
/**
* 构造
*
- * @param host 主机名
- * @param port 端口
- * @param user 用户名
+ * @param host 主机名
+ * @param port 端口
+ * @param user 用户名
* @param password 密码
*/
public Connector(final String host, final int port, final String user, final String password) {
diff --git a/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/JschRuntimeException.java b/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/JschRuntimeException.java
deleted file mode 100644
index 8bbb08696..000000000
--- a/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/JschRuntimeException.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * 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.extra.ssh;
-
-import org.dromara.hutool.core.exception.ExceptionUtil;
-import org.dromara.hutool.core.text.StrUtil;
-
-/**
- * Jsch异常
- * @author xiaoleilu
- */
-public class JschRuntimeException extends RuntimeException{
- private static final long serialVersionUID = 8247610319171014183L;
-
- public JschRuntimeException(final Throwable e) {
- super(ExceptionUtil.getMessage(e), e);
- }
-
- public JschRuntimeException(final String message) {
- super(message);
- }
-
- public JschRuntimeException(final String messageTemplate, final Object... params) {
- super(StrUtil.format(messageTemplate, params));
- }
-
- public JschRuntimeException(final String message, final Throwable throwable) {
- super(message, throwable);
- }
-
- public JschRuntimeException(final String message, final Throwable throwable, final boolean enableSuppression, final boolean writableStackTrace) {
- super(message, throwable, enableSuppression, writableStackTrace);
- }
-
- public JschRuntimeException(final Throwable throwable, final String messageTemplate, final Object... params) {
- super(StrUtil.format(messageTemplate, params), throwable);
- }
-}
diff --git a/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/Session.java b/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/Session.java
new file mode 100644
index 000000000..9f4380817
--- /dev/null
+++ b/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/Session.java
@@ -0,0 +1,25 @@
+/*
+ * 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.extra.ssh;
+
+import org.dromara.hutool.core.func.Wrapper;
+
+import java.io.Closeable;
+
+/**
+ * SSH Session抽象
+ *
+ * @author looly
+ */
+public interface Session extends Wrapper
*
- * @param session Session会话
* @param cmd 命令
* @param charset 发送和读取内容的编码
* @param errStream 错误信息输出到的位置
* @return 执行返回结果
*/
- public static String exec(final Session session, final String cmd, final Charset charset, final OutputStream errStream) {
+ public String exec(final String cmd, final Charset charset, final OutputStream errStream) {
final String result;
try {
- session.execCommand(cmd, charset.name());
- result = IoUtil.read(new StreamGobbler(session.getStdout()), charset);
+ this.raw.execCommand(cmd, charset.name());
+ result = IoUtil.read(new StreamGobbler(this.raw.getStdout()), charset);
// 错误输出
- IoUtil.copy(new StreamGobbler(session.getStderr()), errStream);
+ IoUtil.copy(new StreamGobbler(this.raw.getStderr()), errStream);
} catch (final IOException e) {
throw new IORuntimeException(e);
- } finally {
- close(session);
}
return result;
}
@@ -106,39 +93,50 @@ public class GanymedUtil {
* 此方法单次发送一个命令到服务端,自动读取环境变量,执行结束后自动关闭Session,可能产生阻塞。
*
*
- * @param session Session会话
* @param cmd 命令
* @param charset 发送和读取内容的编码
* @param errStream 错误信息输出到的位置
* @return 执行返回结果
*/
- public static String execByShell(final Session session, final String cmd, final Charset charset, final OutputStream errStream) {
+ public String execByShell(final String cmd, final Charset charset, final OutputStream errStream) {
final String result;
try {
- session.requestDumbPTY();
- IoUtil.write(session.getStdin(), charset, true, cmd);
+ this.raw.requestDumbPTY();
+ IoUtil.write(this.raw.getStdin(), charset, true, cmd);
- result = IoUtil.read(new StreamGobbler(session.getStdout()), charset);
+ result = IoUtil.read(new StreamGobbler(this.raw.getStdout()), charset);
if(null != errStream){
// 错误输出
- IoUtil.copy(new StreamGobbler(session.getStderr()), errStream);
+ IoUtil.copy(new StreamGobbler(this.raw.getStderr()), errStream);
}
} catch (final IOException e) {
throw new IORuntimeException(e);
- } finally {
- close(session);
}
return result;
}
/**
- * 关闭会话
+ * 初始化并打开新的Session
*
- * @param session 会话通道
+ * @param connector {@link Connector},保存连接和验证信息等
+ * @return {@link ch.ethz.ssh2.Session}
*/
- public static void close(final Session session) {
- if (session != null) {
- session.close();
+ private static ch.ethz.ssh2.Session openSession(final Connector connector) {
+
+ // 建立连接
+ final Connection conn = new Connection(connector.getHost(), connector.getPort());
+ try {
+ conn.connect();
+ } catch (final IOException e) {
+ throw new IORuntimeException(e);
+ }
+
+ // 打开会话
+ try {
+ conn.authenticateWithPassword(connector.getUser(), connector.getPassword());
+ return conn.openSession();
+ } catch (final IOException e) {
+ throw new IORuntimeException(e);
}
}
}
diff --git a/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/ChannelType.java b/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/engine/jsch/ChannelType.java
similarity index 96%
rename from hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/ChannelType.java
rename to hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/engine/jsch/ChannelType.java
index 673ee03d6..e35545d97 100644
--- a/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/ChannelType.java
+++ b/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/engine/jsch/ChannelType.java
@@ -10,7 +10,7 @@
* See the Mulan PSL v2 for more details.
*/
-package org.dromara.hutool.extra.ssh;
+package org.dromara.hutool.extra.ssh.engine.jsch;
/**
* Jsch支持的Channel类型
diff --git a/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/engine/jsch/JschSession.java b/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/engine/jsch/JschSession.java
new file mode 100644
index 000000000..ab907a169
--- /dev/null
+++ b/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/engine/jsch/JschSession.java
@@ -0,0 +1,283 @@
+/*
+ * 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.extra.ssh.engine.jsch;
+
+import com.jcraft.jsch.*;
+import org.dromara.hutool.core.io.IORuntimeException;
+import org.dromara.hutool.core.io.IoUtil;
+import org.dromara.hutool.core.util.ByteUtil;
+import org.dromara.hutool.core.util.CharsetUtil;
+import org.dromara.hutool.extra.ssh.Connector;
+import org.dromara.hutool.extra.ssh.Session;
+import org.dromara.hutool.extra.ssh.SshException;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.charset.Charset;
+
+/**
+ * Jsch Session封装
+ */
+public class JschSession implements Session {
+
+ private final com.jcraft.jsch.Session raw;
+
+ /**
+ * 构造
+ *
+ * @param connector {@link Connector},保存连接和验证信息等
+ */
+ public JschSession(final Connector connector) {
+ this(openSession(connector));
+ }
+
+ /**
+ * 构造
+ *
+ * @param raw {@link com.jcraft.jsch.Session}
+ */
+ public JschSession(final com.jcraft.jsch.Session raw) {
+ this.raw = raw;
+ }
+
+ @Override
+ public Object getRaw() {
+ return raw;
+ }
+
+ @Override
+ public void close() throws IOException {
+ if (raw != null && raw.isConnected()) {
+ raw.disconnect();
+ }
+ }
+
+ /**
+ * 绑定端口到本地。 一个会话可绑定多个端口
+ *
+ * @param remoteHost 远程主机
+ * @param remotePort 远程端口
+ * @param localHost 本地主机
+ * @param localPort 本地端口
+ * @return 成功与否
+ * @throws SshException 端口绑定失败异常
+ */
+ public boolean bindPort(final String remoteHost, final int remotePort, final String localHost, final int localPort) throws SshException {
+ if (this.raw != null && this.raw.isConnected()) {
+ try {
+ this.raw.setPortForwardingL(localHost, localPort, remoteHost, remotePort);
+ } catch (final JSchException e) {
+ throw new SshException(e, "From [{}:{}] mapping to [{}:{}] error!", remoteHost, remotePort, localHost, localPort);
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * 绑定ssh服务端的serverPort端口, 到host主机的port端口上.
+ * 即数据从ssh服务端的serverPort端口, 流经ssh客户端, 达到host:port上.
+ *
+ * @param bindPort ssh服务端上要被绑定的端口
+ * @param host 转发到的host
+ * @param port host上的端口
+ * @return 成功与否
+ * @throws SshException 端口绑定失败异常
+ */
+ public boolean bindRemotePort(final int bindPort, final String host, final int port) throws SshException {
+ if (this.raw != null && this.raw.isConnected()) {
+ try {
+ this.raw.setPortForwardingR(bindPort, host, port);
+ } catch (final JSchException e) {
+ throw new SshException(e, "From [{}] mapping to [{}] error!", bindPort, port);
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * 解除端口映射
+ *
+ * @param localPort 需要解除的本地端口
+ */
+ public void unBindPort(final int localPort) {
+ try {
+ this.raw.delPortForwardingL(localPort);
+ } catch (final JSchException e) {
+ throw new SshException(e);
+ }
+ }
+
+ /**
+ * 创建Channel连接
+ *
+ * @param channelType 通道类型,可以是shell或sftp等,见{@link ChannelType}
+ * @return {@link Channel}
+ */
+ public Channel createChannel(final ChannelType channelType) {
+ final Channel channel;
+ try {
+ if (!this.raw.isConnected()) {
+ this.raw.connect();
+ }
+ channel = this.raw.openChannel(channelType.getValue());
+ } catch (final JSchException e) {
+ throw new SshException(e);
+ }
+ return channel;
+ }
+
+ /**
+ * 打开Shell连接
+ *
+ * @return {@link ChannelShell}
+ */
+ public ChannelShell openShell() {
+ return (ChannelShell) openChannel(ChannelType.SHELL);
+ }
+
+ /**
+ * 打开Channel连接
+ *
+ * @param channelType 通道类型,可以是shell或sftp等,见{@link ChannelType}
+ * @return {@link Channel}
+ */
+ public Channel openChannel(final ChannelType channelType) {
+ return openChannel(channelType, 0);
+ }
+
+ /**
+ * 打开Channel连接
+ *
+ * @param channelType 通道类型,可以是shell或sftp等,见{@link ChannelType}
+ * @param timeout 连接超时时长,单位毫秒
+ * @return {@link Channel}
+ */
+ public Channel openChannel(final ChannelType channelType, final int timeout) {
+ final Channel channel = createChannel(channelType);
+ try {
+ channel.connect(Math.max(timeout, 0));
+ } catch (final JSchException e) {
+ throw new SshException(e);
+ }
+ return channel;
+ }
+
+ /**
+ * 执行Shell命令
+ *
+ * @param cmd 命令
+ * @param charset 发送和读取内容的编码
+ * @return {@link ChannelExec}
+ */
+ public String exec(final String cmd, final Charset charset) {
+ return exec(cmd, charset, System.err);
+ }
+
+ /**
+ * 执行Shell命令(使用EXEC方式)
+ *
+ * 此方法单次发送一个命令到服务端,不读取环境变量,执行结束后自动关闭channel,不会产生阻塞。
+ *
+ *
+ * @param cmd 命令
+ * @param charset 发送和读取内容的编码
+ * @param errStream 错误信息输出到的位置
+ * @return 执行结果内容
+ * @since 4.3.1
+ */
+ public String exec(final String cmd, Charset charset, final OutputStream errStream) {
+ if (null == charset) {
+ charset = CharsetUtil.UTF_8;
+ }
+ final ChannelExec channel = (ChannelExec) createChannel(ChannelType.EXEC);
+ channel.setCommand(ByteUtil.toBytes(cmd, charset));
+ channel.setInputStream(null);
+ channel.setErrStream(errStream);
+ InputStream in = null;
+ try {
+ channel.connect();
+ in = channel.getInputStream();
+ return IoUtil.read(in, charset);
+ } catch (final IOException e) {
+ throw new IORuntimeException(e);
+ } catch (final JSchException e) {
+ throw new SshException(e);
+ } finally {
+ IoUtil.closeQuietly(in);
+ if (channel.isConnected()) {
+ channel.disconnect();
+ }
+ }
+ }
+
+ /**
+ * 执行Shell命令
+ *
+ * 此方法单次发送一个命令到服务端,自动读取环境变量,执行结束后自动关闭channel,不会产生阻塞。
+ *
+ *
+ * @param cmd 命令
+ * @param charset 发送和读取内容的编码
+ * @return {@link ChannelExec}
+ * @since 5.2.5
+ */
+ public static String execByShell(final String cmd, final Charset charset) {
+ final ChannelShell shell = openShell();
+ // 开始连接
+ shell.setPty(true);
+ OutputStream out = null;
+ InputStream in = null;
+ try {
+ out = shell.getOutputStream();
+ in = shell.getInputStream();
+
+ out.write(ByteUtil.toBytes(cmd, charset));
+ out.flush();
+
+ return IoUtil.read(in, charset);
+ } catch (final IOException e) {
+ throw new IORuntimeException(e);
+ } finally {
+ IoUtil.closeQuietly(out);
+ IoUtil.closeQuietly(in);
+ if (shell.isConnected()) {
+ shell.disconnect();
+ }
+ }
+ }
+
+ /**
+ * 创建{@link com.jcraft.jsch.Session}
+ *
+ * @param connector {@link Connector},保存连接和验证信息等
+ * @return {@link com.jcraft.jsch.Session}
+ */
+ private static com.jcraft.jsch.Session openSession(final Connector connector) {
+ final JSch jsch = new JSch();
+ final com.jcraft.jsch.Session session;
+ try {
+ session = jsch.getSession(connector.getUser(), connector.getHost(), connector.getPort());
+ } catch (final JSchException e) {
+ throw new SshException(e);
+ }
+
+ session.setPassword(connector.getPassword());
+ // 设置第一次登录的时候提示,可选值:(ask | yes | no)
+ session.setConfig("StrictHostKeyChecking", "no");
+
+ return session;
+ }
+}
diff --git a/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/JschSessionPool.java b/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/engine/jsch/JschSessionPool.java
similarity index 98%
rename from hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/JschSessionPool.java
rename to hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/engine/jsch/JschSessionPool.java
index 7ffd6b6c5..92a4df792 100644
--- a/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/JschSessionPool.java
+++ b/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/engine/jsch/JschSessionPool.java
@@ -10,7 +10,7 @@
* See the Mulan PSL v2 for more details.
*/
-package org.dromara.hutool.extra.ssh;
+package org.dromara.hutool.extra.ssh.engine.jsch;
import org.dromara.hutool.core.cache.SimpleCache;
import org.dromara.hutool.core.text.StrUtil;
diff --git a/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/JschUtil.java b/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/engine/jsch/JschUtil.java
similarity index 93%
rename from hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/JschUtil.java
rename to hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/engine/jsch/JschUtil.java
index 446394538..6f3aed9db 100644
--- a/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/JschUtil.java
+++ b/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/engine/jsch/JschUtil.java
@@ -10,8 +10,9 @@
* See the Mulan PSL v2 for more details.
*/
-package org.dromara.hutool.extra.ssh;
+package org.dromara.hutool.extra.ssh.engine.jsch;
+import com.jcraft.jsch.*;
import org.dromara.hutool.core.io.IORuntimeException;
import org.dromara.hutool.core.io.IoUtil;
import org.dromara.hutool.core.lang.Assert;
@@ -19,7 +20,8 @@ import org.dromara.hutool.core.net.LocalPortGenerator;
import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.core.util.ByteUtil;
import org.dromara.hutool.core.util.CharsetUtil;
-import com.jcraft.jsch.*;
+import org.dromara.hutool.extra.ssh.Connector;
+import org.dromara.hutool.extra.ssh.SshException;
import java.io.IOException;
import java.io.InputStream;
@@ -112,7 +114,7 @@ public class JschUtil {
session.setTimeout(timeout);
session.connect(timeout);
} catch (final JSchException e) {
- throw new JschRuntimeException(e);
+ throw new SshException(e);
}
return session;
}
@@ -132,7 +134,7 @@ public class JschUtil {
try {
session.connect();
} catch (final JSchException e) {
- throw new JschRuntimeException(e);
+ throw new SshException(e);
}
return session;
}
@@ -154,7 +156,7 @@ public class JschUtil {
session.setTimeout(timeout);
session.connect(timeout);
} catch (final JSchException e) {
- throw new JschRuntimeException(e);
+ throw new SshException(e);
}
return session;
}
@@ -198,7 +200,7 @@ public class JschUtil {
try {
jsch.addIdentity(privateKeyPath, passphrase);
} catch (final JSchException e) {
- throw new JschRuntimeException(e);
+ throw new SshException(e);
}
return createSession(jsch, sshHost, sshPort, sshUser);
@@ -231,7 +233,7 @@ public class JschUtil {
try {
session = jsch.getSession(sshUser, sshHost, sshPort);
} catch (final JSchException e) {
- throw new JschRuntimeException(e);
+ throw new SshException(e);
}
// 设置第一次登录的时候提示,可选值:(ask | yes | no)
@@ -248,9 +250,9 @@ public class JschUtil {
* @param remotePort 远程端口
* @param localPort 本地端口
* @return 成功与否
- * @throws JschRuntimeException 端口绑定失败异常
+ * @throws SshException 端口绑定失败异常
*/
- public static boolean bindPort(final Session session, final String remoteHost, final int remotePort, final int localPort) throws JschRuntimeException {
+ public static boolean bindPort(final Session session, final String remoteHost, final int remotePort, final int localPort) throws SshException {
return bindPort(session, remoteHost, remotePort, "127.0.0.1", localPort);
}
@@ -263,15 +265,15 @@ public class JschUtil {
* @param localHost 本地主机
* @param localPort 本地端口
* @return 成功与否
- * @throws JschRuntimeException 端口绑定失败异常
+ * @throws SshException 端口绑定失败异常
* @since 5.7.8
*/
- public static boolean bindPort(final Session session, final String remoteHost, final int remotePort, final String localHost, final int localPort) throws JschRuntimeException {
+ public static boolean bindPort(final Session session, final String remoteHost, final int remotePort, final String localHost, final int localPort) throws SshException {
if (session != null && session.isConnected()) {
try {
session.setPortForwardingL(localHost, localPort, remoteHost, remotePort);
} catch (final JSchException e) {
- throw new JschRuntimeException(e, "From [{}:{}] mapping to [{}:{}] error!", remoteHost, remotePort, localHost, localPort);
+ throw new SshException(e, "From [{}:{}] mapping to [{}:{}] error!", remoteHost, remotePort, localHost, localPort);
}
return true;
}
@@ -288,15 +290,15 @@ public class JschUtil {
* @param host 转发到的host
* @param port host上的端口
* @return 成功与否
- * @throws JschRuntimeException 端口绑定失败异常
+ * @throws SshException 端口绑定失败异常
* @since 5.4.2
*/
- public static boolean bindRemotePort(final Session session, final int bindPort, final String host, final int port) throws JschRuntimeException {
+ public static boolean bindRemotePort(final Session session, final int bindPort, final String host, final int port) throws SshException {
if (session != null && session.isConnected()) {
try {
session.setPortForwardingR(bindPort, host, port);
} catch (final JSchException e) {
- throw new JschRuntimeException(e, "From [{}] mapping to [{}] error!", bindPort, port);
+ throw new SshException(e, "From [{}] mapping to [{}] error!", bindPort, port);
}
return true;
}
@@ -314,7 +316,7 @@ public class JschUtil {
try {
session.delPortForwardingL(localPort);
} catch (final JSchException e) {
- throw new JschRuntimeException(e);
+ throw new SshException(e);
}
}
@@ -325,9 +327,9 @@ public class JschUtil {
* @param remoteHost 远程主机
* @param remotePort 远程端口
* @return 映射后的本地端口
- * @throws JschRuntimeException 连接异常
+ * @throws SshException 连接异常
*/
- public static int openAndBindPortToLocal(final Connector sshConn, final String remoteHost, final int remotePort) throws JschRuntimeException {
+ public static int openAndBindPortToLocal(final Connector sshConn, final String remoteHost, final int remotePort) throws SshException {
final Session session = openSession(sshConn.getHost(), sshConn.getPort(), sshConn.getUser(), sshConn.getPassword());
final int localPort = generateLocalPort();
bindPort(session, remoteHost, remotePort, localPort);
@@ -419,7 +421,7 @@ public class JschUtil {
try {
channel.connect(Math.max(timeout, 0));
} catch (final JSchException e) {
- throw new JschRuntimeException(e);
+ throw new SshException(e);
}
return channel;
}
@@ -440,7 +442,7 @@ public class JschUtil {
}
channel = session.openChannel(channelType.getValue());
} catch (final JSchException e) {
- throw new JschRuntimeException(e);
+ throw new SshException(e);
}
return channel;
}
@@ -487,7 +489,7 @@ public class JschUtil {
} catch (final IOException e) {
throw new IORuntimeException(e);
} catch (final JSchException e) {
- throw new JschRuntimeException(e);
+ throw new SshException(e);
} finally {
IoUtil.closeQuietly(in);
close(channel);
diff --git a/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/Sftp.java b/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/engine/jsch/Sftp.java
similarity index 97%
rename from hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/Sftp.java
rename to hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/engine/jsch/Sftp.java
index ca01a0983..e2f543809 100644
--- a/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/Sftp.java
+++ b/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/engine/jsch/Sftp.java
@@ -10,7 +10,7 @@
* See the Mulan PSL v2 for more details.
*/
-package org.dromara.hutool.extra.ssh;
+package org.dromara.hutool.extra.ssh.engine.jsch;
import org.dromara.hutool.core.collection.CollUtil;
import org.dromara.hutool.core.collection.ListUtil;
@@ -26,6 +26,7 @@ import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpATTRS;
import com.jcraft.jsch.SftpException;
import com.jcraft.jsch.SftpProgressMonitor;
+import org.dromara.hutool.extra.ssh.SshException;
import java.io.File;
import java.io.InputStream;
@@ -219,7 +220,7 @@ public class Sftp extends AbstractFtp {
try {
channel.setFilenameEncoding(charset.toString());
} catch (final SftpException e) {
- throw new JschRuntimeException(e);
+ throw new SshException(e);
}
this.channel = channel;
}
@@ -261,7 +262,7 @@ public class Sftp extends AbstractFtp {
try {
return getClient().pwd();
} catch (final SftpException e) {
- throw new JschRuntimeException(e);
+ throw new SshException(e);
}
}
@@ -275,7 +276,7 @@ public class Sftp extends AbstractFtp {
try {
return getClient().getHome();
} catch (final SftpException e) {
- throw new JschRuntimeException(e);
+ throw new SshException(e);
}
}
@@ -365,7 +366,7 @@ public class Sftp extends AbstractFtp {
});
} catch (final SftpException e) {
if (!StrUtil.startWithIgnoreCase(e.getMessage(), "No such file")) {
- throw new JschRuntimeException(e);
+ throw new SshException(e);
}
// 文件不存在忽略
}
@@ -382,7 +383,7 @@ public class Sftp extends AbstractFtp {
getClient().mkdir(dir);
return true;
} catch (final SftpException e) {
- throw new JschRuntimeException(e);
+ throw new SshException(e);
}
}
@@ -435,7 +436,7 @@ public class Sftp extends AbstractFtp {
try {
getClient().rm(filePath);
} catch (final SftpException e) {
- throw new JschRuntimeException(e);
+ throw new SshException(e);
}
return true;
}
@@ -459,7 +460,7 @@ public class Sftp extends AbstractFtp {
try {
list = channel.ls(channel.pwd());
} catch (final SftpException e) {
- throw new JschRuntimeException(e);
+ throw new SshException(e);
}
String fileName;
@@ -483,7 +484,7 @@ public class Sftp extends AbstractFtp {
channel.rmdir(dirPath);
return true;
} catch (final SftpException e) {
- throw new JschRuntimeException(e);
+ throw new SshException(e);
}
}
@@ -583,7 +584,7 @@ public class Sftp extends AbstractFtp {
try {
getClient().put(srcFilePath, destPath, monitor, mode.ordinal());
} catch (final SftpException e) {
- throw new JschRuntimeException(e);
+ throw new SshException(e);
}
return this;
}
@@ -602,7 +603,7 @@ public class Sftp extends AbstractFtp {
try {
getClient().put(srcStream, destPath, monitor, mode.ordinal());
} catch (final SftpException e) {
- throw new JschRuntimeException(e);
+ throw new SshException(e);
}
return this;
}
@@ -630,7 +631,7 @@ public class Sftp extends AbstractFtp {
* @param destDir 本地目录
*/
@Override
- public void recursiveDownloadFolder(final String sourcePath, final File destDir) throws JschRuntimeException {
+ public void recursiveDownloadFolder(final String sourcePath, final File destDir) throws SshException {
String fileName;
String srcFile;
File destFile;
@@ -665,7 +666,7 @@ public class Sftp extends AbstractFtp {
try {
getClient().get(src, dest);
} catch (final SftpException e) {
- throw new JschRuntimeException(e);
+ throw new SshException(e);
}
return this;
}
@@ -682,7 +683,7 @@ public class Sftp extends AbstractFtp {
try {
getClient().get(src, out);
} catch (final SftpException e) {
- throw new JschRuntimeException(e);
+ throw new SshException(e);
}
return this;
}
diff --git a/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/engine/jsch/package-info.java b/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/engine/jsch/package-info.java
index 05812837a..c795f94d4 100644
--- a/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/engine/jsch/package-info.java
+++ b/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/engine/jsch/package-info.java
@@ -11,7 +11,7 @@
*/
/**
- * SSH 引擎封装
+ * Jsch(http://www.jcraft.com/jsch/) 引擎封装
*
* @author looly
*/
diff --git a/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/SshjSftp.java b/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/engine/sshj/SshjSftp.java
similarity index 99%
rename from hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/SshjSftp.java
rename to hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/engine/sshj/SshjSftp.java
index 259b1aefa..80e80baef 100644
--- a/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/SshjSftp.java
+++ b/hutool-extra/src/main/java/org/dromara/hutool/extra/ssh/engine/sshj/SshjSftp.java
@@ -10,7 +10,7 @@
* See the Mulan PSL v2 for more details.
*/
-package org.dromara.hutool.extra.ssh;
+package org.dromara.hutool.extra.ssh.engine.sshj;
import org.dromara.hutool.core.collection.CollUtil;
import org.dromara.hutool.core.io.IoUtil;
diff --git a/hutool-extra/src/main/java/org/dromara/hutool/extra/tokenizer/TokenizerUtil.java b/hutool-extra/src/main/java/org/dromara/hutool/extra/tokenizer/TokenizerUtil.java
index 6c9b3bb04..bed29c21d 100644
--- a/hutool-extra/src/main/java/org/dromara/hutool/extra/tokenizer/TokenizerUtil.java
+++ b/hutool-extra/src/main/java/org/dromara/hutool/extra/tokenizer/TokenizerUtil.java
@@ -41,4 +41,14 @@ public class TokenizerUtil {
public static TokenizerEngine getEngine() {
return TokenizerEngineFactory.getEngine();
}
+
+ /**
+ * 创建对应名称的分词引擎对象
+ *
+ * @param engineName 引擎名称
+ * @return {@link TokenizerEngine}
+ */
+ public static TokenizerEngine createEngine(final String engineName) {
+ return TokenizerEngineFactory.createEngine(engineName);
+ }
}
diff --git a/hutool-extra/src/main/java/org/dromara/hutool/extra/tokenizer/engine/TokenizerEngineFactory.java b/hutool-extra/src/main/java/org/dromara/hutool/extra/tokenizer/engine/TokenizerEngineFactory.java
index df9d966d6..afee973b7 100644
--- a/hutool-extra/src/main/java/org/dromara/hutool/extra/tokenizer/engine/TokenizerEngineFactory.java
+++ b/hutool-extra/src/main/java/org/dromara/hutool/extra/tokenizer/engine/TokenizerEngineFactory.java
@@ -13,6 +13,7 @@
package org.dromara.hutool.extra.tokenizer.engine;
import org.dromara.hutool.core.lang.Singleton;
+import org.dromara.hutool.core.spi.ServiceLoader;
import org.dromara.hutool.core.spi.SpiUtil;
import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.extra.tokenizer.TokenizerException;
@@ -31,7 +32,7 @@ public class TokenizerEngineFactory {
*
* @return 单例的TokenizerEngine
*/
- public static TokenizerEngine getEngine(){
+ public static TokenizerEngine getEngine() {
final TokenizerEngine engine = Singleton.get(TokenizerEngine.class.getName(), TokenizerEngineFactory::createEngine);
LogUtil.debug("Use [{}] Tokenizer Engine As Default.", StrUtil.removeSuffix(engine.getClass().getSimpleName(), "Engine"));
return engine;
@@ -46,6 +47,26 @@ public class TokenizerEngineFactory {
return doCreateEngine();
}
+ /**
+ * 创建自定义引擎
+ *
+ * @param engineName 引擎名称,忽略大小写,如`Analysis`、`Ansj`、`HanLP`、`IKAnalyzer`、`Jcseg`、`Jieba`、`Mmseg`、`Mynlp`、`Word`
+ * @return 引擎
+ * @throws TokenizerException 无对应名称的引擎
+ */
+ public static TokenizerEngine createEngine(String engineName) throws TokenizerException {
+ if (!StrUtil.endWithIgnoreCase(engineName, "Engine")) {
+ engineName = engineName + "Engine";
+ }
+ final ServiceLoader list = SpiUtil.loadList(TokenizerEngine.class);
+ for (final String serviceName : list.getServiceNames()) {
+ if (StrUtil.endWithIgnoreCase(serviceName, engineName)) {
+ return list.getService(serviceName);
+ }
+ }
+ throw new TokenizerException("No such engine named: " + engineName);
+ }
+
/**
* 根据用户引入的分词引擎jar,自动创建对应的分词引擎对象
*
@@ -53,7 +74,7 @@ public class TokenizerEngineFactory {
*/
private static TokenizerEngine doCreateEngine() {
final TokenizerEngine engine = SpiUtil.loadFirstAvailable(TokenizerEngine.class);
- if(null != engine){
+ if (null != engine) {
return engine;
}
diff --git a/hutool-extra/src/main/resources/META-INF/services/org.dromara.hutool.extra.pinyin.engine.PinyinEngine b/hutool-extra/src/main/resources/META-INF/services/org.dromara.hutool.extra.pinyin.engine.PinyinEngine
index b6764a734..07e159b18 100644
--- a/hutool-extra/src/main/resources/META-INF/services/org.dromara.hutool.extra.pinyin.engine.PinyinEngine
+++ b/hutool-extra/src/main/resources/META-INF/services/org.dromara.hutool.extra.pinyin.engine.PinyinEngine
@@ -14,4 +14,4 @@ org.dromara.hutool.extra.pinyin.engine.tinypinyin.TinyPinyinEngine
org.dromara.hutool.extra.pinyin.engine.jpinyin.JPinyinEngine
org.dromara.hutool.extra.pinyin.engine.pinyin4j.Pinyin4jEngine
org.dromara.hutool.extra.pinyin.engine.bopomofo4j.Bopomofo4jEngine
-org.dromara.hutool.extra.pinyin.engine.houbbpinyin.HoubbPinyinEngine
+org.dromara.hutool.extra.pinyin.engine.houbb.HoubbEngine
diff --git a/hutool-extra/src/test/java/org/dromara/hutool/extra/ftp/FtpTest.java b/hutool-extra/src/test/java/org/dromara/hutool/extra/ftp/FtpTest.java
index 50b8882c8..10d95be66 100644
--- a/hutool-extra/src/test/java/org/dromara/hutool/extra/ftp/FtpTest.java
+++ b/hutool-extra/src/test/java/org/dromara/hutool/extra/ftp/FtpTest.java
@@ -16,7 +16,7 @@ import org.apache.commons.net.ftp.FTPSClient;
import org.dromara.hutool.core.io.IoUtil;
import org.dromara.hutool.core.io.file.FileUtil;
import org.dromara.hutool.core.lang.Console;
-import org.dromara.hutool.extra.ssh.Sftp;
+import org.dromara.hutool.extra.ssh.engine.jsch.Sftp;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
diff --git a/hutool-extra/src/test/java/org/dromara/hutool/extra/pinyin/Bopomofo4jTest.java b/hutool-extra/src/test/java/org/dromara/hutool/extra/pinyin/Bopomofo4jTest.java
index 45e014e91..1b0f0da53 100644
--- a/hutool-extra/src/test/java/org/dromara/hutool/extra/pinyin/Bopomofo4jTest.java
+++ b/hutool-extra/src/test/java/org/dromara/hutool/extra/pinyin/Bopomofo4jTest.java
@@ -12,13 +12,13 @@
package org.dromara.hutool.extra.pinyin;
-import org.dromara.hutool.extra.pinyin.engine.bopomofo4j.Bopomofo4jEngine;
+import org.dromara.hutool.extra.pinyin.engine.PinyinEngine;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
public class Bopomofo4jTest {
- final Bopomofo4jEngine engine = new Bopomofo4jEngine();
+ final PinyinEngine engine = PinyinUtil.createEngine("bopomofo4j");
@Test
public void getFirstLetterByBopomofo4jTest(){
diff --git a/hutool-extra/src/test/java/org/dromara/hutool/extra/pinyin/HoubbPinyinTest.java b/hutool-extra/src/test/java/org/dromara/hutool/extra/pinyin/HoubbPinyinTest.java
index 8a0baee76..948f0504a 100644
--- a/hutool-extra/src/test/java/org/dromara/hutool/extra/pinyin/HoubbPinyinTest.java
+++ b/hutool-extra/src/test/java/org/dromara/hutool/extra/pinyin/HoubbPinyinTest.java
@@ -12,13 +12,13 @@
package org.dromara.hutool.extra.pinyin;
-import org.dromara.hutool.extra.pinyin.engine.houbbpinyin.HoubbPinyinEngine;
+import org.dromara.hutool.extra.pinyin.engine.PinyinEngine;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
public class HoubbPinyinTest {
- final HoubbPinyinEngine engine = new HoubbPinyinEngine();
+ final PinyinEngine engine = PinyinUtil.createEngine("houbb");
@Test
public void getFirstLetterTest(){
diff --git a/hutool-extra/src/test/java/org/dromara/hutool/extra/pinyin/JpinyinTest.java b/hutool-extra/src/test/java/org/dromara/hutool/extra/pinyin/JpinyinTest.java
index e498acf24..adda45c43 100644
--- a/hutool-extra/src/test/java/org/dromara/hutool/extra/pinyin/JpinyinTest.java
+++ b/hutool-extra/src/test/java/org/dromara/hutool/extra/pinyin/JpinyinTest.java
@@ -12,13 +12,13 @@
package org.dromara.hutool.extra.pinyin;
-import org.dromara.hutool.extra.pinyin.engine.jpinyin.JPinyinEngine;
+import org.dromara.hutool.extra.pinyin.engine.PinyinEngine;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
public class JpinyinTest {
- final JPinyinEngine engine = new JPinyinEngine();
+ final PinyinEngine engine = PinyinUtil.createEngine("jpinyin");
@Test
public void getFirstLetterByPinyin4jTest(){
diff --git a/hutool-extra/src/test/java/org/dromara/hutool/extra/pinyin/Pinyin4jTest.java b/hutool-extra/src/test/java/org/dromara/hutool/extra/pinyin/Pinyin4jTest.java
index 37acb1d38..ae1ec5a4a 100644
--- a/hutool-extra/src/test/java/org/dromara/hutool/extra/pinyin/Pinyin4jTest.java
+++ b/hutool-extra/src/test/java/org/dromara/hutool/extra/pinyin/Pinyin4jTest.java
@@ -12,13 +12,13 @@
package org.dromara.hutool.extra.pinyin;
-import org.dromara.hutool.extra.pinyin.engine.pinyin4j.Pinyin4jEngine;
+import org.dromara.hutool.extra.pinyin.engine.PinyinEngine;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
public class Pinyin4jTest {
- final Pinyin4jEngine engine = new Pinyin4jEngine();
+ final PinyinEngine engine = PinyinUtil.createEngine("pinyin4j");
@Test
public void getFirstLetterByPinyin4jTest(){
diff --git a/hutool-extra/src/test/java/org/dromara/hutool/extra/pinyin/TinyPinyinTest.java b/hutool-extra/src/test/java/org/dromara/hutool/extra/pinyin/TinyPinyinTest.java
index 7aae54849..320eca738 100644
--- a/hutool-extra/src/test/java/org/dromara/hutool/extra/pinyin/TinyPinyinTest.java
+++ b/hutool-extra/src/test/java/org/dromara/hutool/extra/pinyin/TinyPinyinTest.java
@@ -12,13 +12,13 @@
package org.dromara.hutool.extra.pinyin;
-import org.dromara.hutool.extra.pinyin.engine.tinypinyin.TinyPinyinEngine;
+import org.dromara.hutool.extra.pinyin.engine.PinyinEngine;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
public class TinyPinyinTest {
- final TinyPinyinEngine engine = new TinyPinyinEngine();
+ final PinyinEngine engine = PinyinUtil.createEngine("tinypinyin");
@Test
public void getFirstLetterByPinyin4jTest(){
diff --git a/hutool-extra/src/test/java/org/dromara/hutool/extra/ssh/JschUtilTest.java b/hutool-extra/src/test/java/org/dromara/hutool/extra/ssh/JschUtilTest.java
index 7c83af49a..76556ba22 100644
--- a/hutool-extra/src/test/java/org/dromara/hutool/extra/ssh/JschUtilTest.java
+++ b/hutool-extra/src/test/java/org/dromara/hutool/extra/ssh/JschUtilTest.java
@@ -15,6 +15,8 @@ package org.dromara.hutool.extra.ssh;
import org.dromara.hutool.core.io.IoUtil;
import org.dromara.hutool.core.lang.Console;
import com.jcraft.jsch.Session;
+import org.dromara.hutool.extra.ssh.engine.jsch.JschUtil;
+import org.dromara.hutool.extra.ssh.engine.jsch.Sftp;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
@@ -74,7 +76,7 @@ public class JschUtilTest {
Console.log("isConnected " + sftp.getClient().isConnected());
Console.log("打印pwd: " + sftp.pwd());
Console.log("cd / : " + sftp.cd("/"));
- }catch (final JschRuntimeException e) {
+ }catch (final SshException e) {
e.printStackTrace();
}
diff --git a/hutool-extra/src/test/java/org/dromara/hutool/extra/ssh/SftpTest.java b/hutool-extra/src/test/java/org/dromara/hutool/extra/ssh/SftpTest.java
index 2a361822c..7e887c1d1 100644
--- a/hutool-extra/src/test/java/org/dromara/hutool/extra/ssh/SftpTest.java
+++ b/hutool-extra/src/test/java/org/dromara/hutool/extra/ssh/SftpTest.java
@@ -13,6 +13,7 @@
package org.dromara.hutool.extra.ssh;
import org.dromara.hutool.core.util.CharsetUtil;
+import org.dromara.hutool.extra.ssh.engine.sshj.SshjSftp;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
diff --git a/hutool-extra/src/test/java/org/dromara/hutool/extra/tokenizer/TokenizerUtilTest.java b/hutool-extra/src/test/java/org/dromara/hutool/extra/tokenizer/TokenizerUtilTest.java
index 1bc82bf94..c2df63bc9 100644
--- a/hutool-extra/src/test/java/org/dromara/hutool/extra/tokenizer/TokenizerUtilTest.java
+++ b/hutool-extra/src/test/java/org/dromara/hutool/extra/tokenizer/TokenizerUtilTest.java
@@ -14,14 +14,6 @@ package org.dromara.hutool.extra.tokenizer;
import org.dromara.hutool.core.collection.iter.IterUtil;
import org.dromara.hutool.extra.tokenizer.engine.TokenizerEngine;
-import org.dromara.hutool.extra.tokenizer.engine.analysis.SmartcnEngine;
-import org.dromara.hutool.extra.tokenizer.engine.hanlp.HanLPEngine;
-import org.dromara.hutool.extra.tokenizer.engine.ikanalyzer.IKAnalyzerEngine;
-import org.dromara.hutool.extra.tokenizer.engine.jcseg.JcsegEngine;
-import org.dromara.hutool.extra.tokenizer.engine.jieba.JiebaEngine;
-import org.dromara.hutool.extra.tokenizer.engine.mmseg.MmsegEngine;
-import org.dromara.hutool.extra.tokenizer.engine.mynlp.MynlpEngine;
-import org.dromara.hutool.extra.tokenizer.engine.word.WordEngine;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
@@ -51,7 +43,7 @@ public class TokenizerUtilTest {
@Test
public void hanlpTest() {
- final TokenizerEngine engine = new HanLPEngine();
+ final TokenizerEngine engine = TokenizerUtil.createEngine("hanlp");
final Result result = engine.parse(text);
final String resultStr = IterUtil.join(result, " ");
Assertions.assertEquals("这 两 个 方法 的 区别 在于 返回 值", resultStr);
@@ -59,7 +51,7 @@ public class TokenizerUtilTest {
@Test
public void ikAnalyzerTest() {
- final TokenizerEngine engine = new IKAnalyzerEngine();
+ final TokenizerEngine engine = TokenizerUtil.createEngine("IKAnalyzer");
final Result result = engine.parse(text);
final String resultStr = IterUtil.join(result, " ");
Assertions.assertEquals("这两个 方法 的 区别 在于 返回值", resultStr);
@@ -67,14 +59,14 @@ public class TokenizerUtilTest {
@Test
public void jcsegTest() {
- final TokenizerEngine engine = new JcsegEngine();
+ final TokenizerEngine engine = TokenizerUtil.createEngine("Jcseg");
final Result result = engine.parse(text);
checkResult(result);
}
@Test
public void jiebaTest() {
- final TokenizerEngine engine = new JiebaEngine();
+ final TokenizerEngine engine = TokenizerUtil.createEngine("Jieba");
final Result result = engine.parse(text);
final String resultStr = IterUtil.join(result, " ");
Assertions.assertEquals("这 两个 方法 的 区别 在于 返回值", resultStr);
@@ -82,14 +74,14 @@ public class TokenizerUtilTest {
@Test
public void mmsegTest() {
- final TokenizerEngine engine = new MmsegEngine();
+ final TokenizerEngine engine = TokenizerUtil.createEngine("Mmseg");
final Result result = engine.parse(text);
checkResult(result);
}
@Test
public void smartcnTest() {
- final TokenizerEngine engine = new SmartcnEngine();
+ final TokenizerEngine engine = TokenizerUtil.createEngine("Smartcn");
final Result result = engine.parse(text);
final String resultStr = IterUtil.join(result, " ");
Assertions.assertEquals("这 两 个 方法 的 区别 在于 返回 值", resultStr);
@@ -97,7 +89,7 @@ public class TokenizerUtilTest {
@Test
public void wordTest() {
- final TokenizerEngine engine = new WordEngine();
+ final TokenizerEngine engine = TokenizerUtil.createEngine("Word");
final Result result = engine.parse(text);
final String resultStr = IterUtil.join(result, " ");
Assertions.assertEquals("这两个 方法 的 区别 在于 返回值", resultStr);
@@ -105,7 +97,7 @@ public class TokenizerUtilTest {
@Test
public void mynlpTest() {
- final TokenizerEngine engine = new MynlpEngine();
+ final TokenizerEngine engine = TokenizerUtil.createEngine("Mynlp");
final Result result = engine.parse(text);
final String resultStr = IterUtil.join(result, " ");
Assertions.assertEquals("这 两个 方法 的 区别 在于 返回 值", resultStr);
diff --git a/hutool-http/src/main/java/org/dromara/hutool/http/HttpUtil.java b/hutool-http/src/main/java/org/dromara/hutool/http/HttpUtil.java
index 6fbf5eb85..781f2d8d6 100644
--- a/hutool-http/src/main/java/org/dromara/hutool/http/HttpUtil.java
+++ b/hutool-http/src/main/java/org/dromara/hutool/http/HttpUtil.java
@@ -17,6 +17,7 @@ import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.http.client.ClientConfig;
import org.dromara.hutool.http.client.Request;
import org.dromara.hutool.http.client.Response;
+import org.dromara.hutool.http.client.engine.ClientEngine;
import org.dromara.hutool.http.client.engine.ClientEngineFactory;
import org.dromara.hutool.http.meta.Method;
import org.dromara.hutool.http.server.SimpleServer;
@@ -85,8 +86,8 @@ public class HttpUtil {
@SuppressWarnings("resource")
public static String get(final String urlString, final int timeout) {
return ClientEngineFactory.getEngine()
- .init(ClientConfig.of().setConnectionTimeout(timeout).setReadTimeout(timeout))
- .send(Request.of(urlString)).bodyStr();
+ .init(ClientConfig.of().setConnectionTimeout(timeout).setReadTimeout(timeout))
+ .send(Request.of(urlString)).bodyStr();
}
/**
@@ -99,7 +100,7 @@ public class HttpUtil {
@SuppressWarnings("resource")
public static String get(final String urlString, final Map paramMap) {
return send(Request.of(urlString).form(paramMap))
- .bodyStr();
+ .bodyStr();
}
/**
@@ -112,7 +113,7 @@ public class HttpUtil {
@SuppressWarnings("resource")
public static String post(final String urlString, final Map paramMap) {
return send(Request.of(urlString).method(Method.POST).form(paramMap))
- .bodyStr();
+ .bodyStr();
}
/**
@@ -131,7 +132,7 @@ public class HttpUtil {
@SuppressWarnings("resource")
public static String post(final String urlString, final String body) {
return send(Request.of(urlString).method(Method.POST).body(body))
- .bodyStr();
+ .bodyStr();
}
/**
@@ -140,18 +141,18 @@ public class HttpUtil {
* @param request HTTP请求
* @return HTTP响应
*/
- public static Response send(final Request request){
+ public static Response send(final Request request) {
return ClientEngineFactory.getEngine().send(request);
}
/**
* 将表单数据加到URL中(用于GET表单提交)
* 表单的键值对会被url编码,但是url中原参数不会被编码
- * 且对form参数进行 FormUrlEncoded ,x-www-form-urlencoded模式,此模式下空格会编码为'+'
+ * 且对form参数进行 FormUrlEncoded ,x-www-form-urlencoded模式,此模式下空格会编码为'+'
*
- * @param url URL
- * @param form 表单数据
- * @param charset 编码 null表示不encode键值对
+ * @param url URL
+ * @param form 表单数据
+ * @param charset 编码 null表示不encode键值对
* @return 合成后的URL
*/
public static String urlWithFormUrlEncoded(final String url, final Map form, final Charset charset) {
@@ -213,6 +214,16 @@ public class HttpUtil {
return urlBuilder.toString();
}
+ /**
+ * 创建客户端引擎
+ *
+ * @param engineName 引擎名称
+ * @return {@link ClientEngine}
+ */
+ public static ClientEngine createClient(final String engineName) {
+ return ClientEngineFactory.createEngine(engineName);
+ }
+
/**
* 创建简易的Http服务器
*
diff --git a/hutool-http/src/main/java/org/dromara/hutool/http/client/engine/ClientEngineFactory.java b/hutool-http/src/main/java/org/dromara/hutool/http/client/engine/ClientEngineFactory.java
index 75937181d..a39ae0564 100644
--- a/hutool-http/src/main/java/org/dromara/hutool/http/client/engine/ClientEngineFactory.java
+++ b/hutool-http/src/main/java/org/dromara/hutool/http/client/engine/ClientEngineFactory.java
@@ -13,6 +13,7 @@
package org.dromara.hutool.http.client.engine;
import org.dromara.hutool.core.lang.Singleton;
+import org.dromara.hutool.core.spi.ServiceLoader;
import org.dromara.hutool.core.spi.SpiUtil;
import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.http.HttpException;
@@ -48,6 +49,26 @@ public class ClientEngineFactory {
return createEngine().init(config);
}
+ /**
+ * 创建自定义引擎
+ *
+ * @param engineName 引擎名称,忽略大小写,如`HttpClient4`、`HttpClient5`、`OkHttp`、`JdkClient`
+ * @return 引擎
+ * @throws HttpException 无对应名称的引擎
+ */
+ public static ClientEngine createEngine(String engineName) throws HttpException {
+ if (!StrUtil.endWithIgnoreCase(engineName, "Engine")) {
+ engineName = engineName + "Engine";
+ }
+ final ServiceLoader list = SpiUtil.loadList(ClientEngine.class);
+ for (final String serviceName : list.getServiceNames()) {
+ if (StrUtil.endWithIgnoreCase(serviceName, engineName)) {
+ return list.getService(serviceName);
+ }
+ }
+ throw new HttpException("No such engine named: " + engineName);
+ }
+
/**
* 根据用户引入的HTTP客户端引擎jar,自动创建对应的拼音引擎对象
* 推荐创建的引擎单例使用,此方法每次调用会返回新的引擎
diff --git a/hutool-http/src/test/java/org/dromara/hutool/http/client/HttpClient4EngineTest.java b/hutool-http/src/test/java/org/dromara/hutool/http/client/HttpClient4EngineTest.java
index dce09cec8..9851f87f3 100644
--- a/hutool-http/src/test/java/org/dromara/hutool/http/client/HttpClient4EngineTest.java
+++ b/hutool-http/src/test/java/org/dromara/hutool/http/client/HttpClient4EngineTest.java
@@ -13,8 +13,8 @@
package org.dromara.hutool.http.client;
import org.dromara.hutool.core.lang.Console;
+import org.dromara.hutool.http.HttpUtil;
import org.dromara.hutool.http.client.engine.ClientEngine;
-import org.dromara.hutool.http.client.engine.httpclient4.HttpClient4Engine;
import org.dromara.hutool.http.meta.Method;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
@@ -25,7 +25,7 @@ public class HttpClient4EngineTest {
@Test
@Disabled
public void getTest() {
- final ClientEngine engine = new HttpClient4Engine();
+ final ClientEngine engine = HttpUtil.createClient("httpclient4");
final Request req = Request.of("https://www.hutool.cn/").method(Method.GET);
final Response res = engine.send(req);
diff --git a/hutool-http/src/test/java/org/dromara/hutool/http/client/HttpClient5EngineTest.java b/hutool-http/src/test/java/org/dromara/hutool/http/client/HttpClient5EngineTest.java
index dd92ccb45..4d3126a7b 100644
--- a/hutool-http/src/test/java/org/dromara/hutool/http/client/HttpClient5EngineTest.java
+++ b/hutool-http/src/test/java/org/dromara/hutool/http/client/HttpClient5EngineTest.java
@@ -13,8 +13,8 @@
package org.dromara.hutool.http.client;
import org.dromara.hutool.core.lang.Console;
+import org.dromara.hutool.http.HttpUtil;
import org.dromara.hutool.http.client.engine.ClientEngine;
-import org.dromara.hutool.http.client.engine.httpclient5.HttpClient5Engine;
import org.dromara.hutool.http.meta.Method;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
@@ -25,7 +25,7 @@ public class HttpClient5EngineTest {
@Test
@Disabled
public void getTest() {
- final ClientEngine engine = new HttpClient5Engine();
+ final ClientEngine engine = HttpUtil.createClient("httpclient5");
final Request req = Request.of("https://www.hutool.cn/").method(Method.GET);
final Response res = engine.send(req);
diff --git a/hutool-http/src/test/java/org/dromara/hutool/http/client/Issue3240Test.java b/hutool-http/src/test/java/org/dromara/hutool/http/client/Issue3240Test.java
index 64712da70..d758e3181 100755
--- a/hutool-http/src/test/java/org/dromara/hutool/http/client/Issue3240Test.java
+++ b/hutool-http/src/test/java/org/dromara/hutool/http/client/Issue3240Test.java
@@ -13,9 +13,8 @@
package org.dromara.hutool.http.client;
import org.dromara.hutool.core.lang.Console;
+import org.dromara.hutool.http.HttpUtil;
import org.dromara.hutool.http.client.engine.ClientEngine;
-import org.dromara.hutool.http.client.engine.httpclient4.HttpClient4Engine;
-import org.dromara.hutool.http.client.engine.okhttp.OkHttpEngine;
import org.dromara.hutool.http.meta.Method;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
@@ -25,7 +24,7 @@ public class Issue3240Test {
@Disabled
void okHttpTest() {
String url = "https://gh.yubue.cn/https://github.com/espressif/arduino-esp32/releases/download/2.0.11/package_esp32_dev_index.json";
- final ClientEngine engine = new OkHttpEngine();
+ final ClientEngine engine = HttpUtil.createClient("okhttp");
final Response send = engine.send(Request.of(url).method(Method.GET));
Console.log(send.body().getString());
}
@@ -34,7 +33,7 @@ public class Issue3240Test {
@Disabled
void httpClient4Test() {
String url = "https://gh.yubue.cn/https://github.com/espressif/arduino-esp32/releases/download/2.0.11/package_esp32_dev_index.json";
- final ClientEngine engine = new HttpClient4Engine();
+ final ClientEngine engine = HttpUtil.createClient("okhttp");
final Response send = engine.send(Request.of(url).method(Method.GET));
Console.log(send.body().getString());
}
diff --git a/hutool-http/src/test/java/org/dromara/hutool/http/client/IssueI7ZRJUTest.java b/hutool-http/src/test/java/org/dromara/hutool/http/client/IssueI7ZRJUTest.java
index 0afd06968..ce7da22df 100755
--- a/hutool-http/src/test/java/org/dromara/hutool/http/client/IssueI7ZRJUTest.java
+++ b/hutool-http/src/test/java/org/dromara/hutool/http/client/IssueI7ZRJUTest.java
@@ -20,7 +20,7 @@ import org.junit.jupiter.api.Test;
public class IssueI7ZRJUTest {
- @SuppressWarnings({"resource", "TestFailedLine"})
+ @SuppressWarnings({"resource"})
@Test
@Disabled
void getBadSSlTest() {
diff --git a/hutool-http/src/test/java/org/dromara/hutool/http/client/JdkEngineTest.java b/hutool-http/src/test/java/org/dromara/hutool/http/client/JdkEngineTest.java
index de5e93ca1..b4d77aa9c 100644
--- a/hutool-http/src/test/java/org/dromara/hutool/http/client/JdkEngineTest.java
+++ b/hutool-http/src/test/java/org/dromara/hutool/http/client/JdkEngineTest.java
@@ -13,8 +13,8 @@
package org.dromara.hutool.http.client;
import org.dromara.hutool.core.lang.Console;
+import org.dromara.hutool.http.HttpUtil;
import org.dromara.hutool.http.client.engine.ClientEngine;
-import org.dromara.hutool.http.client.engine.jdk.JdkClientEngine;
import org.dromara.hutool.http.meta.Method;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
@@ -24,7 +24,7 @@ public class JdkEngineTest {
@Test
@Disabled
public void getTest(){
- final ClientEngine engine = new JdkClientEngine();
+ final ClientEngine engine = HttpUtil.createClient("jdkClient");
final Request req = Request.of("https://www.hutool.cn/").method(Method.GET);
final Response res = engine.send(req);