import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.ftp.FtpException;
import cn.hutool.extra.ssh.ChannelType;
import cn.hutool.extra.ssh.JschRuntimeException;
import com.jcraft.jsch.*;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
/**
* sftp下载工具类
* @author mal
* @date 2021-09-02 15:40
*/
public class SftpUtil {
private static final Logger logger = LoggerFactory.getLogger(SftpUtil.class);
private Session session;
private ChannelSftp sftp;
private String sshUser;
private String sshPass;
private String privateKeyPath;
private String sshHost;
private int sshPort;
public SftpUtil(String sshUser, String sshPass, String sshHost, int sshPort) {
this.sshUser = sshUser;
this.sshPass = sshPass;
this.sshHost = sshHost;
this.sshPort = sshPort;
}
public SftpUtil(String sshUser, String sshHost, int sshPort, String privateKeyPath) {
Assert.notEmpty(privateKeyPath, "privateKeyPath Path must be not empty!");
this.sshUser = sshUser;
this.sshHost = sshHost;
this.sshPort = sshPort;
this.privateKeyPath = privateKeyPath;
}
private SftpUtil() {
}
/**
* 登录sftp
*/
public void login() {
Assert.notEmpty(sshUser, "sshUser Path must be not empty!");
Assert.notEmpty(sshHost, "sshHost Path must be not empty!");
Assert.isTrue(sshPort > 0, "SSH port must be > 0");
JSch.setLogger(new JschLogPrint());
final JSch jSch = new JSch();
if (privateKeyPath != null) {
try {
jSch.addIdentity(privateKeyPath);
} catch (JSchException e) {
logger.error("login,addIdentity error", e);
throw new JschRtException("sftp私钥地址[" + privateKeyPath + "]解析秘钥失败!请检查私钥文件是否存在");
}
}
try {
this.session = jSch.getSession(sshUser, sshHost, sshPort);
// 设置第一次登录的时候提示,可选值:(ask | yes | no)
this.session.setConfig("StrictHostKeyChecking", "no");
this.session.setConfig("kex", "diffie-hellman-group1-sha1");
this.session.connect(10000);
logger.info("用户[{}]成功登录", sshUser);
} catch (JSchException e) {
logger.error("login,getSession error", e);
throw new JschRtException("根据sshUser=[" + sshUser + "],sshHost=[" + sshHost + "],sshPort=[" + sshPort + "],创建session失败!");
}
if (sshPass != null) {
session.setPassword(sshPass);
}
Channel channel;
try {
channel = session.openChannel(ChannelType.SFTP.getValue());
channel.connect(10000);
} catch (JSchException e) {
logger.error("login,openChannel error!", e);
throw new JschRtException("sftp打开消息通道失败!");
}
sftp = (ChannelSftp) channel;
}
/**
*
* @param directory
* @return
* @throws SftpRtException
*/
public boolean cd(String directory) throws FtpException {
if (StrUtil.isBlank(directory)) {
// 当前目录
return true;
}
try {
sftp.cd(directory.replace('\', '/'));
return true;
} catch (SftpException e) {
throw new SftpRtException(e);
}
}
/**
* 判断远程SFTP服务器上是否存在某个文件
* @param directory 目录
* @param fileName 文件名
* @return 是否存在
*/
public boolean isExists(String directory, String fileName){
boolean isHave = false;
try {
if (StringUtils.isNotBlank(directory)) {
sftp.cd(directory);
}
SftpATTRS attrs = sftp.stat(fileName);
if(attrs != null){
isHave = true;
}
} catch (Exception e) {
logger.error("isExists,directory = [" + directory + "], fileName = [" + fileName + "],error", e);
}
return isHave;
}
/**
* 下载文件
* @param directory 下载目录
* @param downloadFile 下载的文件名
* @param saveFile 保存的文件的绝对路径
* @throws SftpException
*/
public void download(String directory, String downloadFile, String saveFile) throws SftpException {
if (directory != null && directory.length() > 0) {
sftp.cd(directory);
}
sftp.get(downloadFile, saveFile);
}
/**
* 下载文件
* @param directory 下载目录
* @param downloadFile 下载的文件名
* @param saveFile 保存的文件的绝对路径
* @throws SftpException
*/
public void download(String directory, String downloadFile, File saveFile) throws SftpException, IOException {
logger.info("download start,directory = 【{}】, downloadFile = 【{}】, saveFile = 【{}】", directory, downloadFile, saveFile.getAbsolutePath());
if (directory != null && directory.length() > 0) {
sftp.cd(directory);
}
try (OutputStream out = new FileOutputStream(saveFile)){
sftp.get(downloadFile, out);
logger.info("download end,directory = 【{}】, downloadFile = 【{}】, saveFile = 【{}】", directory, downloadFile, saveFile.getAbsolutePath());
}
}
/**
* 下载文件
* @param directory 下载目录
* @param downloadFile 下载的文件名
* @param out 目标流
*/
public void download(String directory, String downloadFile, OutputStream out) throws SftpException {
if (directory != null && directory.length() > 0) {
sftp.cd(directory);
}
sftp.get(downloadFile, out);
}
/**
* 下载文件
* @param directory 下载目录
* @param downloadFile 下载的文件名
* @return 字节数组
*/
public byte[] download(String directory, String downloadFile) throws SftpException, IOException {
if (directory != null && directory.length() > 0) {
sftp.cd(directory);
}
InputStream is = sftp.get(downloadFile);
return IOUtils.toByteArray(is);
}
/**
* 获取HOME路径
* @return
*/
public String home() {
try {
return sftp.getHome();
} catch (SftpException e) {
throw new JschRuntimeException(e);
}
}
/**
* 关闭连接 server
*/
public void logout(){
if (sftp != null) {
if (sftp.isConnected()) {
sftp.disconnect();
}
}
if (session != null) {
if (session.isConnected()) {
session.disconnect();
}
}
}
class JschLogPrint implements com.jcraft.jsch.Logger{
@Override
public boolean isEnabled(int level) {
return true;
}
@Override
public void log(int level, String message) {
logger.info(message);
}
}
}
这里边使用到了hutool 工具类
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.2</version>
</dependency>