spring integration sftp
spring integration sftp 操作 sftp
spring integration
spring integration 是 spring 家族中的一个企业系统整合框架。
其集成了 spring 中的轻量级消息传递,并支持通过声明性适配器与外部系统集成。其主要目标是为企业集成提供一个简单的模型,同时保持关注点的分离。
其特性包括:
- 多企业集成模式的实现
- 端点
- 通道(点对点和发布/订阅)
- 聚合器
- 过滤器
- 转换器
- 控制总线
- …
- 与外部系统集成
- ReST/HTTP
- FTP/SFTP
- STOMP
- WebServices(SOAP and Rest)
- TCP/UDP
- JMS
- RabbitMQ
- …
- 此框架具有广泛的 JMX 支持
- 将框架组件公开为 MBean
- 用于从 MBean 获取属性、调用操作、发送/接收的适配器
spring integration sftp
spring integration sftp 是 spring integration 框架中支持 sftp 的模块。
spring integration 提供了三种方式来支持对 sftp 的操作,分别是:
- Inbound Channel Adapter: 入站通道适配器
- Outbound Channel Adapter: 出站通道适配器
- Outbound Gateway: 出站网关
其底层依赖于 com.jcraft.jsch,即 linux 链接并执行命令的工具包。
核心组件
- SftpSessionFactory:
sftp 客户端与服务端的会话工厂。客户端每次访问服务器时都会创建一个 session 对象,且可以通过 SftpSessionCaching 将 session 对象缓存起来,支持 session 共享,即可以在一个会话上进行多个 channel 的操作。如果 session 被重置,则在最后一次 channel 关闭之后,将断开连接。isSharedSession 为 true 时 session 将共享。 - SftpSessionCaching:
sftp 会话缓存工厂。通过 poolSize 和 sessionWaiteTimeout 来设置缓存池大小和会话等待超时时间。缓存池默认是无限大,超时时间默认是 Integer.MAX_VALUE。 - SftpRemoteFileTemplate:
基于 SftpSessionFactory 创建的 sftp 文件操作模板类。其父类是 RemoteFileTemplate。支持上传、下载、追加、删除、重命名、列表、是否存在。基于输入输出流实现。 - SftpInboundChannelAdapter:
sftp 入站通道适配器。可同步远程目录到本地,且可监听远程文件的操作,可实现下载。 - SftpOutboundChannelAdapter:
sftp 出站通道适配器。实际是一个 sftp 消息处理器,将在服务器与客户端之间创建一个消息传输通道。此处的消息指的是 Message 的 payload,其支持 File、byte[]、String。其支持 ls、nlst、get、rm、mget、mv、put、mput 操作。 - Channel Adapter:
通道适配器,实际上是适配消息在客户端和服务器之间的传输。inbound adapter 是接收其它系统的消息,outbound adapter 是发送消息到其它系统。 - @ServiceActivator:
将注解作用的方法注册为处理消息的站点,inputChannel 表示接收消息的通道。
操作 sftp 命令及参数
命令:
ls: 获取文件列表
nlst: 获取列表内的文件名
get: 下载单个文件
rm: 删除文件
mget: 批量下载
mv: 移动/重命名文件
put: 上传单个文件
mput: 批量上传
可配参数:
-1: 在 ls 的结果中只返回文件名,不返回文件信息
-a: 在 ls 中返回所有文件(隐藏文件也会返回)
-f: 对 ls 的结果不排序(fileName)
-dirs: 在 ls 的结果中返回目录信息
-links: 在 ls 的结果中返回文件详细信息(权限、形态、大小等)
-P: get、mget(下载)时将远程文件时间信息同步到本地
-x: get、mget(下载)时如果没有文件返回将抛出一个异常
-R: ls、mget 时递归文件夹
-stream: get 时返回文件流 且必须调用 Session.close()
-D: get、mget 成功后删除远程文件
springboot + spring integration sftp demo
version:
springboot: 2.5.6
spring integration: 5.5.5
spring inetgration sftp: 5.5.5
pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-integration</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-sftp</artifactId>
</dependency>
SftpConfig:
sftp 配置工厂及消息处理器。
@Configuration
@EnableIntegration // 开启整合
public class SftpConfig {
private static final Logger logger = LogManager.getLogger(SftpConfig.class);
/**
* SftpSessionFactory
* sftp 客户端与服务端的会话工厂
*
* SftpSessionCaching
* sftp 会话缓存工厂
*
* @return
*/
@Bean
public SessionFactory<ChannelSftp.LsEntry> sftpSessionFactory() {
DefaultSftpSessionFactory factory = new DefaultSftpSessionFactory(true);
factory.setHost("ip");
factory.setPort(22);
factory.setUser("momo");
factory.setPassword("momo");
factory.setAllowUnknownKeys(true); // 允许无条件连接
CachingSessionFactory<ChannelSftp.LsEntry> cachingSessionFactory = new CachingSessionFactory<>(factory);
cachingSessionFactory.setPoolSize(10);
cachingSessionFactory.setSessionWaitTimeout(10 * 1000);
return cachingSessionFactory;
}
/**
* SftpRemoteFileTemplate
* 于 SftpSessionFactory 创建的 sftp 文件操作模板类
* 用来创建 SftpOutboundGateway(见 SftpOutboundGateway 构造方法源码)
*
* @return
*/
@Bean
public SftpRemoteFileTemplate sftpRemoteFileTemplate() {
return new SftpRemoteFileTemplate(sftpSessionFactory());
}
/**
* 发送执行 ls 命令
* payload 为远程目录
* @return
*/
@Bean
@ServiceActivator(inputChannel = "lsChannel")
public MessageHandler lsHandler() {
SftpOutboundGateway gateway = new SftpOutboundGateway(sftpSessionFactory(), "ls", "payload");
gateway.setOptions("-dirs"); // 显示目录记录
return gateway;
}
/**
* 发送执行 nlst 命令
* payload 为远程目录
* @return
*/
@Bean
@ServiceActivator(inputChannel = "nlstChannel")
public MessageHandler nlstHandler() {
SftpOutboundGateway gateway = new SftpOutboundGateway(sftpSessionFactory(), "nlst", "payload");
gateway.setOptions("-f");
return gateway;
}
/**
* 发送执行 get 命令
* payload 为远程文件
* @return
*/
@Bean
@ServiceActivator(inputChannel = "getChannel")
public MessageHandler getHandler() {
SftpOutboundGateway gateway = new SftpOutboundGateway(sftpSessionFactory(), "get", "payload");
gateway.setOptions("-P");
gateway.setLocalDirectory(new File("D:\\xgllhz\\tmp\\sftp"));
return gateway;
}
/**
* 发送执行 rm 命令
* payload 为远程文件
* @return
*/
@Bean
@ServiceActivator(inputChannel = "rmChannel")
public MessageHandler rmHandler() {
return new SftpOutboundGateway(sftpSessionFactory(), "rm", "payload");
}
/**
* 发送执行 mget 命令
* payload 为远程目录
* @return
*/
@Bean
@ServiceActivator(inputChannel = "mgetChannel")
public MessageHandler mgetHandler() {
SftpOutboundGateway gateway = new SftpOutboundGateway(sftpSessionFactory(), "mget", "payload");
gateway.setOptions("-R");
gateway.setFileExistsMode(FileExistsMode.REPLACE_IF_MODIFIED); // 若被修改则替换
gateway.setLocalDirectory(new File("D:\\xgllhz\\tmp\\sftp"));
gateway.setAutoCreateLocalDirectory(true); // 自动创建本地目录
return gateway;
}
/**
* 发送执行 mv 命令
* payload 为远程文件
* @return
*/
@Bean
@ServiceActivator(inputChannel = "mvChannel")
public MessageHandler mvHandler() {
SftpOutboundGateway gateway = new SftpOutboundGateway(sftpSessionFactory(), "mv", "payload");
gateway.setRenameExpression(new LiteralExpression("sftp/tests/test.txt"));
return gateway;
}
/**
* 发送执行 put 命令
* payload 为 File
* @return
*/
@Bean
@ServiceActivator(inputChannel = "putChannel")
public MessageHandler putHandler() {
SftpOutboundGateway gateway = new SftpOutboundGateway(sftpSessionFactory(), "put", "payload");
gateway.setRemoteDirectoryExpression(new LiteralExpression("sftp/test/"));
return gateway;
}
/**
* 发送执行 mput 命令
* payload 为 List< File>
* @return
*/
@Bean
@ServiceActivator(inputChannel = "mputChannel")
public MessageHandler mputHandler() {
SftpOutboundGateway gateway = new SftpOutboundGateway(sftpSessionFactory(), "mput", "payload");
gateway.setOptions("-R");
gateway.setRemoteDirectoryExpression(new LiteralExpression("sftp/test/")); // 设置远程目录
gateway.setAutoCreateDirectory(true); // 自动创建远程目录
return gateway;
}
}
SftpGateway:
@MessagingGateway 用于消息网关代理整合,requestChannel 表示发送消息的通道。
@MessagingGateway
public interface SftpGateway {
/**
* 获取远程指定目录下文件列表
* @param directory 远程目录
* @return List<SftpFileInfo>
*/
@Gateway(requestChannel = "lsChannel")
List<SftpFileInfo> listFile(String directory);
/**
* 获取远程指定目录下所有文件名
* @param directory 远程目录
* @return List<String>
*/
@Gateway(requestChannel = "nlstChannel")
List<String> nlstFile(String directory);
/**
* 下载指定文件
* @param directory 远程文件名(包含目录)
* @return File
*/
@Gateway(requestChannel = "getChannel")
File getFile(String directory);
/**
* 删除远程指定文件
* @param directory 远程文件名(包含目录)
* @return boolean
*/
@Gateway(requestChannel = "rmChannel")
Boolean rmFile(String directory);
/**
* 批量下载远程指定目录下所有文件
* @param directory 远程目录
* @return List<File>
*/
@Gateway(requestChannel = "mgetChannel")
List<File> mgetFile(String directory);
/**
* 移动远程指定文件
* @param directory 远程文件名(包含目录)
* @return boolean
*/
@Gateway(requestChannel = "mvChannel")
Boolean mvFile(String directory);
/**
* 上传本地文件
* @param file File
* @return String 远程文件名(包含目录)
*/
@Gateway(requestChannel = "putChannel")
String putFile(File file);
/**
* 批量上传本地文件
* @param list List<File>
* @return List<String> 远程文件名(包含目录)
*/
@Gateway(requestChannel = "mputChannel")
List<String> mputFile(List<File> list);
}
TestController:
@RestController
@RequestMapping("/api/common")
public class TestController {
private static final Logger logger = LogManager.getLogger(TestController.class);
@Resource
private SftpGateway sftpGateway;
@RequestMapping("/sftp")
@ResponseBody
public APIResponse<Map<String, Object>> sftp() {
logger.info("enter TestController.sftp()");
// ls
List<SftpFileInfo> list1 = sftpGateway.listFile("/sftp/test/");
list1.stream().peek(fileInfo -> System.out.println(fileInfo.getFilename()));
// nlst
List<String> list2 = sftpGateway.nlstFile("/sftp/test/");
System.out.println(list2.toString());
// get
File file = sftpGateway.getFile("/sftp/test/test.txt");
System.out.println(file.getName());
// rm
boolean res1 = sftpGateway.rmFile("/sftp/test/test.txt");
System.out.println(res1);
// mget
List<File> list3 = sftpGateway.mgetFile("/sftp/test/");
list3.stream().peek(file -> System.out.println(file.getName()));
// mv
boolean res2 = sftpGateway.mvFile("/sftp/test/test.txt");
System.out.println(res2);
// put
File file2 = new File("D:\\xgllhz\\tmp\\sftp\\test.txt");
String fileName = sftpGateway.putFile(file);
System.out.println(fileName);
// mput
List<File> list4 = new ArrayList<>();
list4.add(new File("D:\\xgllhz\\tmp\\sftp\\test1.txt"));
list4.add(new File("D:\\xgllhz\\tmp\\sftp\\test2.txt"));
list4.add(new File("D:\\xgllhz\\tmp\\sftp\\test3.txt"));
List<String> lists = sftpGateway.mputFile(list4);
lists.forEach(System.out::println);
return new APIResponse<>();
}
}
@XGLLHZ-一路生花.mp3