Sftp使用
# Sftp使用
# 1.引入坐标
<dependency>
<groupId>cn.lovecyy</groupId>
<artifactId>relaxed-spring-boot-starter-sftp</artifactId>
<version>${version}</version>
</dependency>
# 2.application.yml
relaxed:
sftp:
host: 127.0.0.1
port: 2222
username: root
password: 123456
sessionConnectTimeout: 15000
channelConnectedTimeout: 15000
###以下为对象池配置
pool:
max-total: 20
max-idle: 10
min-idle: 5
lifo: true
fairness: false
max-wait-millis: 5000
min-evictable-idle-time-millis: -1
evictor-shutdown-timeout-millis: 10000
soft-min-evictable-idle-time-millis: 1800000
num-tests-per-eviction-run: 3
test-on-create: false
test-on-borrow: true
test-on-return: false
test-while-idle: true
time-between-eviction-runs-millis: 600000
block-when-exhausted: true
jmx-enabled: false
jmx-name-prefix: pool
jmx-name-base: sftp
abandoned:
remove-abandoned-on-borrow: true
remove-abandoned-on-maintenance: true
remove-abandoned-timeout: 300
log-abandoned: false
require-full-stack-trace: false
use-usage-tracking: false
# 3.测试操作
@Autowired
private ISftpClient iSftpClient;
//不带返回值
iSftpClient.open(sftp -> {
//此处可以进行sftp 方式调用
List<String> list = sftp.list(path);
log.info("查询到文件列表{}", list);
});
//带返回值
List<String> list = iSftpClient.supplyOpen(sftp -> sftp.list(path));
# 附:自定义sftp client方法
# 1.自定义客户端函数
定义CustomSftp.java 继成 自SftpExecutor.java
public SftpExtensionExecutor(ChannelSftp channelSftp) {
super(channelSftp);
}
@Override
public File download(String absoluteFilePath, File file) {
downloadPathCheck(file);
return super.download(absoluteFilePath, file);
}
@Override
public File download(String dir, String name, File file) {
downloadPathCheck(file);
return super.download(dir, name, file);
}
/**
* 下载文件目标路径检查不存在 父级文件夹则创建
* @author yakir
* @date 2022/5/25 10:30
* @param file
*/
public static void downloadPathCheck(File file) {
File dirFile = file.getParentFile();
mkdir(dirFile);
}
private static File mkdir(File dir) {
if (dir == null) {
return null;
}
if (false == dir.exists()) {
mkdirsSafely(dir, 5, 1);
}
return dir;
}
/**
* 安全地级联创建目录 (确保并发环境下能创建成功)
*
* <pre>
* 并发环境下,假设 test 目录不存在,如果线程A mkdirs "test/A" 目录,线程B mkdirs "test/B"目录,
* 其中一个线程可能会失败,进而导致以下代码抛出 FileNotFoundException 异常
*
* file.getParentFile().mkdirs(); // 父目录正在被另一个线程创建中,返回 false
* file.createNewFile(); // 抛出 IO 异常,因为该线程无法感知到父目录已被创建
* </pre>
* @param dir 待创建的目录
* @param tryCount 最大尝试次数
* @param sleepMillis 线程等待的毫秒数
* @return true表示创建成功,false表示创建失败
* @author z8g
* @since 5.7.21
*/
private static boolean mkdirsSafely(File dir, int tryCount, long sleepMillis) {
if (dir == null) {
return false;
}
if (dir.isDirectory()) {
return true;
}
for (int i = 1; i <= tryCount; i++) { // 高并发场景下,可以看到 i 处于 1 ~ 3 之间
// 如果文件已存在,也会返回 false,所以该值不能作为是否能创建的依据,因此不对其进行处理
// noinspection ResultOfMethodCallIgnored
dir.mkdirs();
if (dir.exists()) {
return true;
}
sleep(sleepMillis);
}
return dir.exists();
}
/**
* 挂起当前线程
* @param millis 挂起的毫秒数
* @return 被中断返回false,否则true
* @since 5.3.2
*/
public static boolean sleep(long millis) {
if (millis > 0) {
try {
Thread.sleep(millis);
}
catch (InterruptedException e) {
return false;
}
}
return true;
}
# 2.注册到容器
/**
* sftp provider 主要负责提供产出{@See AbstractSql}子实列的动作
* @return
*/
@Bean
@ConditionalOnMissingBean
public ISftpProvider iSftpProvider() {
return channelSftp -> new SftpExecutor(channelSftp);
}