package com.koukay.Controller.Controllers.util;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.SftpATTRS;
import com.jcraft.jsch.SftpException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.concurrent.TimeUnit;
@Component
@Slf4j
public class SFTPClient {
private final static Logger log = LoggerFactory.getLogger(SFTPClient.class);
@Value("${sftp.directory}")
private String ftpPath;
private volatile boolean isConfig = false;
private ChannelSftpPool channelSftpPool;
@Value("${sftp.host}")
private String host ;// 服务器ip地址
@Value("${sftp.username}")
private String username ; //账号
@Value("${sftp.password}")
private String password ;//密码
@Value("${sftp.port}")
private int port ;// 端口号
private final Cache cache = Caffeine.newBuilder()
.maximumSize(1000)
.expireAfterAccess(15, TimeUnit.MINUTES)
.build();
private void initSFTPConfig() {
log();
if (isConfig) {
return;
}
isConfig = true;
if (log.isDebugEnabled()) {
log.debug("加载SFTP配置:{}");
}
int ftpPort = this.port;
String ftpServer =this.host;
String ftpAccount = this.username;
String ftpPassword = this.password;
//如果没有配置路径则获取登录用户根目录
if (StringUtils.isEmpty(ftpPath)) {
ftpPath = ".";
}
ftpPath = ftpPath.replaceAll("\\\\", "/");
channelSftpPool = new ChannelSftpPool(new ChannelSftpPoolConfig(), new ChannelSftpPooledObjectFactory(false,
null, ftpServer, ftpAccount, ftpPassword, ftpPort));
}
private void log() {
if (channelSftpPool != null) {
log.info("getMaxTotal = {},getNumActive = {},getNumIdle = {},createCount = {},borrowedCount = {},destroyedCount = {}",
channelSftpPool.internalPool.getMaxTotal(),
channelSftpPool.internalPool.getNumActive(),
channelSftpPool.internalPool.getNumIdle(),
channelSftpPool.internalPool.getCreatedCount(),
channelSftpPool.internalPool.getBorrowedCount(),
channelSftpPool.internalPool.getDestroyedCount());
}
}
public void rebuild() {
isConfig = false;
if (channelSftpPool != null) {
channelSftpPool.close();
}
initSFTPConfig();
}
/**
* 创建SFTP连接
*
* @return ChannelSftp
* @throws Exception
*/
public ChannelSftp createSftp() {
initSFTPConfig();
return channelSftpPool.getResource();
}
/**
* 关闭连接
*
* @param sftp sftp
*/
public void disconnect(ChannelSftp sftp) {
if (sftp != null) {
channelSftpPool.returnResourceObject(sftp);
}
}
/**
* 上传文件
*
* @param fileName
* @param inputStream
* @return
* @throws Exception
*/
public boolean uploadFile(String fileName, InputStream inputStream) throws Exception {
initSFTPConfig();
ChannelSftp sftp = this.channelSftpPool.getResource();
createFolder(sftp);
try {
sftp.put(inputStream, getFileName(fileName), ChannelSftp.OVERWRITE);
return true;
} catch (Exception e) {
log.error("Upload file failure. TargetPath: {}", fileName, e);
throw new Exception("Upload File failure");
} finally {
if (sftp != null) this.disconnect(sftp);
}
}
/**
* 删除文件
*
* @param fileName
* @return
* @throws Exception
*/
public boolean deleteFile(String fileName) throws Exception {
initSFTPConfig();
ChannelSftp sftp = this.channelSftpPool.getResource();
try {
fileName = getFileName(fileName);
sftp.rm(fileName);
return true;
} catch (Exception e) {
log.error("Delete file failure. TargetPath: {}", fileName, e);
throw new Exception("Delete File failure");
} finally {
if (sftp != null) this.disconnect(sftp);
}
}
/**
* 下载文件
*
* @param fileName
* @return
* @throws Exception
*/
public void downloadFile(String fileName, HttpServletResponse response) throws Exception {
initSFTPConfig();
ChannelSftp sftp = this.channelSftpPool.getResource();
OutputStream outputStream = response.getOutputStream();
try {
fileName = getFileName(fileName);
log.info("sftp pwd = {},fileName = {}", sftp.pwd(), fileName);
byte[] bytes = (byte[]) cache.getIfPresent(fileName);
if (bytes == null) {
bytes = getFromSftp(fileName);
}
if (bytes != null) {
IOUtils.copy(new ByteArrayInputStream(bytes), outputStream);
} else {
log.info("sftp fileName = {} non-existent!!!", fileName);
}
} catch (Exception e) {
log.error("Download file failure. TargetPath: {}", fileName, e);
throw new Exception("Download File failure");
} finally {
if (sftp != null) this.disconnect(sftp);
}
}
public byte[] getFromSftp(String fileName) {
initSFTPConfig();
ChannelSftp sftp = this.channelSftpPool.getResource();
try (InputStream in = sftp.get(fileName)) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
IOUtils.copy(in, out);
byte[] bytes = out.toByteArray();
return bytes;
} catch (SftpException | IOException e) {
log.error(e.getMessage(), e);
} finally {
if (sftp != null) this.disconnect(sftp);
}
return null;
}
/**
* 下载文件到特定目录
*
* @param fileName
* @return
* @throws Exception
*/
public void downloadFileToDir(String fileName, String dirPath) throws Exception {
initSFTPConfig();
ChannelSftp sftp = this.channelSftpPool.getResource();
File file = new File(dirPath+File.separator+fileName);
FileOutputStream fos = new FileOutputStream(file);
try {
fileName = getFileName(fileName);
log.info("sftp pwd = {},fileName = {}", sftp.pwd(), fileName);
sftp.get(fileName, fos);
fos.flush();
} catch (Exception e) {
log.error("Download file failure. TargetPath: {}", fileName, e);
throw new Exception("Download File failure");
} finally {
if (sftp != null) this.disconnect(sftp);
if (fos != null) {
fos.close();
}
}
}
public String getFileName(String fileName) {
if (ftpPath.endsWith("/")) {
fileName = ftpPath + fileName;
} else {
fileName = ftpPath + "/" + fileName;
}
return fileName;
}
/**
* 校验是否可以连接成功
*
* @return 是否成功
*/
public Boolean checkSftp() {
isConfig = false;
if (channelSftpPool != null) {
channelSftpPool.close();
}
initSFTPConfig();
ChannelSftp sftp = null;
try {
sftp = this.channelSftpPool.getResource();
sftp.cd(".");
} catch (Exception e) {
log.debug(e.getMessage());
return false;
} finally {
if (sftp != null) this.disconnect(sftp);
}
return true;
}
/**
* 判断文件是否存在,删除前判断
* @param fileName
* @return
*/
public boolean fileExist(String fileName) {
initSFTPConfig();
ChannelSftp sftp = null;
try {
sftp = this.channelSftpPool.getResource();
SftpATTRS attrs = sftp.lstat(getFileName(fileName));
return true;
}catch (SftpException e) {
if (e.id == ChannelSftp.SSH_FX_NO_SUCH_FILE) {
log.info("file {} not exist.", fileName);
}
}finally {
if (sftp != null) this.disconnect(sftp);
}
return false;
}
/**
* 判断文件夹是否存在,不存在则创建
* @param sftp
* @return
*/
public boolean createFolder(ChannelSftp sftp) {
boolean exist=true;
String[] splitDirs = ftpPath.split("/");
try {
//判断文件夹是否存在
sftp.stat(ftpPath);
} catch (SftpException e) {
//不存在的话逐级判断并创建
for (int i = 0; i < splitDirs.length; i++) {
SftpATTRS attr =null;
String splitDir = splitDirs[i];
if (i==0) {
try {
//进入根目录
sftp.cd("/");
} catch (SftpException sftpException) {
sftpException.printStackTrace();
}
}
if (StringUtils.isNotEmpty(splitDir)) {
try {
//判断每级文件夹是否存在
attr = sftp.stat(splitDir);
sftp.cd(splitDir);
} catch (SftpException sftpException) {
if (attr==null){
try {
log.info("文件夹不存在,正在创建:" + splitDir);
sftp.mkdir(splitDir);
log.info("完成创建子目录:" + splitDir);
exist= true;
sftp.cd(splitDir);
} catch (SftpException sftpException1) {
exist=false;
log.info("文件夹创建失败:" + sftpException1);
}
}
}
}
}
}
return exist;
}
}