add PinyinUtil

This commit is contained in:
Looly 2020-04-27 13:45:54 +08:00
parent 63732834ac
commit cf1f208aa0
12 changed files with 467 additions and 144 deletions

View File

@ -9,6 +9,8 @@
* 【core 】 ImgUtil.createImage支持背景透明issue#851@Github * 【core 】 ImgUtil.createImage支持背景透明issue#851@Github
* 【json 】 更改JSON转字符串时"</"被转义的规则为不转义issue#852@Github * 【json 】 更改JSON转字符串时"</"被转义的规则为不转义issue#852@Github
* 【cron 】 表达式的所有段支持L关键字issue#849@Github * 【cron 】 表达式的所有段支持L关键字issue#849@Github
* 【extra 】 增加PinyinUtil封装TinyPinyin
* 【extra 】 Ftp和Sftp增加FtpConfig提供超时等更多可选参数
### Bug修复 ### Bug修复
* 【core 】 修复URLBuilder中请求参数有`&amp;`导致的问题issue#850@Github * 【core 】 修复URLBuilder中请求参数有`&amp;`导致的问题issue#850@Github

View File

@ -3,6 +3,7 @@ package cn.hutool.core.lang;
import cn.hutool.core.lang.func.Func0; import cn.hutool.core.lang.func.Func0;
import java.io.Serializable; import java.io.Serializable;
import java.util.Iterator;
import java.util.Map; import java.util.Map;
import java.util.WeakHashMap; import java.util.WeakHashMap;
import java.util.concurrent.locks.StampedLock; import java.util.concurrent.locks.StampedLock;
@ -14,7 +15,7 @@ import java.util.concurrent.locks.StampedLock;
* @param <V> 值类型 * @param <V> 值类型
* @author Looly * @author Looly
*/ */
public class SimpleCache<K, V> implements Serializable { public class SimpleCache<K, V> implements Iterable<Map.Entry<K, V>>, Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** /**
@ -148,4 +149,9 @@ public class SimpleCache<K, V> implements Serializable {
lock.unlockWrite(stamp); lock.unlockWrite(stamp);
} }
} }
@Override
public Iterator<Map.Entry<K, V>> iterator() {
return this.cache.entrySet().iterator();
}
} }

View File

@ -214,6 +214,12 @@
<version>${spring-boot.version}</version> <version>${spring-boot.version}</version>
<optional>true</optional> <optional>true</optional>
</dependency> </dependency>
<dependency>
<groupId>io.github.biezhi</groupId>
<artifactId>TinyPinyin</artifactId>
<version>2.0.3.RELEASE</version>
<optional>true</optional>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId> <artifactId>spring-boot-starter-test</artifactId>

View File

@ -1,15 +1,15 @@
package cn.hutool.extra.ftp; 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.collection.CollUtil;
import cn.hutool.core.io.FileUtil; import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.CharsetUtil; import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil; 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方法 * 抽象FTP类用于定义通用的FTP方法
* *
@ -19,14 +19,18 @@ import cn.hutool.core.util.StrUtil;
public abstract class AbstractFtp implements Closeable { public abstract class AbstractFtp implements Closeable {
public static final Charset DEFAULT_CHARSET = CharsetUtil.CHARSET_UTF_8 ; public static final Charset DEFAULT_CHARSET = CharsetUtil.CHARSET_UTF_8 ;
protected String host; protected FtpConfig ftpConfig;
protected int port;
/**
protected String user; * 构造
protected String password; *
* @param config FTP配置
protected Charset charset; * @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); this.cd(StrUtil.SLASH);
} }
for (int i = 0; i < dirs.length; i++) { for (String s : dirs) {
if (StrUtil.isNotEmpty(dirs[i])) { if (StrUtil.isNotEmpty(s)) {
if (false == cd(dirs[i])) { if (false == cd(s)) {
//目录不存在时创建 //目录不存在时创建
mkdir(dirs[i]); mkdir(s);
cd(dirs[i]); cd(s);
} }
} }
} }

View File

@ -13,6 +13,7 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.net.SocketException;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -20,23 +21,27 @@ import java.util.List;
/** /**
* FTP客户端封装<br> * FTP客户端封装<br>
* 此客户端基于Apache-Commons-Net * 此客户端基于Apache-Commons-Net
* *
* @author looly * @author looly
* @since 4.1.8 * @since 4.1.8
*/ */
public class Ftp extends AbstractFtp { public class Ftp extends AbstractFtp {
/** 默认端口 */ /**
* 默认端口
*/
public static final int DEFAULT_PORT = 21; public static final int DEFAULT_PORT = 21;
private FTPClient client; private FTPClient client;
private FtpMode mode; private FtpMode mode;
/** 执行完操作是否返回当前目录 */ /**
* 执行完操作是否返回当前目录
*/
private boolean backToPwd; private boolean backToPwd;
/** /**
* 构造匿名登录 * 构造匿名登录
* *
* @param host 域名或IP * @param host 域名或IP
*/ */
public Ftp(String host) { public Ftp(String host) {
@ -45,7 +50,7 @@ public class Ftp extends AbstractFtp {
/** /**
* 构造匿名登录 * 构造匿名登录
* *
* @param host 域名或IP * @param host 域名或IP
* @param port 端口 * @param port 端口
*/ */
@ -55,10 +60,10 @@ public class Ftp extends AbstractFtp {
/** /**
* 构造 * 构造
* *
* @param host 域名或IP * @param host 域名或IP
* @param port 端口 * @param port 端口
* @param user 用户名 * @param user 用户名
* @param password 密码 * @param password 密码
*/ */
public Ftp(String host, int port, String user, String password) { public Ftp(String host, int port, String user, String password) {
@ -67,12 +72,12 @@ public class Ftp extends AbstractFtp {
/** /**
* 构造 * 构造
* *
* @param host 域名或IP * @param host 域名或IP
* @param port 端口 * @param port 端口
* @param user 用户名 * @param user 用户名
* @param password 密码 * @param password 密码
* @param charset 编码 * @param charset 编码
*/ */
public Ftp(String host, int port, String user, String password, Charset charset) { public Ftp(String host, int port, String user, String password, Charset charset) {
this(host, port, user, password, charset, null); this(host, port, user, password, charset, null);
@ -81,19 +86,25 @@ public class Ftp extends AbstractFtp {
/** /**
* 构造 * 构造
* *
* @param host 域名或IP * @param host 域名或IP
* @param port 端口 * @param port 端口
* @param user 用户名 * @param user 用户名
* @param password 密码 * @param password 密码
* @param charset 编码 * @param charset 编码
* @param mode 模式 * @param mode 模式
*/ */
public Ftp(String host, int port, String user, String password, Charset charset, FtpMode mode) { public Ftp(String host, int port, String user, String password, Charset charset, FtpMode mode) {
this.host = host; this(new FtpConfig(host, port, user, password, charset), mode);
this.port = port; }
this.user = user;
this.password = password; /**
this.charset = charset; * 构造
*
* @param config FTP配置
* @param mode 模式
*/
public Ftp(FtpConfig config, FtpMode mode) {
super(config);
this.mode = mode; this.mode = mode;
this.init(); this.init();
} }
@ -104,15 +115,15 @@ public class Ftp extends AbstractFtp {
* @return this * @return this
*/ */
public Ftp init() { 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 host 域名或IP
* @param port 端口 * @param port 端口
* @param user 用户名 * @param user 用户名
* @param password 密码 * @param password 密码
* @return this * @return this
*/ */
@ -122,22 +133,39 @@ public class Ftp extends AbstractFtp {
/** /**
* 初始化连接 * 初始化连接
* *
* @param host 域名或IP * @param host 域名或IP
* @param port 端口 * @param port 端口
* @param user 用户名 * @param user 用户名
* @param password 密码 * @param password 密码
* @param mode 模式 * @param mode 模式
* @return this * @return this
*/ */
public Ftp init(String host, int port, String user, String password, FtpMode mode) { 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(); 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 { try {
// 连接ftp服务器 // 连接ftp服务器
client.connect(host, port); client.connect(config.getHost(), config.getPort());
// 登录ftp服务器 // 登录ftp服务器
client.login(user, password); client.login(config.getUser(), config.getPassword());
} catch (IOException e) { } catch (IOException e) {
throw new FtpException(e); throw new FtpException(e);
} }
@ -148,7 +176,7 @@ public class Ftp extends AbstractFtp {
} catch (IOException e) { } catch (IOException e) {
// ignore // 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; this.client = client;
if (mode != null) { if (mode != null) {
@ -159,7 +187,7 @@ public class Ftp extends AbstractFtp {
/** /**
* 设置FTP连接模式可选主动和被动模式 * 设置FTP连接模式可选主动和被动模式
* *
* @param mode 模式枚举 * @param mode 模式枚举
* @return this * @return this
* @since 4.1.19 * @since 4.1.19
@ -167,19 +195,19 @@ public class Ftp extends AbstractFtp {
public Ftp setMode(FtpMode mode) { public Ftp setMode(FtpMode mode) {
this.mode = mode; this.mode = mode;
switch (mode) { switch (mode) {
case Active: case Active:
this.client.enterLocalActiveMode(); this.client.enterLocalActiveMode();
break; break;
case Passive: case Passive:
this.client.enterLocalPassiveMode(); this.client.enterLocalPassiveMode();
break; break;
} }
return this; return this;
} }
/** /**
* 设置执行完操作是否返回当前目录 * 设置执行完操作是否返回当前目录
* *
* @param backToPwd 执行完操作是否返回当前目录 * @param backToPwd 执行完操作是否返回当前目录
* @return this * @return this
* @since 4.6.0 * @since 4.6.0
@ -191,7 +219,7 @@ public class Ftp extends AbstractFtp {
/** /**
* 如果连接超时的话重新进行连接 经测试当连接超时时client.isConnected()仍然返回ture无法判断是否连接超时 因此通过发送pwd命令的方式检查连接是否超时 * 如果连接超时的话重新进行连接 经测试当连接超时时client.isConnected()仍然返回ture无法判断是否连接超时 因此通过发送pwd命令的方式检查连接是否超时
* *
* @return this * @return this
*/ */
@Override @Override
@ -211,7 +239,7 @@ public class Ftp extends AbstractFtp {
/** /**
* 改变目录 * 改变目录
* *
* @param directory 目录 * @param directory 目录
* @return 是否成功 * @return 是否成功
*/ */
@ -230,7 +258,7 @@ public class Ftp extends AbstractFtp {
/** /**
* 远程当前目录 * 远程当前目录
* *
* @return 远程当前目录 * @return 远程当前目录
* @since 4.1.14 * @since 4.1.14
*/ */
@ -256,7 +284,7 @@ public class Ftp extends AbstractFtp {
/** /**
* 遍历某个目录下所有文件和目录不会递归遍历 * 遍历某个目录下所有文件和目录不会递归遍历
* *
* @param path 目录 * @param path 目录
* @return 文件或目录列表 * @return 文件或目录列表
*/ */
@ -291,7 +319,7 @@ public class Ftp extends AbstractFtp {
/** /**
* 判断ftp服务器文件是否存在 * 判断ftp服务器文件是否存在
* *
* @param path 文件路径 * @param path 文件路径
* @return 是否存在 * @return 是否存在
*/ */
@ -356,15 +384,15 @@ public class Ftp extends AbstractFtp {
/** /**
* 上传文件到指定目录可选 * 上传文件到指定目录可选
* *
* <pre> * <pre>
* 1. path为null或""上传到当前路径 * 1. path为null或""上传到当前路径
* 2. path为相对路径则相对于当前路径的子路径 * 2. path为相对路径则相对于当前路径的子路径
* 3. path为绝对路径则上传到此路径 * 3. path为绝对路径则上传到此路径
* </pre> * </pre>
* *
* @param destPath 服务端路径可以为{@code null} 或者相对路径或绝对路径 * @param destPath 服务端路径可以为{@code null} 或者相对路径或绝对路径
* @param file 文件 * @param file 文件
* @return 是否上传成功 * @return 是否上传成功
*/ */
@Override @Override
@ -375,15 +403,15 @@ public class Ftp extends AbstractFtp {
/** /**
* 上传文件到指定目录可选 * 上传文件到指定目录可选
* *
* <pre> * <pre>
* 1. path为null或""上传到当前路径 * 1. path为null或""上传到当前路径
* 2. path为相对路径则相对于当前路径的子路径 * 2. path为相对路径则相对于当前路径的子路径
* 3. path为绝对路径则上传到此路径 * 3. path为绝对路径则上传到此路径
* </pre> * </pre>
* *
* @param file 文件 * @param file 文件
* @param path 服务端路径可以为{@code null} 或者相对路径或绝对路径 * @param path 服务端路径可以为{@code null} 或者相对路径或绝对路径
* @param fileName 自定义在服务端保存的文件名 * @param fileName 自定义在服务端保存的文件名
* @return 是否上传成功 * @return 是否上传成功
*/ */
@ -397,16 +425,15 @@ public class Ftp extends AbstractFtp {
/** /**
* 上传文件到指定目录可选 * 上传文件到指定目录可选
* *
* <pre> * <pre>
* 1. path为null或""上传到当前路径 * 1. path为null或""上传到当前路径
* 2. path为相对路径则相对于当前路径的子路径 * 2. path为相对路径则相对于当前路径的子路径
* 3. path为绝对路径则上传到此路径 * 3. path为绝对路径则上传到此路径
* </pre> * </pre>
* *
* * @param path 服务端路径可以为{@code null} 或者相对路径或绝对路径
* @param path 服务端路径可以为{@code null} 或者相对路径或绝对路径 * @param fileName 文件名
* @param fileName 文件名
* @param fileStream 文件流 * @param fileStream 文件流
* @return 是否上传成功 * @return 是否上传成功
*/ */
@ -443,8 +470,8 @@ public class Ftp extends AbstractFtp {
/** /**
* 下载文件 * 下载文件
* *
* @param path 文件路径 * @param path 文件路径
* @param outFile 输出文件或目录 * @param outFile 输出文件或目录
*/ */
@Override @Override
@ -456,10 +483,10 @@ public class Ftp extends AbstractFtp {
/** /**
* 下载文件 * 下载文件
* *
* @param path 文件路径 * @param path 文件路径
* @param fileName 文件名 * @param fileName 文件名
* @param outFile 输出文件或目录 * @param outFile 输出文件或目录
*/ */
public void download(String path, String fileName, File outFile) { public void download(String path, String fileName, File outFile) {
if (outFile.isDirectory()) { if (outFile.isDirectory()) {
@ -477,10 +504,10 @@ public class Ftp extends AbstractFtp {
/** /**
* 下载文件到输出流 * 下载文件到输出流
* *
* @param path 文件路径 * @param path 文件路径
* @param fileName 文件名 * @param fileName 文件名
* @param out 输出位置 * @param out 输出位置
*/ */
public void download(String path, String fileName, OutputStream out) { public void download(String path, String fileName, OutputStream out) {
String pwd = null; String pwd = null;
@ -503,7 +530,7 @@ public class Ftp extends AbstractFtp {
/** /**
* 获取FTPClient客户端对象 * 获取FTPClient客户端对象
* *
* @return {@link FTPClient} * @return {@link FTPClient}
*/ */
public FTPClient getClient() { public FTPClient getClient() {

View File

@ -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;
}
}

View File

@ -0,0 +1,73 @@
package cn.hutool.extra.pinyin;
import com.github.promeg.pinyinhelper.Pinyin;
/**
* 拼音工具类封装了TinyPinyin
*
* <p>
* TinyPinyin(https://github.com/promeG/TinyPinyin)提供者未提交Maven中央库<br>
* 因此使用
* https://github.com/biezhi/TinyPinyin打包的版本
* </p>
*
* <p>
* 引入
* <pre>
* &lt;dependency&gt;
* &lt;groupId&gt;io.github.biezhi&lt;/groupId&gt;
* &lt;artifactId&gt;TinyPinyin&lt;/artifactId&gt;
* &lt;version&gt;2.0.3.RELEASE&lt;/version&gt;
* &lt;/dependency&gt;
* </pre>
* </p>
*
* @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();
}
}

View File

@ -0,0 +1,7 @@
/**
* 拼音工具封装基于TinyPinyin
*
* @author looly
*
*/
package cn.hutool.extra.pinyin;

View File

@ -1,13 +1,12 @@
package cn.hutool.extra.ssh; package cn.hutool.extra.ssh;
import cn.hutool.core.lang.SimpleCache;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import com.jcraft.jsch.Session; import com.jcraft.jsch.Session;
import java.util.Collection; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
/** /**
* Jsch会话池 * Jsch会话池
@ -20,11 +19,7 @@ public enum JschSessionPool {
/** /**
* SSH会话池keyhostvalueSession对象 * SSH会话池keyhostvalueSession对象
*/ */
private final Map<String, Session> sessionPool = new ConcurrentHashMap<>(); private final SimpleCache<String, Session> cache = new SimpleCache<>(new HashMap<>());
/**
*
*/
private static final Object lock = new Object();
/** /**
* 获取Session不存在返回null * 获取Session不存在返回null
@ -33,7 +28,7 @@ public enum JschSessionPool {
* @return Session * @return Session
*/ */
public Session get(String key) { 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) { public Session getSession(String sshHost, int sshPort, String sshUser, String sshPass) {
final String key = StrUtil.format("{}@{}:{}", sshUser, sshHost, sshPort); final String key = StrUtil.format("{}@{}:{}", sshUser, sshHost, sshPort);
Session session = get(key); return this.cache.get(key, ()-> JschUtil.openSession(sshHost, sshPort, sshUser, sshPass));
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;
} }
/** /**
@ -72,17 +57,7 @@ public enum JschSessionPool {
*/ */
public Session getSession(String sshHost, int sshPort, String sshUser, String prvkey, byte[] passphrase) { public Session getSession(String sshHost, int sshPort, String sshUser, String prvkey, byte[] passphrase) {
final String key = StrUtil.format("{}@{}:{}", sshUser, sshHost, sshPort); final String key = StrUtil.format("{}@{}:{}", sshUser, sshHost, sshPort);
Session session = get(key); return this.cache.get(key, ()->JschUtil.openSession(sshHost, sshPort, sshUser, prvkey, passphrase));
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;
} }
/** /**
@ -92,7 +67,7 @@ public enum JschSessionPool {
* @param session Session * @param session Session
*/ */
public void put(String key, 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 * @param key 主机格式为user@host:port
*/ */
public void close(String key) { public void close(String key) {
Session session = sessionPool.get(key); Session session = get(key);
if (session != null && session.isConnected()) { if (session != null && session.isConnected()) {
session.disconnect(); session.disconnect();
} }
sessionPool.remove(key); this.cache.remove(key);
} }
/** /**
@ -116,7 +91,7 @@ public enum JschSessionPool {
*/ */
public void remove(Session session) { public void remove(Session session) {
if (null != session) { if (null != session) {
final Iterator<Entry<String, Session>> iterator = this.sessionPool.entrySet().iterator(); final Iterator<Entry<String, Session>> iterator = this.cache.iterator();
Entry<String, Session> entry; Entry<String, Session> entry;
while (iterator.hasNext()) { while (iterator.hasNext()) {
entry = iterator.next(); entry = iterator.next();
@ -132,12 +107,13 @@ public enum JschSessionPool {
* 关闭所有SSH连接会话 * 关闭所有SSH连接会话
*/ */
public void closeAll() { public void closeAll() {
Collection<Session> sessions = sessionPool.values(); Session session;
for (Session session : sessions) { for (Entry<String, Session> entry : this.cache) {
if (session.isConnected()) { session = entry.getValue();
if (session != null && session.isConnected()) {
session.disconnect(); session.disconnect();
} }
} }
sessionPool.clear(); cache.clear();
} }
} }

View File

@ -85,9 +85,24 @@ public class JschUtil {
* @return SSH会话 * @return SSH会话
*/ */
public static Session openSession(String sshHost, int sshPort, String sshUser, String sshPass) { 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); final Session session = createSession(sshHost, sshPort, sshUser, sshPass);
try { try {
session.connect(); session.connect(timeout);
} catch (JSchException e) { } catch (JSchException e) {
throw new JschRuntimeException(e); throw new JschRuntimeException(e);
} }
@ -257,7 +272,19 @@ public class JschUtil {
* @since 4.0.3 * @since 4.0.3
*/ */
public static ChannelSftp openSftp(Session session) { 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 * @since 4.5.2
*/ */
public static Channel openChannel(Session session, ChannelType channelType) { 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); final Channel channel = createChannel(session, channelType);
try { try {
channel.connect(); channel.connect(Math.max(timeout, 0));
} catch (JSchException e) { } catch (JSchException e) {
throw new JschRuntimeException(e); throw new JschRuntimeException(e);
} }

View File

@ -4,6 +4,7 @@ import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Filter; import cn.hutool.core.lang.Filter;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.ftp.AbstractFtp; import cn.hutool.extra.ftp.AbstractFtp;
import cn.hutool.extra.ftp.FtpConfig;
import com.jcraft.jsch.ChannelSftp; import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.ChannelSftp.LsEntry; import com.jcraft.jsch.ChannelSftp.LsEntry;
import com.jcraft.jsch.ChannelSftp.LsEntrySelector; import com.jcraft.jsch.ChannelSftp.LsEntrySelector;
@ -59,7 +60,18 @@ public class Sftp extends AbstractFtp {
* @since 4.1.14 * @since 4.1.14
*/ */
public Sftp(String sshHost, int sshPort, String sshUser, String sshPass, Charset charset) { 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 * @since 4.1.14
*/ */
public Sftp(Session session, Charset charset) { public Sftp(Session session, Charset charset) {
super(FtpConfig.create().setCharset(charset));
init(session, charset); init(session, charset);
} }
@ -89,6 +102,7 @@ public class Sftp extends AbstractFtp {
* @param charset 编码 * @param charset 编码
*/ */
public Sftp(ChannelSftp channel, Charset charset) { public Sftp(ChannelSftp channel, Charset charset) {
super(FtpConfig.create().setCharset(charset));
init(channel, charset); init(channel, charset);
} }
// ---------------------------------------------------------------------------------------- Constructor end // ---------------------------------------------------------------------------------------- Constructor end
@ -103,13 +117,28 @@ public class Sftp extends AbstractFtp {
* @param charset 编码 * @param charset 编码
*/ */
public void init(String sshHost, int sshPort, String sshUser, String sshPass, Charset 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); 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) { public void init(Session session, Charset charset) {
this.session = session; 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 编码 * @param charset 编码
*/ */
public void init(ChannelSftp channel, Charset charset) { public void init(ChannelSftp channel, Charset charset) {
this.charset = charset; this.ftpConfig.setCharset(charset);
try { try {
channel.setFilenameEncoding(charset.toString()); channel.setFilenameEncoding(charset.toString());
} catch (SftpException e) { } catch (SftpException e) {
@ -139,8 +168,8 @@ public class Sftp extends AbstractFtp {
@Override @Override
public Sftp reconnectIfTimeout() { public Sftp reconnectIfTimeout() {
if (false == this.cd("/") && StrUtil.isNotBlank(this.host)) { if (false == this.cd("/") && StrUtil.isNotBlank(this.ftpConfig.getHost())) {
init(this.host, this.port, this.user, this.password, this.charset); init(this.ftpConfig);
} }
return this; return this;
} }
@ -414,9 +443,9 @@ public class Sftp extends AbstractFtp {
@Override @Override
public String toString() { public String toString() {
return "Sftp{" + return "Sftp{" +
"host='" + host + '\'' + "host='" + this.ftpConfig.getHost() + '\'' +
", port=" + port + ", port=" + this.ftpConfig.getPort() +
", user='" + user + '\'' + ", user='" + this.ftpConfig.getUser() + '\'' +
'}'; '}';
} }

View File

@ -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);
}
}