FTP 出站通道介面卡

FTP 出站通道介面卡依賴於一個 `MessageHandler` 實現,該實現連線到 FTP 伺服器,併為接收到的每條訊息的載荷中的檔案啟動 FTP 傳輸。它還支援檔案的多種表示形式,因此您不僅限於 `java.io.File` 型別的載荷。FTP 出站通道介面卡支援以下載荷型別:

  • `java.io.File`: 實際的檔案物件

  • `byte[]`: 表示檔案內容的位元組陣列

  • `java.lang.String`: 表示檔案內容的文字

  • `java.io.InputStream`: 傳輸到遠端檔案的資料流

  • `org.springframework.core.io.Resource`: 用於傳輸到遠端檔案的資料資源

以下示例展示瞭如何配置 `outbound-channel-adapter`:

<int-ftp:outbound-channel-adapter id="ftpOutbound"
    channel="ftpChannel"
    session-factory="ftpSessionFactory"
    charset="UTF-8"
    remote-file-separator="/"
    auto-create-directory="true"
    remote-directory-expression="headers['remote_dir']"
    temporary-remote-directory-expression="headers['temp_remote_dir']"
    filename-generator="fileNameGenerator"
    use-temporary-filename="true"
    chmod="600"
    mode="REPLACE"/>

前面的配置展示瞭如何使用 `outbound-channel-adapter` 元素來配置 FTP 出站通道介面卡,同時為各種屬性提供值,例如 `filename-generator` (實現了 `o.s.i.file.FileNameGenerator` 策略介面)、對 `session-factory` 的引用以及其他屬性。您還可以看到一些 `*expression` 屬性的示例,這些屬性允許您使用 SpEL 配置設定,例如 `remote-directory-expression`、`temporary-remote-directory-expression` 和 `remote-filename-generator-expression` (SpEL 替代方案,對應前面的 `filename-generator`)。與任何允許使用 SpEL 的元件一樣,可以透過 'payload' 和 'headers' 變數訪問載荷和訊息頭。有關可用屬性的更多詳細資訊,請參閱模式

預設情況下,如果沒有指定檔案命名生成器,Spring Integration 使用 `o.s.i.file.DefaultFileNameGenerator`。`DefaultFileNameGenerator` 根據 `MessageHeaders` 中 `file_name` 頭的值(如果存在)確定檔名,或者,如果訊息的載荷已經是 `java.io.File`,則使用該檔案的原始名稱。
定義某些值(例如 `remote-directory`)可能依賴於平臺或 FTP 伺服器。例如,正如 forum.spring.io/showthread.php?p=333478&posted=1#post333478 上報告的那樣,在某些平臺上,您必須在目錄定義末尾新增斜槓(例如,`remote-directory="/thing1/thing2/"` 而不是 `remote-directory="/thing1/thing2"`)。

從版本 4.1 開始,您可以在傳輸檔案時指定 `mode`。預設情況下,現有檔案將被覆蓋。模式由 `FileExistsMode` 列舉定義,包括以下值:

  • `REPLACE` (預設) -> 替換 (預設)

  • REPLACE_IF_MODIFIED -> 如果修改則替換

  • APPEND -> 追加

  • APPEND_NO_FLUSH -> 追加不重新整理

  • IGNORE -> 忽略

  • FAIL -> 失敗

`IGNORE` 和 `FAIL` 不傳輸檔案。`FAIL` 會丟擲異常,而 `IGNORE` 會靜默忽略傳輸(儘管會生成 `DEBUG` 日誌條目)。

版本 5.2 引入了 `chmod` 屬性,您可以使用它在上傳後更改遠端檔案許可權。您可以使用傳統的 Unix 八進位制格式(例如,`600` 僅允許檔案所有者讀寫)。在使用 Java 配置介面卡時,您可以使用 `setChmodOctal("600")` 或 `setChmod(0600)`。僅在您的 FTP 伺服器支援 `SITE CHMOD` 子命令時適用。

避免寫入部分檔案

處理檔案傳輸時出現的一個常見問題是處理部分檔案的可能性。也就是說,檔案可能在傳輸實際完成之前就出現在檔案系統中。

為了解決這個問題,Spring Integration FTP 介面卡使用了一個通用演算法:檔案以臨時名稱傳輸,然後在完全傳輸後重命名。

預設情況下,每個正在傳輸的檔案都會在檔案系統中顯示一個額外的字尾,預設情況下,該字尾為 `.writing`。您可以透過設定 `temporary-file-suffix` 屬性來更改此後綴。

然而,在某些情況下,您可能不想使用這種技術(例如,如果伺服器不允許重新命名檔案)。對於這種情況,您可以透過將 `use-temporary-file-name` 設定為 `false` 來停用此功能(預設值為 `true`)。當此屬性為 `false` 時,檔案將以最終名稱寫入,並且消費應用程式需要其他機制來檢測檔案在訪問之前已完全上傳。

使用 Java 配置進行配置

以下 Spring Boot 應用程式展示瞭如何使用 Java 配置配置出站介面卡:

@SpringBootApplication
@IntegrationComponentScan
public class FtpJavaApplication {

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

    @Bean
    public SessionFactory<FTPFile> ftpSessionFactory() {
        DefaultFtpSessionFactory sf = new DefaultFtpSessionFactory();
        sf.setHost("localhost");
        sf.setPort(port);
        sf.setUsername("foo");
        sf.setPassword("foo");
        sf.setTestSession(true);
        return new CachingSessionFactory<FTPFile>(sf);
    }

    @Bean
    @ServiceActivator(inputChannel = "ftpChannel")
    public MessageHandler handler() {
        FtpMessageHandler handler = new FtpMessageHandler(ftpSessionFactory());
        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 = "toFtpChannel")
         void sendToFtp(File file);

    }
}

使用 Java DSL 進行配置

以下 Spring Boot 應用程式展示瞭如何使用 Java DSL 配置出站介面卡:

@SpringBootApplication
@IntegrationComponentScan
public class FtpJavaApplication {

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

    @Bean
    public SessionFactory<FTPFile> ftpSessionFactory() {
        DefaultFtpSessionFactory sf = new DefaultFtpSessionFactory();
        sf.setHost("localhost");
        sf.setPort(port);
        sf.setUsername("foo");
        sf.setPassword("foo");
        sf.setTestSession(true);
        return new CachingSessionFactory<FTPFile>(sf);
    }

    @Bean
    public IntegrationFlow ftpOutboundFlow() {
        return IntegrationFlow.from("toFtpChannel")
                .handle(Ftp.outboundAdapter(ftpSessionFactory(), FileExistsMode.FAIL)
                        .useTemporaryFileName(false)
                        .fileNameExpression("headers['" + FileHeaders.FILENAME + "']")
                        .remoteDirectory(this.ftpServer.getTargetFtpDirectory().getName())
                ).get();
    }

    @MessagingGateway
    public interface MyGateway {

         @Gateway(requestChannel = "toFtpChannel")
         void sendToFtp(File file);

    }

}