使用 SFTP 出站通道适配器通过 SFTP 将数据流式传输到远程文件服务器

问题描述 投票:0回答:1

在我的 Spring Boot 应用程序中,我必须从数据库读取大量数据,将其转换为 CSV 文件并将其上传到 SFTP 服务器。由于文件可能很大,我无法读取内存中的整个文件然后上传。它将被传输并附加到 SFTP 服务器上。

我使用 atmoz/sftp docker 容器作为我的 SFTP 服务器,它工作正常。

对于 Spring boot 客户端 - Spring 集成 - SFTP 出站通道适配器 对我来说似乎很有希望。使用以下代码,我可以将文件上传到 SFTP 服务器:

@SpringBootApplication
public class SftpIngApplication {

    public static void main(String[] args) throws FileNotFoundException {
        ConfigurableApplicationContext context =
                new SpringApplicationBuilder(SftpIngApplication.class)
                        .web(WebApplicationType.SERVLET)
                        .run(args);
        MyGateway gateway = context.getBean(MyGateway.class);
        gateway.sendToSftp(new File("/home/john/sftp-ing/notes.txt"));
    }

    @Bean
    public SessionFactory<SftpClient.DirEntry> sftpSessionFactory() {
        DefaultSftpSessionFactory factory = new DefaultSftpSessionFactory(true);
        factory.setHost("localhost");
        factory.setPort(2222);
        factory.setUser("foo");
        factory.setPassword("pass");
        factory.setAllowUnknownKeys(true);
        return new CachingSessionFactory<>(factory);
    }

    @MessagingGateway
    public interface MyGateway {

        @Gateway(requestChannel = "toSftpChannel")
        void sendToSftp(File file);

    }

    @Bean
    public SftpRemoteFileTemplate sftpRemoteFileTemplate(SessionFactory<SftpClient.DirEntry> sftpSessionFactory) {
        return new SftpRemoteFileTemplate(sftpSessionFactory);
    }

    @Bean
    public IntegrationFlow sftpOutboundFlow(SessionFactory<SftpClient.DirEntry> sftpSessionFactory) {
        return IntegrationFlow.from("toSftpChannel")
                .handle(Sftp.outboundAdapter(sftpSessionFactory, FileExistsMode.REPLACE)

                        .useTemporaryFileName(false)
                        .remoteDirectory("upload")
                ).get();
    }

}

但是此示例使用

new File("/home/john/sftp-ing/notes.txt")
来上传文件。只需将其替换为 FileInputStream 也会上传文件,但不会使用相同的名称和扩展名,即 bar.txt。文件上传为
67157c1b-439d-9f3b-f2be-88eff908e39c.msg
.

在我看来,流是开放的,有些可能需要关闭,但是我不确定最好的方法是什么。有人可以帮我解决这个问题吗?

spring spring-boot spring-integration spring-integration-sftp
1个回答
0
投票

在您的用例中使用

InputStream
作为传输到 SFTP 的有效负载确实是正确的。您还缺少一个要提供的文件名。

FileNameGenerator
中的默认
RemoteFileTemplate
是一个
DefaultFileNameGenerator
,逻辑如下:

public String generateFileName(Message<?> message) {
    Object filename = evaluateExpression(this.expression, message);
    if (filename instanceof String name && StringUtils.hasText(name)) {
        return name;
    }
    Object payload = message.getPayload();
    if (payload instanceof File file) {
        return file.getName();
    }
    return message.getHeaders().getId() + ".msg";
}

提到的表达是这样的:

private volatile Expression expression =
        new FunctionExpression<Message<?>>((message) -> message.getHeaders().get(FileHeaders.FILENAME));

由于您不提供该信息

FileHeaders.FILENAME
,您最终会得到基于消息 ID 生成的名称。

在将

FileHeaders.FILENAME
发送到您的
InputStream
之前,请考虑使用预期的文件名填充
sftpOutboundFlow
标头!

© www.soinside.com 2019 - 2024. All rights reserved.