FTP 送信チャネルアダプター

FTP 発信チャネルアダプターは、FTP サーバーに接続し、受信メッセージのペイロードで受信するすべてのファイルに対して FTP 転送を開始する MessageHandler 実装に依存しています。また、ファイルのいくつかの表現もサポートしているため、java.io.File -typed ペイロードのみに制限されません。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"/>

上記の構成は、filename-generator (o.s.i.file.FileNameGenerator 戦略インターフェースの実装)、session-factory への参照、その他の属性などのさまざまな属性の値を提供しながら、outbound-channel-adapter エレメントを使用して FTP 送信・チャネルアダプターを構成する方法を示しています。また、SpEL を使用して remote-directory-expressiontemporary-remote-directory-expressionremote-filename-generator-expression (前の例に示した filename-generator の代替 SpEL)などの設定を構成できる *expression 属性の例もいくつか見ることができます。SpEL の使用を許可する他のコンポーネントと同様に、ペイロードとメッセージヘッダーへのアクセスは、「ペイロード」変数と「ヘッダー」変数を介して利用できます。使用可能な属性の詳細については、スキーマ [GitHub] (英語) を参照してください。

デフォルトでは、ファイル名ジェネレーターが指定されていない場合、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 (default)

  • REPLACE_IF_MODIFIED

  • APPEND

  • APPEND_NO_FLUSH

  • IGNORE

  • FAIL

IGNORE および FAIL はファイルを転送しません。FAIL は例外をスローしますが、IGNORE はサイレントに転送を無視します(ただし、DEBUG ログエントリが生成されます)。

バージョン 5.2 は chmod 属性を導入しました。これを使用して、アップロード後にリモートファイルの許可を変更できます。従来の Unix 8 進形式を使用できます(たとえば、600 では、ファイル所有者に対してのみ読み取り / 書き込みが許可されます)。java を使用してアダプターを構成する場合、setChmodOctal("600") または setChmod(0600) を使用できます。FTP サーバーが SITE CHMOD サブコマンドをサポートしている場合にのみ適用されます。

部分的に書き込まれたファイルの回避

ファイル転送を処理するときに発生する一般的な問題の 1 つは、部分的なファイルを処理する可能性です。つまり、転送が実際に完了する前にファイルがファイルシステムに表示される場合があります。

この課題に対処するために、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);

    }

}