SFTP 出站通道适配器

SFTP出站通道适配器是一个特殊的 MessageHandler,它连接到远程目录并为收到的每个作为传入 Message 的 payload 的文件启动文件传输。它还支持文件的多种表示形式,因此您不限于 File 对象。与FTP出站适配器类似,SFTP出站通道适配器支持以下payload:

  • java.io.File:实际的文件对象

  • byte[]:表示文件内容的字节数组

  • java.lang.String:表示文件内容的文本

  • java.io.InputStream:要传输到远程文件的数据流

  • org.springframework.core.io.Resource:要传输到远程文件的数据资源

以下示例展示了如何配置SFTP出站通道适配器:

<int-sftp:outbound-channel-adapter id="sftpOutboundAdapter"
    session-factory="sftpSessionFactory"
    channel="inputChannel"
    charset="UTF-8"
    remote-file-separator="/"
    remote-directory="foo/bar"
    remote-filename-generator-expression="payload.getName() + '-mysuffix'"
    filename-generator="fileNameGenerator"
    use-temporary-filename="true"
    chmod="600"
    mode="REPLACE"/>

有关这些属性的更多详细信息,请参阅schema

SpEL和SFTP出站适配器

与Spring Integration中的许多其他组件一样,您可以通过指定两个属性:remote-directory-expressionremote-filename-generator-expression前面描述过)来配置SFTP出站通道适配器时使用Spring表达式语言(SpEL)。表达式评估上下文将消息作为其根对象,这使您可以使用可以根据消息中的数据(来自“payload”或“headers”)动态计算文件名或现有目录路径的表达式。在前面的示例中,我们定义了 remote-filename-generator-expression 属性,其表达式值根据原始名称计算文件名,同时附加后缀:'-mysuffix'。

从版本4.1开始,您可以在传输文件时指定 mode。默认情况下,现有文件会被覆盖。这些模式由 FileExistsMode 枚举定义,其中包括以下值:

  • REPLACE(默认)

  • REPLACE_IF_MODIFIED

  • APPEND

  • APPEND_NO_FLUSH

  • IGNORE

  • FAIL

使用 IGNOREFAIL 时,文件不会被传输。FAIL 会导致抛出异常,而 IGNORE 会静默忽略传输(尽管会生成 DEBUG 日志条目)。

版本4.3引入了 chmod 属性,您可以使用它在上传后更改远程文件权限。您可以使用传统的Unix八进制格式(例如,600只允许文件所有者读写)。使用Java配置适配器时,您可以使用 setChmodOctal("600")setChmod(0600)

避免部分写入的文件

处理文件传输时常见的​​问题之一是处理部分文件的可能性。文件可能在文件系统​​中出现,但其传输实际上尚未完成。

为了解决这个问题,Spring Integration SFTP适配器使用一种通用算法,即文件在临时名称下传输,并在完全传输后重命名。

默认情况下,每个正在传输的文件都会在文件系统​​中显示一个附加后缀,默认情况下为 .writing。您可以通过设置 temporary-file-suffix 属性来更改它。

但是,在某些情况下,您可能不希望使用此技术(例如,如果服务器不允许重命名文件)。对于这种情况,您可以通过将 use-temporary-file-name 设置为 false 来禁用此功能(默认值为 true)。当此属性为 false 时,文件会以其最终名称写入,并且消费应用程序需要其他机制来检测文件完全上传后才能访问它。

使用 Java 配置

以下Spring Boot应用程序展示了如何使用Java配置出站适配器的示例:

@SpringBootApplication
@IntegrationComponentScan
public class SftpJavaApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext context =
                    new SpringApplicationBuilder(SftpJavaApplication.class)
                        .web(false)
                        .run(args);
        MyGateway gateway = context.getBean(MyGateway.class);
        gateway.sendToSftp(new File("/foo/bar.txt"));
    }

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

    @Bean
    @ServiceActivator(inputChannel = "toSftpChannel")
    public MessageHandler handler() {
        SftpMessageHandler handler = new SftpMessageHandler(sftpSessionFactory());
        handler.setRemoteDirectoryExpressionString("headers['remote-target-dir']");
        handler.setFileNameGenerator(new FileNameGenerator() {

            @Override
            public String generateFileName(Message<?> message) {
                 return "handlerContent.test";
            }

        });
        return handler;
    }

    @MessagingGateway
    public interface MyGateway {

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

    }
}

使用 Java DSL 进行配置

以下 Spring Boot 应用程序演示了如何使用 Java DSL 配置出站适配器

@SpringBootApplication
public class SftpJavaApplication {

    public static void main(String[] args) {
        new SpringApplicationBuilder(SftpJavaApplication.class)
            .web(false)
            .run(args);
    }

    @Bean
    public IntegrationFlow sftpOutboundFlow() {
        return IntegrationFlow.from("toSftpChannel")
            .handle(Sftp.outboundAdapter(this.sftpSessionFactory, FileExistsMode.FAIL)
                         .useTemporaryFileName(false)
                         .remoteDirectory("/foo")
            ).get();
    }

}
© . This site is unofficial and not affiliated with VMware.