All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.dromara.hutool.extra.ssh.SshjSftp Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2023 looly([email protected])
 * 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:
 *          http://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.collection.CollUtil;
import org.dromara.hutool.core.io.IoUtil;
import org.dromara.hutool.core.util.CharsetUtil;
import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.extra.ftp.AbstractFtp;
import org.dromara.hutool.extra.ftp.FtpConfig;
import org.dromara.hutool.extra.ftp.FtpException;
import net.schmizz.sshj.SSHClient;
import net.schmizz.sshj.connection.channel.direct.Session;
import net.schmizz.sshj.sftp.RemoteResourceInfo;
import net.schmizz.sshj.sftp.SFTPClient;
import net.schmizz.sshj.transport.verification.PromiscuousVerifier;
import net.schmizz.sshj.xfer.FileSystemFile;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.List;

/**
 * 在使用jsch 进行sftp协议下载文件时,总是中文乱码,而该框架源码又不允许设置编码。故:站在巨人的肩膀上,此类便孕育而出。
 *
 * 

* 基于sshj 框架适配。
* 参考:https://github.com/hierynomus/sshj *

* * @author youyongkun * @since 5.7.19 */ public class SshjSftp extends AbstractFtp { private SSHClient ssh; private SFTPClient sftp; /** * 构造,使用默认端口 * * @param sshHost 主机 */ public SshjSftp(final String sshHost) { this(new FtpConfig(sshHost, 22, null, null, CharsetUtil.UTF_8)); } /** * 构造 * * @param sshHost 主机 * @param sshUser 用户名 * @param sshPass 密码 */ public SshjSftp(final String sshHost, final String sshUser, final String sshPass) { this(new FtpConfig(sshHost, 22, sshUser, sshPass, CharsetUtil.UTF_8)); } /** * 构造 * * @param sshHost 主机 * @param sshPort 端口 * @param sshUser 用户名 * @param sshPass 密码 */ public SshjSftp(final String sshHost, final int sshPort, final String sshUser, final String sshPass) { this(new FtpConfig(sshHost, sshPort, sshUser, sshPass, CharsetUtil.UTF_8)); } /** * 构造 * * @param sshHost 主机 * @param sshPort 端口 * @param sshUser 用户名 * @param sshPass 密码 * @param charset 编码 */ public SshjSftp(final String sshHost, final int sshPort, final String sshUser, final String sshPass, final Charset charset) { this(new FtpConfig(sshHost, sshPort, sshUser, sshPass, charset)); } /** * 构造 * * @param config FTP配置 * @since 5.3.3 */ protected SshjSftp(final FtpConfig config) { super(config); init(); } /** * SSH 初始化并创建一个sftp客户端. * * @author youyongkun * @since 5.7.18 */ public void init() { this.ssh = new SSHClient(); ssh.addHostKeyVerifier(new PromiscuousVerifier()); try { ssh.connect(ftpConfig.getHost(), ftpConfig.getPort()); ssh.authPassword(ftpConfig.getUser(), ftpConfig.getPassword()); ssh.setRemoteCharset(ftpConfig.getCharset()); this.sftp = ssh.newSFTPClient(); } catch (final IOException e) { throw new FtpException("sftp 初始化失败.", e); } } @Override public AbstractFtp reconnectIfTimeout() { if (StrUtil.isBlank(this.ftpConfig.getHost())) { throw new FtpException("Host is blank!"); } try { this.cd(StrUtil.SLASH); } catch (final FtpException e) { close(); init(); } return this; } @Override public boolean cd(final String directory) { final String exec = String.format("cd %s", directory); command(exec); final String pwd = pwd(); return pwd.equals(directory); } @Override public String pwd() { return command("pwd"); } @Override public boolean mkdir(final String dir) { try { sftp.mkdir(dir); } catch (final IOException e) { throw new FtpException(e); } return containsFile(dir); } @Override public List ls(final String path) { final List infoList; try { infoList = sftp.ls(path); } catch (final IOException e) { throw new FtpException(e); } if (CollUtil.isNotEmpty(infoList)) { return CollUtil.map(infoList, RemoteResourceInfo::getName); } return null; } @Override public boolean delFile(final String path) { try { sftp.rm(path); return !containsFile(path); } catch (final IOException e) { throw new FtpException(e); } } @Override public boolean delDir(final String dirPath) { try { sftp.rmdir(dirPath); return !containsFile(dirPath); } catch (final IOException e) { throw new FtpException(e); } } @Override public boolean uploadFile(final String destPath, final File file) { try { sftp.put(new FileSystemFile(file), destPath); return containsFile(destPath); } catch (final IOException e) { throw new FtpException(e); } } @Override public void download(final String path, final File outFile) { try { sftp.get(path, new FileSystemFile(outFile)); } catch (final IOException e) { throw new FtpException(e); } } @Override public void recursiveDownloadFolder(final String sourcePath, final File destDir) { final List files = ls(sourcePath); if (files != null && !files.isEmpty()) { files.forEach(path -> download(sourcePath + "/" + path, destDir)); } } @Override public void close() { try { sftp.close(); ssh.disconnect(); } catch (final IOException e) { throw new FtpException(e); } } /** * 是否包含该文件 * * @param fileDir 文件绝对路径 * @return true:包含 false:不包含 * @author youyongkun * @since 5.7.18 */ public boolean containsFile(final String fileDir) { try { sftp.lstat(fileDir); return true; } catch (final IOException e) { return false; } } /** * 执行Linux 命令 * * @param exec 命令 * @return 返回响应结果. * @author youyongkun * @since 5.7.19 */ public String command(final String exec) { Session session = null; try { session = ssh.startSession(); final Session.Command command = session.exec(exec); final InputStream inputStream = command.getInputStream(); return IoUtil.read(inputStream, DEFAULT_CHARSET); } catch (final Exception e) { throw new FtpException(e); } finally { IoUtil.closeQuietly(session); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy