diff --git a/CHANGELOG.md b/CHANGELOG.md
index 608c7c33f..8968e2af4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,8 @@
* 【core 】 ImgUtil.createImage支持背景透明(issue#851@Github)
* 【json 】 更改JSON转字符串时""被转义的规则为不转义(issue#852@Github)
* 【cron 】 表达式的所有段支持L关键字(issue#849@Github)
+* 【extra 】 增加PinyinUtil,封装TinyPinyin
+* 【extra 】 Ftp和Sftp增加FtpConfig,提供超时等更多可选参数
### Bug修复
* 【core 】 修复URLBuilder中请求参数有`&`导致的问题(issue#850@Github)
diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/SimpleCache.java b/hutool-core/src/main/java/cn/hutool/core/lang/SimpleCache.java
index 07e31c668..1f4ea3a75 100644
--- a/hutool-core/src/main/java/cn/hutool/core/lang/SimpleCache.java
+++ b/hutool-core/src/main/java/cn/hutool/core/lang/SimpleCache.java
@@ -3,6 +3,7 @@ package cn.hutool.core.lang;
import cn.hutool.core.lang.func.Func0;
import java.io.Serializable;
+import java.util.Iterator;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.locks.StampedLock;
@@ -14,7 +15,7 @@ import java.util.concurrent.locks.StampedLock;
* @param 值类型
* @author Looly
*/
-public class SimpleCache implements Serializable {
+public class SimpleCache implements Iterable>, Serializable {
private static final long serialVersionUID = 1L;
/**
@@ -148,4 +149,9 @@ public class SimpleCache implements Serializable {
lock.unlockWrite(stamp);
}
}
+
+ @Override
+ public Iterator> iterator() {
+ return this.cache.entrySet().iterator();
+ }
}
diff --git a/hutool-extra/pom.xml b/hutool-extra/pom.xml
index fd00e96b8..d368455aa 100644
--- a/hutool-extra/pom.xml
+++ b/hutool-extra/pom.xml
@@ -214,6 +214,12 @@
${spring-boot.version}
true
+
+ io.github.biezhi
+ TinyPinyin
+ 2.0.3.RELEASE
+ true
+
org.springframework.boot
spring-boot-starter-test
diff --git a/hutool-extra/src/main/java/cn/hutool/extra/ftp/AbstractFtp.java b/hutool-extra/src/main/java/cn/hutool/extra/ftp/AbstractFtp.java
index ff605b0a2..6b8397557 100644
--- a/hutool-extra/src/main/java/cn/hutool/extra/ftp/AbstractFtp.java
+++ b/hutool-extra/src/main/java/cn/hutool/extra/ftp/AbstractFtp.java
@@ -1,15 +1,15 @@
package cn.hutool.extra.ftp;
-import java.io.Closeable;
-import java.io.File;
-import java.nio.charset.Charset;
-import java.util.List;
-
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
+import java.io.Closeable;
+import java.io.File;
+import java.nio.charset.Charset;
+import java.util.List;
+
/**
* 抽象FTP类,用于定义通用的FTP方法
*
@@ -19,14 +19,18 @@ import cn.hutool.core.util.StrUtil;
public abstract class AbstractFtp implements Closeable {
public static final Charset DEFAULT_CHARSET = CharsetUtil.CHARSET_UTF_8 ;
-
- protected String host;
- protected int port;
-
- protected String user;
- protected String password;
-
- protected Charset charset;
+
+ protected FtpConfig ftpConfig;
+
+ /**
+ * 构造
+ *
+ * @param config FTP配置
+ * @since 5.3.3
+ */
+ protected AbstractFtp(FtpConfig config){
+ this.ftpConfig = config;
+ }
/**
* 如果连接超时的话,重新进行连接
@@ -119,12 +123,12 @@ public abstract class AbstractFtp implements Closeable {
//首位为空,表示以/开头
this.cd(StrUtil.SLASH);
}
- for (int i = 0; i < dirs.length; i++) {
- if (StrUtil.isNotEmpty(dirs[i])) {
- if (false == cd(dirs[i])) {
+ for (String s : dirs) {
+ if (StrUtil.isNotEmpty(s)) {
+ if (false == cd(s)) {
//目录不存在时创建
- mkdir(dirs[i]);
- cd(dirs[i]);
+ mkdir(s);
+ cd(s);
}
}
}
diff --git a/hutool-extra/src/main/java/cn/hutool/extra/ftp/Ftp.java b/hutool-extra/src/main/java/cn/hutool/extra/ftp/Ftp.java
index 9e3bb1be6..e1ec874e6 100644
--- a/hutool-extra/src/main/java/cn/hutool/extra/ftp/Ftp.java
+++ b/hutool-extra/src/main/java/cn/hutool/extra/ftp/Ftp.java
@@ -13,6 +13,7 @@ import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.net.SocketException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
@@ -20,23 +21,27 @@ import java.util.List;
/**
* FTP客户端封装
* 此客户端基于Apache-Commons-Net
- *
+ *
* @author looly
* @since 4.1.8
*/
public class Ftp extends AbstractFtp {
- /** 默认端口 */
+ /**
+ * 默认端口
+ */
public static final int DEFAULT_PORT = 21;
private FTPClient client;
private FtpMode mode;
- /** 执行完操作是否返回当前目录 */
+ /**
+ * 执行完操作是否返回当前目录
+ */
private boolean backToPwd;
/**
* 构造,匿名登录
- *
+ *
* @param host 域名或IP
*/
public Ftp(String host) {
@@ -45,7 +50,7 @@ public class Ftp extends AbstractFtp {
/**
* 构造,匿名登录
- *
+ *
* @param host 域名或IP
* @param port 端口
*/
@@ -55,10 +60,10 @@ public class Ftp extends AbstractFtp {
/**
* 构造
- *
- * @param host 域名或IP
- * @param port 端口
- * @param user 用户名
+ *
+ * @param host 域名或IP
+ * @param port 端口
+ * @param user 用户名
* @param password 密码
*/
public Ftp(String host, int port, String user, String password) {
@@ -67,12 +72,12 @@ public class Ftp extends AbstractFtp {
/**
* 构造
- *
- * @param host 域名或IP
- * @param port 端口
- * @param user 用户名
+ *
+ * @param host 域名或IP
+ * @param port 端口
+ * @param user 用户名
* @param password 密码
- * @param charset 编码
+ * @param charset 编码
*/
public Ftp(String host, int port, String user, String password, Charset charset) {
this(host, port, user, password, charset, null);
@@ -81,19 +86,25 @@ public class Ftp extends AbstractFtp {
/**
* 构造
*
- * @param host 域名或IP
- * @param port 端口
- * @param user 用户名
+ * @param host 域名或IP
+ * @param port 端口
+ * @param user 用户名
* @param password 密码
- * @param charset 编码
- * @param mode 模式
+ * @param charset 编码
+ * @param mode 模式
*/
public Ftp(String host, int port, String user, String password, Charset charset, FtpMode mode) {
- this.host = host;
- this.port = port;
- this.user = user;
- this.password = password;
- this.charset = charset;
+ this(new FtpConfig(host, port, user, password, charset), mode);
+ }
+
+ /**
+ * 构造
+ *
+ * @param config FTP配置
+ * @param mode 模式
+ */
+ public Ftp(FtpConfig config, FtpMode mode) {
+ super(config);
this.mode = mode;
this.init();
}
@@ -104,15 +115,15 @@ public class Ftp extends AbstractFtp {
* @return this
*/
public Ftp init() {
- return this.init(this.host, this.port, this.user, this.password, this.mode);
+ return this.init(this.ftpConfig, this.mode);
}
/**
* 初始化连接
*
- * @param host 域名或IP
- * @param port 端口
- * @param user 用户名
+ * @param host 域名或IP
+ * @param port 端口
+ * @param user 用户名
* @param password 密码
* @return this
*/
@@ -122,22 +133,39 @@ public class Ftp extends AbstractFtp {
/**
* 初始化连接
- *
- * @param host 域名或IP
- * @param port 端口
- * @param user 用户名
+ *
+ * @param host 域名或IP
+ * @param port 端口
+ * @param user 用户名
* @param password 密码
- * @param mode 模式
+ * @param mode 模式
* @return this
*/
public Ftp init(String host, int port, String user, String password, FtpMode mode) {
+ return init(new FtpConfig(host, port, user, password, this.ftpConfig.getCharset()), mode);
+ }
+
+ /**
+ * 初始化连接
+ *
+ * @param config FTP配置
+ * @param mode 模式
+ * @return this
+ */
+ public Ftp init(FtpConfig config, FtpMode mode) {
final FTPClient client = new FTPClient();
- client.setControlEncoding(this.charset.toString());
+ client.setControlEncoding(config.getCharset().toString());
+ client.setConnectTimeout((int) config.getConnectionTimeout());
+ try {
+ client.setSoTimeout((int)config.getSoTimeout());
+ } catch (SocketException e) {
+ //ignore
+ }
try {
// 连接ftp服务器
- client.connect(host, port);
+ client.connect(config.getHost(), config.getPort());
// 登录ftp服务器
- client.login(user, password);
+ client.login(config.getUser(), config.getPassword());
} catch (IOException e) {
throw new FtpException(e);
}
@@ -148,7 +176,7 @@ public class Ftp extends AbstractFtp {
} catch (IOException e) {
// ignore
}
- throw new FtpException("Login failed for user [{}], reply code is: [{}]", user, replyCode);
+ throw new FtpException("Login failed for user [{}], reply code is: [{}]", config.getUser(), replyCode);
}
this.client = client;
if (mode != null) {
@@ -159,7 +187,7 @@ public class Ftp extends AbstractFtp {
/**
* 设置FTP连接模式,可选主动和被动模式
- *
+ *
* @param mode 模式枚举
* @return this
* @since 4.1.19
@@ -167,19 +195,19 @@ public class Ftp extends AbstractFtp {
public Ftp setMode(FtpMode mode) {
this.mode = mode;
switch (mode) {
- case Active:
- this.client.enterLocalActiveMode();
- break;
- case Passive:
- this.client.enterLocalPassiveMode();
- break;
+ case Active:
+ this.client.enterLocalActiveMode();
+ break;
+ case Passive:
+ this.client.enterLocalPassiveMode();
+ break;
}
return this;
}
/**
* 设置执行完操作是否返回当前目录
- *
+ *
* @param backToPwd 执行完操作是否返回当前目录
* @return this
* @since 4.6.0
@@ -191,7 +219,7 @@ public class Ftp extends AbstractFtp {
/**
* 如果连接超时的话,重新进行连接 经测试,当连接超时时,client.isConnected()仍然返回ture,无法判断是否连接超时 因此,通过发送pwd命令的方式,检查连接是否超时
- *
+ *
* @return this
*/
@Override
@@ -211,7 +239,7 @@ public class Ftp extends AbstractFtp {
/**
* 改变目录
- *
+ *
* @param directory 目录
* @return 是否成功
*/
@@ -230,7 +258,7 @@ public class Ftp extends AbstractFtp {
/**
* 远程当前目录
- *
+ *
* @return 远程当前目录
* @since 4.1.14
*/
@@ -256,7 +284,7 @@ public class Ftp extends AbstractFtp {
/**
* 遍历某个目录下所有文件和目录,不会递归遍历
- *
+ *
* @param path 目录
* @return 文件或目录列表
*/
@@ -291,7 +319,7 @@ public class Ftp extends AbstractFtp {
/**
* 判断ftp服务器文件是否存在
- *
+ *
* @param path 文件路径
* @return 是否存在
*/
@@ -356,15 +384,15 @@ public class Ftp extends AbstractFtp {
/**
* 上传文件到指定目录,可选:
- *
+ *
*
* 1. path为null或""上传到当前路径
* 2. path为相对路径则相对于当前路径的子路径
* 3. path为绝对路径则上传到此路径
*
- *
+ *
* @param destPath 服务端路径,可以为{@code null} 或者相对路径或绝对路径
- * @param file 文件
+ * @param file 文件
* @return 是否上传成功
*/
@Override
@@ -375,15 +403,15 @@ public class Ftp extends AbstractFtp {
/**
* 上传文件到指定目录,可选:
- *
+ *
*
* 1. path为null或""上传到当前路径
* 2. path为相对路径则相对于当前路径的子路径
* 3. path为绝对路径则上传到此路径
*
- *
- * @param file 文件
- * @param path 服务端路径,可以为{@code null} 或者相对路径或绝对路径
+ *
+ * @param file 文件
+ * @param path 服务端路径,可以为{@code null} 或者相对路径或绝对路径
* @param fileName 自定义在服务端保存的文件名
* @return 是否上传成功
*/
@@ -397,16 +425,15 @@ public class Ftp extends AbstractFtp {
/**
* 上传文件到指定目录,可选:
- *
+ *
*
* 1. path为null或""上传到当前路径
* 2. path为相对路径则相对于当前路径的子路径
* 3. path为绝对路径则上传到此路径
*
- *
- *
- * @param path 服务端路径,可以为{@code null} 或者相对路径或绝对路径
- * @param fileName 文件名
+ *
+ * @param path 服务端路径,可以为{@code null} 或者相对路径或绝对路径
+ * @param fileName 文件名
* @param fileStream 文件流
* @return 是否上传成功
*/
@@ -443,8 +470,8 @@ public class Ftp extends AbstractFtp {
/**
* 下载文件
- *
- * @param path 文件路径
+ *
+ * @param path 文件路径
* @param outFile 输出文件或目录
*/
@Override
@@ -456,10 +483,10 @@ public class Ftp extends AbstractFtp {
/**
* 下载文件
- *
- * @param path 文件路径
+ *
+ * @param path 文件路径
* @param fileName 文件名
- * @param outFile 输出文件或目录
+ * @param outFile 输出文件或目录
*/
public void download(String path, String fileName, File outFile) {
if (outFile.isDirectory()) {
@@ -477,10 +504,10 @@ public class Ftp extends AbstractFtp {
/**
* 下载文件到输出流
- *
- * @param path 文件路径
+ *
+ * @param path 文件路径
* @param fileName 文件名
- * @param out 输出位置
+ * @param out 输出位置
*/
public void download(String path, String fileName, OutputStream out) {
String pwd = null;
@@ -503,7 +530,7 @@ public class Ftp extends AbstractFtp {
/**
* 获取FTPClient客户端对象
- *
+ *
* @return {@link FTPClient}
*/
public FTPClient getClient() {
diff --git a/hutool-extra/src/main/java/cn/hutool/extra/ftp/FtpConfig.java b/hutool-extra/src/main/java/cn/hutool/extra/ftp/FtpConfig.java
new file mode 100644
index 000000000..f87d494d0
--- /dev/null
+++ b/hutool-extra/src/main/java/cn/hutool/extra/ftp/FtpConfig.java
@@ -0,0 +1,134 @@
+package cn.hutool.extra.ftp;
+
+import java.io.Serializable;
+import java.nio.charset.Charset;
+
+/**
+ * FTP配置项,提供FTP各种参数信息
+ *
+ * @author looly
+ */
+public class FtpConfig implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ public static FtpConfig create(){
+ return new FtpConfig();
+ }
+
+ /**
+ * 主机
+ */
+ private String host;
+ /**
+ * 端口
+ */
+ private int port;
+ /**
+ * 用户名
+ */
+ private String user;
+ /**
+ * 密码
+ */
+ private String password;
+ /**
+ * 编码
+ */
+ private Charset charset;
+
+ /**
+ * 连接超时时长,单位毫秒
+ */
+ private long connectionTimeout;
+
+ /**
+ * Socket连接超时时长,单位毫秒
+ */
+ private long soTimeout;
+
+ /**
+ * 构造
+ */
+ public FtpConfig() {
+ }
+
+ /**
+ * 构造
+ *
+ * @param host 主机
+ * @param port 端口
+ * @param user 用户名
+ * @param password 密码
+ * @param charset 编码
+ */
+ public FtpConfig(String host, int port, String user, String password, Charset charset) {
+ this.host = host;
+ this.port = port;
+ this.user = user;
+ this.password = password;
+ this.charset = charset;
+ }
+
+ public String getHost() {
+ return host;
+ }
+
+ public FtpConfig setHost(String host) {
+ this.host = host;
+ return this;
+ }
+
+ public int getPort() {
+ return port;
+ }
+
+ public FtpConfig setPort(int port) {
+ this.port = port;
+ return this;
+ }
+
+ public String getUser() {
+ return user;
+ }
+
+ public FtpConfig setUser(String user) {
+ this.user = user;
+ return this;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public FtpConfig setPassword(String password) {
+ this.password = password;
+ return this;
+ }
+
+ public Charset getCharset() {
+ return charset;
+ }
+
+ public FtpConfig setCharset(Charset charset) {
+ this.charset = charset;
+ return this;
+ }
+
+ public long getConnectionTimeout() {
+ return connectionTimeout;
+ }
+
+ public FtpConfig setConnectionTimeout(long connectionTimeout) {
+ this.connectionTimeout = connectionTimeout;
+ return this;
+ }
+
+ public long getSoTimeout() {
+ return soTimeout;
+ }
+
+ public FtpConfig setSoTimeout(long soTimeout) {
+ this.soTimeout = soTimeout;
+ return this;
+ }
+}
diff --git a/hutool-extra/src/main/java/cn/hutool/extra/pinyin/PinyinUtil.java b/hutool-extra/src/main/java/cn/hutool/extra/pinyin/PinyinUtil.java
new file mode 100644
index 000000000..1f565688a
--- /dev/null
+++ b/hutool-extra/src/main/java/cn/hutool/extra/pinyin/PinyinUtil.java
@@ -0,0 +1,73 @@
+package cn.hutool.extra.pinyin;
+
+import com.github.promeg.pinyinhelper.Pinyin;
+
+/**
+ * 拼音工具类,封装了TinyPinyin
+ *
+ *
+ * TinyPinyin(https://github.com/promeG/TinyPinyin)提供者未提交Maven中央库,
+ * 因此使用
+ * https://github.com/biezhi/TinyPinyin打包的版本
+ *
+ *
+ *
+ * 引入:
+ *
+ * <dependency>
+ * <groupId>io.github.biezhi</groupId>
+ * <artifactId>TinyPinyin</artifactId>
+ * <version>2.0.3.RELEASE</version>
+ * </dependency>
+ *
+ *
+ *
+ * @author looly
+ */
+public class PinyinUtil {
+
+ /**
+ * 自定义拼音全局配置,例如加入自定义字典等
+ *
+ * @param config 配置,通过Pinyin.newConfig().with(dict)添加字典
+ */
+ public static void init(Pinyin.Config config) {
+ Pinyin.init(config);
+ }
+
+ /**
+ * 如果c为汉字,则返回大写拼音;如果c不是汉字,则返回String.valueOf(c)
+ *
+ * @param c 任意字符,汉族返回拼音,非汉字原样返回
+ * @param isToUpperCase 是否转换为大写
+ * @return 汉族返回拼音,非汉字原样返回
+ */
+ public static String toPinyin(char c, boolean isToUpperCase) {
+ final String pinyin = Pinyin.toPinyin(c);
+ return isToUpperCase ? pinyin : pinyin.toLowerCase();
+ }
+
+ /**
+ * 将输入字符串转为拼音,每个字之间的拼音使用空格分隔
+ *
+ * @param str 任意字符,汉族返回拼音,非汉字原样返回
+ * @param isToUpperCase 是否转换为大写
+ * @return 汉族返回拼音,非汉字原样返回
+ */
+ public static String toPinyin(String str, boolean isToUpperCase) {
+ return toPinyin(str, " ", isToUpperCase);
+ }
+
+ /**
+ * 将输入字符串转为拼音,以字符为单位插入分隔符
+ *
+ * @param str 任意字符,汉族返回拼音,非汉字原样返回
+ * @param separator 每个字拼音之间的分隔符
+ * @param isToUpperCase 是否转换为大写
+ * @return 汉族返回拼音,非汉字原样返回
+ */
+ public static String toPinyin(String str, String separator, boolean isToUpperCase) {
+ final String pinyin = Pinyin.toPinyin(str, separator);
+ return isToUpperCase ? pinyin : pinyin.toLowerCase();
+ }
+}
diff --git a/hutool-extra/src/main/java/cn/hutool/extra/pinyin/package-info.java b/hutool-extra/src/main/java/cn/hutool/extra/pinyin/package-info.java
new file mode 100644
index 000000000..1e1bb8603
--- /dev/null
+++ b/hutool-extra/src/main/java/cn/hutool/extra/pinyin/package-info.java
@@ -0,0 +1,7 @@
+/**
+ * 拼音工具封装,基于TinyPinyin
+ *
+ * @author looly
+ *
+ */
+package cn.hutool.extra.pinyin;
\ No newline at end of file
diff --git a/hutool-extra/src/main/java/cn/hutool/extra/ssh/JschSessionPool.java b/hutool-extra/src/main/java/cn/hutool/extra/ssh/JschSessionPool.java
index 3466edff0..aa2703da0 100644
--- a/hutool-extra/src/main/java/cn/hutool/extra/ssh/JschSessionPool.java
+++ b/hutool-extra/src/main/java/cn/hutool/extra/ssh/JschSessionPool.java
@@ -1,13 +1,12 @@
package cn.hutool.extra.ssh;
+import cn.hutool.core.lang.SimpleCache;
import cn.hutool.core.util.StrUtil;
import com.jcraft.jsch.Session;
-import java.util.Collection;
+import java.util.HashMap;
import java.util.Iterator;
-import java.util.Map;
import java.util.Map.Entry;
-import java.util.concurrent.ConcurrentHashMap;
/**
* Jsch会话池
@@ -20,11 +19,7 @@ public enum JschSessionPool {
/**
* SSH会话池,key:host,value:Session对象
*/
- private final Map sessionPool = new ConcurrentHashMap<>();
- /**
- * 锁
- */
- private static final Object lock = new Object();
+ private final SimpleCache cache = new SimpleCache<>(new HashMap<>());
/**
* 获取Session,不存在返回null
@@ -33,7 +28,7 @@ public enum JschSessionPool {
* @return Session
*/
public Session get(String key) {
- return sessionPool.get(key);
+ return cache.get(key);
}
/**
@@ -47,17 +42,7 @@ public enum JschSessionPool {
*/
public Session getSession(String sshHost, int sshPort, String sshUser, String sshPass) {
final String key = StrUtil.format("{}@{}:{}", sshUser, sshHost, sshPort);
- Session session = get(key);
- if (null == session || false == session.isConnected()) {
- synchronized (lock) {
- session = get(key);
- if (null == session || false == session.isConnected()) {
- session = JschUtil.openSession(sshHost, sshPort, sshUser, sshPass);
- put(key, session);
- }
- }
- }
- return session;
+ return this.cache.get(key, ()-> JschUtil.openSession(sshHost, sshPort, sshUser, sshPass));
}
/**
@@ -72,17 +57,7 @@ public enum JschSessionPool {
*/
public Session getSession(String sshHost, int sshPort, String sshUser, String prvkey, byte[] passphrase) {
final String key = StrUtil.format("{}@{}:{}", sshUser, sshHost, sshPort);
- Session session = get(key);
- if (null == session || false == session.isConnected()) {
- synchronized (lock) {
- session = get(key);
- if (null == session || false == session.isConnected()) {
- session = JschUtil.openSession(sshHost, sshPort, sshUser, prvkey, passphrase);
- put(key, session);
- }
- }
- }
- return session;
+ return this.cache.get(key, ()->JschUtil.openSession(sshHost, sshPort, sshUser, prvkey, passphrase));
}
/**
@@ -92,7 +67,7 @@ public enum JschSessionPool {
* @param session Session
*/
public void put(String key, Session session) {
- this.sessionPool.put(key, session);
+ this.cache.put(key, session);
}
/**
@@ -101,11 +76,11 @@ public enum JschSessionPool {
* @param key 主机,格式为user@host:port
*/
public void close(String key) {
- Session session = sessionPool.get(key);
+ Session session = get(key);
if (session != null && session.isConnected()) {
session.disconnect();
}
- sessionPool.remove(key);
+ this.cache.remove(key);
}
/**
@@ -116,7 +91,7 @@ public enum JschSessionPool {
*/
public void remove(Session session) {
if (null != session) {
- final Iterator> iterator = this.sessionPool.entrySet().iterator();
+ final Iterator> iterator = this.cache.iterator();
Entry entry;
while (iterator.hasNext()) {
entry = iterator.next();
@@ -132,12 +107,13 @@ public enum JschSessionPool {
* 关闭所有SSH连接会话
*/
public void closeAll() {
- Collection sessions = sessionPool.values();
- for (Session session : sessions) {
- if (session.isConnected()) {
+ Session session;
+ for (Entry entry : this.cache) {
+ session = entry.getValue();
+ if (session != null && session.isConnected()) {
session.disconnect();
}
}
- sessionPool.clear();
+ cache.clear();
}
}
diff --git a/hutool-extra/src/main/java/cn/hutool/extra/ssh/JschUtil.java b/hutool-extra/src/main/java/cn/hutool/extra/ssh/JschUtil.java
index 2a9baaba2..62211cab1 100644
--- a/hutool-extra/src/main/java/cn/hutool/extra/ssh/JschUtil.java
+++ b/hutool-extra/src/main/java/cn/hutool/extra/ssh/JschUtil.java
@@ -85,9 +85,24 @@ public class JschUtil {
* @return SSH会话
*/
public static Session openSession(String sshHost, int sshPort, String sshUser, String sshPass) {
+ return openSession(sshHost, sshPort, sshUser, sshPass, 0);
+ }
+
+ /**
+ * 打开一个新的SSH会话
+ *
+ * @param sshHost 主机
+ * @param sshPort 端口
+ * @param sshUser 用户名
+ * @param sshPass 密码
+ * @param timeout Socket连接超时时长,单位毫秒
+ * @return SSH会话
+ * @since 5.3.3
+ */
+ public static Session openSession(String sshHost, int sshPort, String sshUser, String sshPass, int timeout) {
final Session session = createSession(sshHost, sshPort, sshUser, sshPass);
try {
- session.connect();
+ session.connect(timeout);
} catch (JSchException e) {
throw new JschRuntimeException(e);
}
@@ -257,7 +272,19 @@ public class JschUtil {
* @since 4.0.3
*/
public static ChannelSftp openSftp(Session session) {
- return (ChannelSftp) openChannel(session, ChannelType.SFTP);
+ return openSftp(session, 0);
+ }
+
+ /**
+ * 打开SFTP连接
+ *
+ * @param session Session会话
+ * @param timeout 连接超时时长,单位毫秒
+ * @return {@link ChannelSftp}
+ * @since 5.3.3
+ */
+ public static ChannelSftp openSftp(Session session, int timeout) {
+ return (ChannelSftp) openChannel(session, ChannelType.SFTP, timeout);
}
/**
@@ -305,9 +332,22 @@ public class JschUtil {
* @since 4.5.2
*/
public static Channel openChannel(Session session, ChannelType channelType) {
+ return openChannel(session, channelType, 0);
+ }
+
+ /**
+ * 打开Channel连接
+ *
+ * @param session Session会话
+ * @param channelType 通道类型,可以是shell或sftp等,见{@link ChannelType}
+ * @param timeout 连接超时时长,单位毫秒
+ * @return {@link Channel}
+ * @since 5.3.3
+ */
+ public static Channel openChannel(Session session, ChannelType channelType, int timeout) {
final Channel channel = createChannel(session, channelType);
try {
- channel.connect();
+ channel.connect(Math.max(timeout, 0));
} catch (JSchException e) {
throw new JschRuntimeException(e);
}
diff --git a/hutool-extra/src/main/java/cn/hutool/extra/ssh/Sftp.java b/hutool-extra/src/main/java/cn/hutool/extra/ssh/Sftp.java
index c16cfeb21..d63ea63f9 100644
--- a/hutool-extra/src/main/java/cn/hutool/extra/ssh/Sftp.java
+++ b/hutool-extra/src/main/java/cn/hutool/extra/ssh/Sftp.java
@@ -4,6 +4,7 @@ import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Filter;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.ftp.AbstractFtp;
+import cn.hutool.extra.ftp.FtpConfig;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.ChannelSftp.LsEntry;
import com.jcraft.jsch.ChannelSftp.LsEntrySelector;
@@ -59,7 +60,18 @@ public class Sftp extends AbstractFtp {
* @since 4.1.14
*/
public Sftp(String sshHost, int sshPort, String sshUser, String sshPass, Charset charset) {
- init(sshHost, sshPort, sshUser, sshPass, charset);
+ this(new FtpConfig(sshHost, sshPort, sshUser, sshPass, charset));
+ }
+
+ /**
+ * 构造
+ *
+ * @param config FTP配置
+ * @since 5.3.3
+ */
+ public Sftp(FtpConfig config) {
+ super(config);
+ init(config);
}
/**
@@ -79,6 +91,7 @@ public class Sftp extends AbstractFtp {
* @since 4.1.14
*/
public Sftp(Session session, Charset charset) {
+ super(FtpConfig.create().setCharset(charset));
init(session, charset);
}
@@ -89,6 +102,7 @@ public class Sftp extends AbstractFtp {
* @param charset 编码
*/
public Sftp(ChannelSftp channel, Charset charset) {
+ super(FtpConfig.create().setCharset(charset));
init(channel, charset);
}
// ---------------------------------------------------------------------------------------- Constructor end
@@ -103,13 +117,28 @@ public class Sftp extends AbstractFtp {
* @param charset 编码
*/
public void init(String sshHost, int sshPort, String sshUser, String sshPass, Charset charset) {
- this.host = sshHost;
- this.port = sshPort;
- this.user = sshUser;
- this.password = sshPass;
init(JschUtil.getSession(sshHost, sshPort, sshUser, sshPass), charset);
}
+ /**
+ * 初始化
+ *
+ * @since 5.3.3
+ */
+ public void init() {
+ init(this.ftpConfig);
+ }
+
+ /**
+ * 初始化
+ *
+ * @param config FTP配置
+ * @since 5.3.3
+ */
+ public void init(FtpConfig config) {
+ init(config.getHost(), config.getPort(), config.getUser(), config.getPassword(), config.getCharset());
+ }
+
/**
* 初始化
*
@@ -118,7 +147,7 @@ public class Sftp extends AbstractFtp {
*/
public void init(Session session, Charset charset) {
this.session = session;
- init(JschUtil.openSftp(session), charset);
+ init(JschUtil.openSftp(session, (int)this.ftpConfig.getConnectionTimeout()), charset);
}
/**
@@ -128,7 +157,7 @@ public class Sftp extends AbstractFtp {
* @param charset 编码
*/
public void init(ChannelSftp channel, Charset charset) {
- this.charset = charset;
+ this.ftpConfig.setCharset(charset);
try {
channel.setFilenameEncoding(charset.toString());
} catch (SftpException e) {
@@ -139,8 +168,8 @@ public class Sftp extends AbstractFtp {
@Override
public Sftp reconnectIfTimeout() {
- if (false == this.cd("/") && StrUtil.isNotBlank(this.host)) {
- init(this.host, this.port, this.user, this.password, this.charset);
+ if (false == this.cd("/") && StrUtil.isNotBlank(this.ftpConfig.getHost())) {
+ init(this.ftpConfig);
}
return this;
}
@@ -414,9 +443,9 @@ public class Sftp extends AbstractFtp {
@Override
public String toString() {
return "Sftp{" +
- "host='" + host + '\'' +
- ", port=" + port +
- ", user='" + user + '\'' +
+ "host='" + this.ftpConfig.getHost() + '\'' +
+ ", port=" + this.ftpConfig.getPort() +
+ ", user='" + this.ftpConfig.getUser() + '\'' +
'}';
}
diff --git a/hutool-extra/src/test/java/cn/hutool/extra/pinyin/PinyinUtilTest.java b/hutool-extra/src/test/java/cn/hutool/extra/pinyin/PinyinUtilTest.java
new file mode 100644
index 000000000..167f3e43b
--- /dev/null
+++ b/hutool-extra/src/test/java/cn/hutool/extra/pinyin/PinyinUtilTest.java
@@ -0,0 +1,19 @@
+package cn.hutool.extra.pinyin;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class PinyinUtilTest {
+
+ @Test
+ public void toPinyinTest(){
+ final String pinyin = PinyinUtil.toPinyin("你好", false);
+ Assert.assertEquals("ni hao", pinyin);
+ }
+
+ @Test
+ public void toPinyinUpperCaseTest(){
+ final String pinyin = PinyinUtil.toPinyin("你好怡", true);
+ Assert.assertEquals("NI HAO YI", pinyin);
+ }
+}