此版本仍在开发中,尚未被视为稳定版本。对于最新的稳定版本,请使用 Spring Integration 6.3.4spring-doc.cn

此版本仍在开发中,尚未被视为稳定版本。对于最新的稳定版本,请使用 Spring Integration 6.3.4spring-doc.cn

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

  • java.io.File:实际文件对象spring-doc.cn

  • byte[]:表示文件内容的字节数组spring-doc.cn

  • java.lang.String:表示文件内容的文本spring-doc.cn

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

  • org.springframework.core.io.Resource:用于将数据传输到远程文件的资源spring-doc.cn

以下示例说明如何配置 SFTP 出站通道适配器:spring-doc.cn

<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.spring-doc.cn

SPEL 和 SFTP 出站适配器

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

从版本 4.1 开始,您可以指定何时传输文件。 默认情况下,现有文件将被覆盖。 模式由枚举定义,其中包括以下值:modeFileExistsModespring-doc.cn

使用 和 ,不会传输文件。 导致引发异常,同时静默忽略传输(尽管生成了日志条目)。IGNOREFAILFAILIGNOREDEBUGspring-doc.cn

版本 4.3 引入了该属性,您可以使用该属性在上传后更改远程文件权限。 您可以使用传统的 Unix 八进制格式(例如,仅允许文件所有者进行读写操作)。 使用 java 配置适配器时,可以使用 或 。chmod600setChmodOctal("600")setChmod(0600)spring-doc.cn

避免部分写入的文件

处理文件传输时的一个常见问题是处理部分文件的可能性。 文件可能在传输实际完成之前就出现在文件系统中。spring-doc.cn

为了解决这个问题, Spring 集成 SFTP 适配器使用一种通用算法,其中文件以临时名称传输,并在完全传输后重命名。spring-doc.cn

默认情况下,正在传输的每个文件都会显示在文件系统中,并带有一个附加后缀,默认情况下,该后缀为 . 您可以通过设置属性来更改。.writingtemporary-file-suffixspring-doc.cn

但是,在某些情况下,您可能不想使用此技术(例如,如果服务器不允许重命名文件)。 对于此类情况,您可以通过设置为 (默认为 ) 来禁用此功能。 当此属性为 时,文件将以其最终名称写入,并且使用应用程序需要一些其他机制来检测文件是否已完全上传,然后再访问它。use-temporary-file-namefalsetruefalsespring-doc.cn

使用 Java 配置进行配置

Spring 下面的 Boot 应用程序显示了如何使用 Java 配置出站适配器的示例:spring-doc.cn

@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 配置出站适配器的示例:spring-doc.cn

@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();
    }

}