一、项目结构
SFTP
SftpProperties --配置载入
SftpFactory ---连接工厂
SftpPool ----连接池
SftpHelper ----辅助方法,下载
<!-- ftp远程工具 -->
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<version>3.3</version>
<!-- https://mvnrepository.com/artifact/com.jcraft/jsch -->
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.53</version>
</dependency>
<!-- pool 对象池 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
config:
# 协议
sftpClientProtocol: sftp
# ip地址
sftpClientHost: ip
# 端口
sftpClientPort: 2222
# 用户名
sftpClientUsername: name
# 密码
sftpClientPassword: password
# 根路径
sftpClientRoot: /
fileBackupPaths: D:/2023/TEST/LDPBACKS/
remotePaths: /home/LDP/
#本地路径
localPaths: D:/2023/TEST/LDP/
#
sftpClientSessionStrictHostKeyChecking: no
# session连接超时时间
sftpClientSessionConnectTimeout: 15000
# channel连接超时时间
sftpClientChannelConnectedTimeout: 15000
sftpMaxTotal: 100
sftpMinIdel: 2
sftpMaxIdle: 20
4.1 SftpProperties.class
import com.jcraft.jsch.ChannelSftp;
import lombok.Data;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
/**
* @author gyDeBug
* @description: 配置文件和实体注入
* @param:
* @return:
* @date:2021/11/30
*/
@Data
@Component
@Configuration
public class SftpProperties {
private String host;
private int port;
private String username;
private String password;
private String root;
private String localPath;
private String fileBackupPaths;
private String remotePaths;
private Integer sessionConnectTimeout;
private Integer channelConnectedTimeout;
private Pool pool = new Pool();
@Value("${config.sftpClientHost}")
public void setHost(String host) {
this.host = host;
}
@Value("${config.sftpClientPort}")
public void setPort(int port) {
this.port = port;
}
@Value("${config.sftpClientUsername}")
public void setUsername(String username) {
this.username = username;
}
@Value("${config.sftpClientPassword}")
public void setPassword(String password) {
this.password = password;
}
@Value("${config.sftpClientRoot}")
public void setRoot(String root) {
this.root = root;
}
@Value("${config.localPaths}")
public void setLocalPath(String localPath) {
this.localPath = localPath;
}
@Value("${config.fileBackupPaths}")
public void setFileBackupPaths(String fileBackupPaths) {
this.fileBackupPaths = fileBackupPaths;
}
@Value("${config.remotePaths}")
public void setRemotePaths(String remotePaths) {
this.remotePaths = remotePaths;
}
@Value("${config.sftpClientSessionConnectTimeout}")
public void setSessionConnectTimeout(Integer sessionConnectTimeout) {
this.sessionConnectTimeout = sessionConnectTimeout;
}
@Value("${config.sftpClientChannelConnectedTimeout}")
public void setChannelConnectedTimeout(Integer channelConnectedTimeout) {
this.channelConnectedTimeout = channelConnectedTimeout;
}
public static class Pool extends GenericObjectPoolConfig<ChannelSftp> {
private int maxTotal = 100;
允许最大空闲对象数
private int maxIdle = 80;
// 允许最小空闲对象数
private int minIdle = 10;
//控制获取不到连接时超时时间,避免无限等待
private long maxWaitMillis = 60000;
public Pool() {
super();
}
@Override
public long getMaxWaitMillis() {
return maxWaitMillis;
}
@Override
public void setMaxWaitMillis(long maxWaitMillis) {
this.maxWaitMillis = maxWaitMillis;
}
@Override
public int getMaxTotal() {
return maxTotal;
}
@Override
public void setMaxTotal(int maxTotal) {
this.maxTotal = maxTotal;
}
@Override
public int getMaxIdle() {
return maxIdle;
}
@Override
public void setMaxIdle(int maxIdle) {
this.maxIdle = maxIdle;
}
@Override
public int getMinIdle() {
return minIdle;
}
@Override
public void setMinIdle(int minIdle) {
this.minIdle = minIdle;
}
}
}
4.2 SftpFactory.class
import com.airtravel.odb.common.wechat.WechatService;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.pool2.BasePooledObjectFactory;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import java.util.Properties;
@Data
@Slf4j
public class SftpFactory extends BasePooledObjectFactory<ChannelSftp> {
private SftpProperties properties;
@Autowired
private Environment environment;
public SftpFactory(SftpProperties properties) {
this.properties = properties;
}
@Override
public ChannelSftp create() {
try {
JSch jsch = new JSch();
Session sshSession = jsch.getSession(properties.getUsername(), properties.getHost(), properties.getPort());
sshSession.setPassword(properties.getPassword());
Properties sshConfig = new Properties();
sshConfig.put("StrictHostKeyChecking", "no");
sshSession.setConfig(sshConfig);
sshSession.connect(properties.getSessionConnectTimeout());
ChannelSftp channel = (ChannelSftp) sshSession.openChannel("sftp");
channel.connect(properties.getChannelConnectedTimeout());
return channel;
} catch (JSchException e) {
log.info("连接sfpt失败:"+e.getMessage());
e.printStackTrace();
return null;
}
}
@Override
public PooledObject<ChannelSftp> wrap(ChannelSftp channelSftp) {
return new DefaultPooledObject<>(channelSftp);
}
// 销毁对象
@Override
public void destroyObject(PooledObject<ChannelSftp> p) {
ChannelSftp channelSftp = p.getObject();
channelSftp.disconnect();
}
}
4.3 SftpPool.class
import com.jcraft.jsch.ChannelSftp;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
@Data
@Slf4j
public class SftpPool {
private GenericObjectPool<ChannelSftp> pool;
@Autowired
private Environment environment;
public SftpPool(SftpFactory factory) {
this.pool = new GenericObjectPool<>(factory, factory.getProperties().getPool());
// 当池中对象用完时,请求新的对象所要执行的动作
// public byte whenExhaustedAction = DEFAULT_WHEN_EXHAUSTED_ACTION;
// 是否在从池中取出对象前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个.
// 在从对象池获取对象时是否检测对象有效(true : 是) , 配置true会降低性能;
this.pool.setTestOnBorrow(true);
// 是否在向池中归还对象前进行检验,如果检验失败
//在向对象池中归还对象时是否检测对象有效(true : 是) , 配置true会降低性能
this.pool.setTestOnReturn(true);
// 连接是否被空闲连接回收器(如果有)进行检验.如果检测失败,则连接将被从池中去除
this.pool.setTestWhileIdle(true);
// 在空闲连接回收器线程运行期间休眠的时间毫秒数. 如果设置为非正数,则不运行空闲连接回收器线程.空闲连接检测的周期(单位毫秒)
this.pool.setTimeBetweenEvictionRunsMillis(80000);
// 设定在进行后台对象清理时,每次检查对象数,检测空闲对象线程每次运行时检测的空闲对象的数量;
// public int numTestsPerEvictionRun = GenericObjectPool.DEFAULT_NUM_TESTS_PER_EVICTION_RUN;
// this.pool.setNumTestsPerEvictionRun(80000);
// 被空闲对象回收器回收前在池中保持空闲状态的最小时间毫秒数
this.pool.setMinEvictableIdleTimeMillis(90000);
// 被空闲对象回收器回收前在池中保持空闲状态的最小时间毫秒数
// public long softMinEvictableIdleTimeMillis = GenericObjectPool.DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
this.pool.setTimeBetweenEvictionRunsMillis(80000);
// 是否采用后进先出策略
// public boolean lifo = GenericObjectPool.DEFAULT_LIFO;
}
/**
* 获取一个sftp连接对象
* @return sftp连接对象
*/
public ChannelSftp borrowObject() {
try {
return pool.borrowObject();
} catch (Exception e) {
log.info("获取sftp连接池连接失败:"+e.getMessage());
return null;
}
}
/**
* 归还一个sftp连接对象
* @param channelSftp sftp连接对象
*/
public void returnObject(ChannelSftp channelSftp) {
if (channelSftp!=null) {
pool.returnObject(channelSftp);
}
}
}
4.4 SftpHelper.calss
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.SftpException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import javax.annotation.Resource;
import java.io.*;
import java.util.ArrayList;
import java.util.Vector;
// sftp辅助类
@Slf4j
public class SftpHelper {
@Resource
private SftpProperties sftpProperties;
private SftpPool pool;
@Autowired
private Environment environment;
public SftpHelper(SftpPool pool) {
this.pool = pool;
}
public ArrayList<String> downSftpFile(){
log.info("获取SFTP连接信息");
ChannelSftp sftp = pool.borrowObject();
log.info("登录成功,从连接池获取SFTP连接信息"+sftp);
ArrayList<String> fileList = new ArrayList<String>();
if(sftp == null){
String msg = "从连接池获取SFTP连接信息为null";
}else{
try {
sftp.cd(sftpProperties.getRemotePaths());
log.info("SFTP登录进入目录:"+sftpProperties.getRemotePaths());
Vector<ChannelSftp.LsEntry> list = sftp.ls("*.txt");
if(list.size() >0){
for (ChannelSftp.LsEntry entry : list) {
String filename = entry.getFilename();
log.info("遍历SFTP文件————————————————"+filename);
String routeFileName = sftpProperties.getRemotePaths()+filename;
//下载
File localFile = new File(sftpProperties.getLocalPath()+filename);
OutputStream outputStream = new FileOutputStream(localFile);
sftp.get(routeFileName, outputStream);
outputStream.close();
//备份下载
File localbackupFile = new File(sftpProperties.getFileBackupPaths()+filename);
OutputStream osputStream = new FileOutputStream(localbackupFile);
sftp.get(routeFileName, osputStream);
osputStream.close();
log.info("下载文件:"+filename);
fileList.add(sftpProperties.getLocalPath()+filename);
//删除文件
sftp.rm(filename);
}
}else{
log.info("本次遍历文件为空");
}
} catch (Exception e) {
log.info("SFTP文件下载失败:"+e.getMessage());
e.printStackTrace();
} finally {
pool.returnObject(sftp);
}
}
return fileList;
}