add session

This commit is contained in:
Looly 2023-09-21 21:14:00 +08:00
parent 8d7b890b3e
commit 8a0e477f69
39 changed files with 707 additions and 238 deletions

View File

@ -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<K, V> implements Iterable<Map.Entry<K, V>>, Serializabl
}
});
}
/**
* 获取所有键
*
* @return 所有键
*/
public List<K> keys(){
return this.rawMap.keySet().stream().map(Mutable::get).collect(Collectors.toList());
}
}

View File

@ -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}<br>
@ -136,6 +134,11 @@ public class ListServiceLoader<S> extends AbsServiceLoader<S> {
return this.serviceNames.size();
}
@Override
public List<String> getServiceNames(){
return ListUtil.view(this.serviceNames);
}
/**
* 获取指定服务的实现类
*
@ -148,7 +151,12 @@ public class ListServiceLoader<S> extends AbsServiceLoader<S> {
return null;
}
return ClassLoaderUtil.loadClass(serviceClassName);
return getServiceClass(serviceClassName);
}
@Override
public Class<S> getServiceClass(final String serviceName) {
return ClassLoaderUtil.loadClass(serviceName);
}
/**
@ -162,7 +170,12 @@ public class ListServiceLoader<S> extends AbsServiceLoader<S> {
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<S> extends AbsServiceLoader<S> {
@Override
public S next() {
return getServiceByName(nameIter.next());
return getService(nameIter.next());
}
};
}
@ -223,7 +236,7 @@ public class ListServiceLoader<S> extends AbsServiceLoader<S> {
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<S> extends AbsServiceLoader<S> {
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));
}
/**
* 创建服务无缓存
*

View File

@ -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<S> extends AbsServiceLoader<S> {
return this.serviceProperties.size();
}
/**
* 获取指定服务的实现类
*
* @param serviceName 服务名称
* @return 服务名称对应的实现类
*/
@Override
public List<String> getServiceNames() {
return ListUtil.view(this.serviceCache.keys());
}
@Override
public Class<S> getServiceClass(final String serviceName) {
final String serviceClassName = this.serviceProperties.getProperty(serviceName);
if (StrUtil.isBlank(serviceClassName)) {
@ -143,12 +145,7 @@ public class MapServiceLoader<S> extends AbsServiceLoader<S> {
return ClassLoaderUtil.loadClass(serviceClassName);
}
/**
* 获取指定名称对应的服务使用缓存多次调用只返回相同的服务对象
*
* @param serviceName 服务名称
* @return 服务对象
*/
@Override
public S getService(final String serviceName) {
return this.serviceCache.get(serviceName, () -> createService(serviceName));
}

View File

@ -12,6 +12,8 @@
package org.dromara.hutool.core.spi;
import java.util.List;
/**
* SPI服务加载接口<br>
* 用户实现此接口用于制定不同的服务加载方式
@ -19,7 +21,7 @@ package org.dromara.hutool.core.spi;
* @param <S> 服务对象类型
* @author looly
*/
public interface ServiceLoader<S> extends Iterable<S>{
public interface ServiceLoader<S> extends Iterable<S> {
/**
* 加载服务
@ -32,4 +34,27 @@ public interface ServiceLoader<S> extends Iterable<S>{
* @return 总数
*/
int size();
/**
* 获取服务名称列表
*
* @return 服务名称列表
*/
List<String> getServiceNames();
/**
* 获取指定服务的实现类
*
* @param serviceName 服务名称
* @return 服务名称对应的实现类
*/
Class<S> getServiceClass(String serviceName);
/**
* 获取指定名称对应的服务
*
* @param serviceName 服务名称
* @return 服务对象
*/
S getService(String serviceName);
}

View File

@ -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);
}
/**
* 获得全局单例的拼音引擎
*

View File

@ -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<PinyinEngine> 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自动创建对应的拼音引擎对象<br>
* 推荐创建的引擎单例使用此方法每次调用会返回新的引擎

View File

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

View File

@ -29,4 +29,4 @@
*
* @author looly
*/
package org.dromara.hutool.extra.pinyin.engine.houbbpinyin;
package org.dromara.hutool.extra.pinyin.engine.houbb;

View File

@ -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) {

View File

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

View File

@ -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<Object>, Closeable {
}

View File

@ -0,0 +1,85 @@
/*
* 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.HutoolException;
/**
* SSH异常
*
* @author xiaoleilu
*/
public class SshException extends HutoolException {
private static final long serialVersionUID = 1L;
/**
* 构造
*
* @param e 异常
*/
public SshException(final Throwable e) {
super(e);
}
/**
* 构造
*
* @param message 消息
*/
public SshException(final String message) {
super(message);
}
/**
* 构造
*
* @param messageTemplate 消息模板
* @param params 参数
*/
public SshException(final String messageTemplate, final Object... params) {
super(messageTemplate, params);
}
/**
* 构造
*
* @param message 消息
* @param cause 被包装的子异常
*/
public SshException(final String message, final Throwable cause) {
super(message, cause);
}
/**
* 构造
*
* @param message 消息
* @param cause 被包装的子异常
* @param enableSuppression 是否启用抑制
* @param writableStackTrace 堆栈跟踪是否应该是可写的
*/
public SshException(final String message, final Throwable cause, final boolean enableSuppression, final boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
/**
* 构造
*
* @param cause 被包装的子异常
* @param messageTemplate 消息模板
* @param params 参数
*/
public SshException(final Throwable cause, final String messageTemplate, final Object... params) {
super(cause, messageTemplate, params);
}
}

View File

@ -10,65 +10,55 @@
* See the Mulan PSL v2 for more details.
*/
package org.dromara.hutool.extra.ssh;
package org.dromara.hutool.extra.ssh.engine.ganymed;
import ch.ethz.ssh2.Connection;
import ch.ethz.ssh2.Session;
import ch.ethz.ssh2.StreamGobbler;
import org.dromara.hutool.core.io.IORuntimeException;
import org.dromara.hutool.core.io.IoUtil;
import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.extra.ssh.Connector;
import org.dromara.hutool.extra.ssh.Session;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.Charset;
/**
* Ganymed-SSH2封装https://www.ganymed.ethz.ch/ssh2/
* {@link ch.ethz.ssh2.Session}包装
*
* @author looly
* @since 5.5.3
*/
public class GanymedUtil {
public class GanymedSession implements Session {
private final ch.ethz.ssh2.Session raw;
/**
* 连接到服务器
* 构造
*
* @param sshHost 主机
* @param sshPort 端口
* @return {@link Connection}
* @param connector {@link Connector}保存连接和验证信息等
*/
public static Connection connect(final String sshHost, final int sshPort) {
final Connection conn = new Connection(sshHost, sshPort);
try {
conn.connect();
} catch (final IOException e) {
throw new IORuntimeException(e);
}
return conn;
public GanymedSession(final Connector connector) {
this(openSession(connector));
}
/**
* 打开远程会话
* 构造
*
* @param sshHost 主机
* @param sshPort 端口
* @param sshUser 用户名如果为null默认root
* @param sshPass 密码
* @return {@link Session}
* @param raw {@link ch.ethz.ssh2.Session}
*/
public static Session openSession(final String sshHost, final int sshPort, String sshUser, final String sshPass) {
// 默认root用户
if (StrUtil.isEmpty(sshUser)) {
sshUser = "root";
}
public GanymedSession(final ch.ethz.ssh2.Session raw) {
this.raw = raw;
}
final Connection connect = connect(sshHost, sshPort);
try {
connect.authenticateWithPassword(sshUser, sshPass);
return connect.openSession();
} catch (final IOException e) {
throw new IORuntimeException(e);
@Override
public ch.ethz.ssh2.Session getRaw() {
return raw;
}
@Override
public void close() throws IOException {
if (raw != null) {
raw.close();
}
}
@ -78,24 +68,21 @@ public class GanymedUtil {
* 此方法单次发送一个命令到服务端不读取环境变量执行结束后自动关闭Session不会产生阻塞
* </p>
*
* @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可能产生阻塞
* </p>
*
* @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);
}
}
}

View File

@ -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类型

View File

@ -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端口上. <br>
* 即数据从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方式
* <p>
* 此方法单次发送一个命令到服务端不读取环境变量执行结束后自动关闭channel不会产生阻塞
* </p>
*
* @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命令
* <p>
* 此方法单次发送一个命令到服务端自动读取环境变量执行结束后自动关闭channel不会产生阻塞
* </p>
*
* @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;
}
}

View File

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

View File

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

View File

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

View File

@ -11,7 +11,7 @@
*/
/**
* SSH 引擎封装
* Jsch(http://www.jcraft.com/jsch/) 引擎封装
*
* @author looly
*/

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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(){

View File

@ -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(){

View File

@ -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(){

View File

@ -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(){

View File

@ -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(){

View File

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

View File

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

View File

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

View File

@ -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<String, Object> 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<String, Object> 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<String, Object> 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服务器
*

View File

@ -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<ClientEngine> 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自动创建对应的拼音引擎对象<br>
* 推荐创建的引擎单例使用此方法每次调用会返回新的引擎

View File

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

View File

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

View File

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

View File

@ -20,7 +20,7 @@ import org.junit.jupiter.api.Test;
public class IssueI7ZRJUTest {
@SuppressWarnings({"resource", "TestFailedLine"})
@SuppressWarnings({"resource"})
@Test
@Disabled
void getBadSSlTest() {

View File

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