FTP 送信ゲートウェイ

FTP 送信ゲートウェイは、リモート FTP または FTPS サーバーと対話するための限られたコマンドセットを提供します。サポートされているコマンドは次のとおりです。

  • ls (リストファイル)

  • nlst (リストファイル名)

  • get (ファイルを取得する)

  • mget (ファイルの取得)

  • rm (ファイルを削除)

  • mv (ファイルの移動 / 名前変更)

  • put (ファイルの送信)

  • mput (複数のファイルを送信する)

ls コマンドの使用

ls はリモートファイルをリストし、次のオプションをサポートします。

  • -1: ファイル名のリストを取得します。デフォルトでは、FileInfo オブジェクトのリストを取得します。

  • -a: すべてのファイルを含める ( "." で始まるものを含む)

  • -f: リストをソートしないでください

  • -dirs: インクルードディレクトリ (それらはデフォルトで除外されます)

  • -links: シンボリックリンクを含める (それらはデフォルトで除外されます)

  • -R: リモートディレクトリを再帰的にリストする

さらに、inbound-channel-adapter と同じ方法で、ファイル名のフィルタリングが提供されます。FTP 受信チャネルアダプターを参照してください。

ls 操作の結果のメッセージペイロードは、ファイル名のリストまたは FileInfo オブジェクトのリストです。これらのオブジェクトは、変更された時間、権限、その他の詳細などの情報を提供します。

ls コマンドが実行されたリモートディレクトリは、file_remoteDirectory ヘッダーで提供されます。

再帰オプション(-R)を使用する場合、fileName にはサブディレクトリ要素が含まれ、ファイルへの相対パス(リモートディレクトリに対する相対パス)を表します。-dirs オプションが含まれている場合、各再帰ディレクトリもリスト内の要素として返されます。この場合、-1 オプションを使用しないことをお勧めします。FileInfo オブジェクトで実行できるディレクトリとファイルを区別できないためです。

バージョン 4.3 以降、FtpSession は list() および listNames() メソッドの null をサポートします。expression 属性は省略できます。便宜上、Java 構成には、expression 引数を持たない 2 つのコンストラクターがあります。または LSNLSTPUTMPUT コマンドの場合、null は、FTP プロトコルに従ってクライアントの作業ディレクトリとして扱われます。リクエストメッセージに対してリモートパスを評価するには、他のすべてのコマンドを expression とともに提供する必要があります。DefaultFtpSessionFactory を継承し、postProcessClientAfterConnect() コールバックを実装するときに、FTPClient.changeWorkingDirectory() 関数を使用して作業ディレクトリを設定できます。

nlst コマンドの使用

バージョン 5 では、nlst コマンドのサポートが導入されました。

nlst はリモートファイル名をリストし、1 つのオプションのみをサポートします。

  • -f: リストをソートしないでください

nlst 操作から生じるメッセージペイロードは、ファイル名のリストです。

nlst コマンドが実行されたリモートディレクトリは、file_remoteDirectory ヘッダーで提供されます。

LIST コマンドを使用する ls コマンドの -1 オプションとは異なり、nlst コマンドは、ターゲット FTP サーバーに NLST コマンドを送信します。このコマンドは、サーバーが LIST をサポートしていない場合に役立ちます(たとえば、セキュリティ制限のため)。nlst 操作の結果は、他の詳細なしの名前です。フレームワークは、エンティティがディレクトリであるかどうかを判断できません。たとえば、フィルタリングや再帰的なリストを実行できます。

get コマンドの使用

get はリモートファイルを取得します。次のオプションをサポートしています。

  • -P: リモートファイルのタイムスタンプを保持します。

  • -stream: リモートファイルをストリームとして取得します。

  • -D: 転送に成功したら、リモートファイルを削除します。FileExistsMode は IGNORE であり、ローカルファイルがすでに存在するため、転送が無視される場合、リモートファイルは削除されません。

file_remoteDirectory ヘッダーはリモートディレクトリ名を提供し、file_remoteFile ヘッダーはファイル名を提供します。

get 操作の結果として生成されるメッセージペイロードは、取得されたファイルを表す File オブジェクト、または -stream オプションを使用する場合は InputStream です。-stream オプションを使用すると、ファイルをストリームとして取得できます。テキストファイルの場合、一般的な使用例は、この操作をファイルスプリッターまたはストリームトランスフォーマーと組み合わせることです。リモートファイルをストリームとして使用する場合、ストリームの使用後に Session を閉じる必要があります。便宜上、Session は closeableResource ヘッダーで提供されており、IntegrationMessageHeaderAccessor のコンビニエンスメソッドを使用してアクセスできます。次の例は、コンビニエンスメソッドの使用メソッドを示しています。

Closeable closeable = new IntegrationMessageHeaderAccessor(message).getCloseableResource();
if (closeable != null) {
    closeable.close();
}

ファイルスプリッターストリームトランスフォーマーなどのフレームワークコンポーネントは、データが転送された後、セッションを自動的に閉じます。

次の例は、ファイルをストリームとして使用する方法を示しています。

<int-ftp:outbound-gateway session-factory="ftpSessionFactory"
                            request-channel="inboundGetStream"
                            command="get"
                            command-options="-stream"
                            expression="payload"
                            remote-directory="ftpTarget"
                            reply-channel="stream" />

<int-file:splitter input-channel="stream" output-channel="lines" />
カスタムコンポーネントで入力ストリームを使用する場合は、Session を閉じる必要があります。次の例に示すように、カスタムコードで、またはメッセージのコピーを service-activator にルーティングして SpEL を使用することで、これを行うことができます。
<int:service-activator input-channel="closeSession"
    expression="headers['closeableResource'].close()" />

mget コマンドの使用

mget は、パターンに基づいて複数のリモートファイルを取得し、次のオプションをサポートします。

  • -P: リモートファイルのタイムスタンプを保持します。

  • -R: ディレクトリツリー全体を再帰的に取得します。

  • -x: パターンに一致するファイルがない場合は例外をスローします(そうでない場合は空のリストが返されます)。

  • -D: 転送が成功したら、各リモートファイルを削除します。FileExistsMode は IGNORE であり、ローカルファイルがすでに存在するため、転送が無視される場合、リモートファイルは削除されません。

mget 操作の結果のメッセージペイロードは、List<File> オブジェクト(つまり、File オブジェクトの List、それぞれが取得したファイルを表す)です。

バージョン 5.0 以降、FileExistsMode が IGNORE の場合、出力メッセージのペイロードには、ファイルがすでに存在するためにフェッチされなかったファイルが含まれなくなりました。以前は、リストには既存のファイルを含むすべてのファイルが含まれていました。

リモートパスを決定するために使用される式は、 で終わる結果を生成する必要があります。somedir/ は、somedir の完全なツリーをフェッチします。

バージョン 5.0 以降、再帰的な mget を新しい FileExistsMode.REPLACE_IF_MODIFIED モードと組み合わせて、リモートディレクトリツリー全体を定期的にローカルに同期することができます。このモードは、-P (タイムスタンプを保持)オプションに関係なく、ローカルファイルの最終変更タイムスタンプをリモートタイムスタンプに置き換えます。

再帰を使用する (-R)

パターンは無視され、* が想定されます。デフォルトでは、リモートツリー全体が取得されます。ただし、FileListFilter を提供することにより、ツリー内のファイルをフィルタリングできます。ツリー内のディレクトリもこの方法でフィルタリングできます。FileListFilter は、参照、filename-patternfilename-regex 属性によって提供できます。例: filename-regex="(subDir|.*1.txt)" は、リモートディレクトリおよび subDir 子ディレクトリにある 1.txt で終わるすべてのファイルを取得します。ただし、次の例は、5.0 バージョンが使用可能になった代替手段を示しています。

サブディレクトリがフィルタリングされると、そのサブディレクトリの追加の走査は実行されません。

-dirs オプションは許可されません(再帰 mget は再帰 ls を使用してディレクトリツリーを取得するため、ディレクトリ自体をリストに含めることはできません)。

通常、リモートディレクトリ構造がローカルに保持されるように、local-directory-expression で #remoteDirectory 変数を使用します。

永続ファイルリストフィルターにブールプロパティ forRecursion が追加されました。このプロパティを true に設定すると、alwaysAcceptDirectories も設定されます。これは、送信ゲートウェイ(ls および mget)での再帰操作が常にディレクトリツリー全体を毎回トラバースすることを意味します。これは、ディレクトリツリーの奥深くで変更が検出されなかった問題を解決するためです。さらに、forRecursion=true により、ファイルへのフルパスがメタデータストアキーとして使用されます。これにより、同じ名前のファイルが異なるディレクトリに複数回表示された場合にフィルターが正しく機能しなかった問題が解決されます。重要: これは、永続メタデータストア内の既存のキーが、最上位ディレクトリにあるファイルで見つからないことを意味します。このため、プロパティはデフォルトで false です。これは将来のリリースで変更される可能性があります。

バージョン 5.0 から、FtpSimplePatternFileListFilter および FtpRegexPatternFileListFilter は、alwaysAcceptDirectories プロパティを true に設定することにより、常にディレクトリを渡すように構成できます。これにより、次の例に示すように、単純なパターンの再帰が可能になります。

<bean id="starDotTxtFilter"
        class="org.springframework.integration.ftp.filters.FtpSimplePatternFileListFilter">
    <constructor-arg value="*.txt" />
    <property name="alwaysAcceptDirectories" value="true" />
</bean>

<bean id="dotStarDotTxtFilter"
            class="org.springframework.integration.ftp.filters.FtpRegexPatternFileListFilter">
    <constructor-arg value="^.*\.txt$" />
    <property name="alwaysAcceptDirectories" value="true" />
</bean>

前の例のようなフィルターを定義したら、ゲートウェイで filter プロパティを設定することにより、フィルターを使用できます。

put コマンドの使用

put コマンドは、ファイルを リモートサーバーに送信します。メッセージのペイロードは、java.io.Filebyte[]、または String です。remote-filename-generator (または式) を使用して、リモートファイルに名前を付けます。その他の使用可能な属性には、remote-directorytemporary-remote-directory、それらに相当する *-expression である use-temporary-file-name および auto-create-directory が含まれます。詳細については、スキーマ [GitHub] (英語) のドキュメントを参照してください。

put 操作の結果として生じるメッセージペイロードは、転送後のサーバー上のファイルの完全パスを表す String です。

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

mput コマンドの使用

mput は複数のファイルをサーバーに送信し、1 つのオプションのみをサポートします。

  • -R: 再帰的。ディレクトリとそのサブディレクトリ内のすべてのファイル(おそらくフィルタリングされた)を送信します。

メッセージペイロードは、ローカルディレクトリを表す java.io.File (または String)でなければなりません。バージョン 5.1 以降、File または String のコレクションもサポートされています。

このコマンドは、put コマンドと同じ属性をサポートしています。さらに、ローカルディレクトリ内のファイルは、mput-patternmput-regexmput-filter または mput-filter-expression のいずれかでフィルターできます。サブディレクトリ自体がフィルターを通過する限り、フィルターは再帰で機能します。フィルターを通過しないサブディレクトリは再帰されません。

mput 操作の結果のメッセージペイロードは、List<String> オブジェクト(つまり、転送の結果としてのリモートファイルパスの List)です。

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

rm コマンドの使用

rm コマンドはファイルを削除します。

rm コマンドにはオプションがありません。

rm 操作の結果としてのメッセージペイロードは、削除が成功した場合は Boolean.TRUE、そうでない場合は Boolean.FALSE です。file_remoteDirectory ヘッダーはリモートディレクトリを提供し、file_remoteFile ヘッダーはファイル名を提供します。

mv コマンドの使用

mv コマンドはファイルを移動します。

mv コマンドにはオプションがありません。

expression 属性は "from" パスを定義し、rename-expression 属性は "to" パスを定義します。デフォルトでは、rename-expression は headers['file_renameTo'] です。この式は null または空の String に評価してはなりません。必要に応じて、必要なリモートディレクトリが作成されます。結果メッセージのペイロードは Boolean.TRUE です。file_remoteDirectory ヘッダーは元のリモートディレクトリを提供し、file_remoteFile ヘッダーはファイル名を提供します。新しいパスは file_renameTo ヘッダーにあります。

バージョン 5.5.6 以降、remoteDirectoryExpression を mv コマンドで使用できるようになりました。"from" ファイルが完全なファイルパスでない場合、remoteDirectoryExpression の結果がリモートディレクトリとして使用されます。同じことが "to" ファイルにも当てはまります。たとえば、タスクがディレクトリ内のリモートファイルの名前を変更するだけの場合です。

FTP 送信ゲートウェイコマンドに関する追加情報

get および mget コマンドは、local-filename-generator-expression 属性をサポートしています。転送中にローカルファイルの名前を生成する SpEL 式を定義します。評価コンテキストのルートオブジェクトはリクエストメッセージです。mget で特に有用な remoteFileName 変数も使用可能です(例: local-filename-generator-expression="#remoteFileName.toUpperCase() + headers.something")。

get および mget コマンドは、local-directory-expression 属性をサポートしています。転送中にローカルディレクトリの名前を生成する SpEL 式を定義します。評価コンテキストのルートオブジェクトはリクエストメッセージですが、mget で特に有用な remoteDirectory 変数も使用可能です(例: local-directory-expression="'/tmp/local/' + #remoteDirectory.toUpperCase() + headers.something")。この属性は、local-directory 属性と相互に排他的です。

すべてのコマンドについて、ゲートウェイの「式」プロパティは、コマンドが機能するパスを提供します。mget コマンドの場合、式は "'、すべてのファイルを取得することを意味する、または ' somedirectory/" などと評価される場合があります。

次の例は、ls コマンド用に構成されたゲートウェイを示しています。

<int-ftp:outbound-gateway id="gateway1"
    session-factory="ftpSessionFactory"
    request-channel="inbound1"
    command="ls"
    command-options="-1"
    expression="payload"
    reply-channel="toSplitter"/>

toSplitter チャネルに送信されるメッセージのペイロードは、それぞれファイルの名前を含む String オブジェクトのリストです。command-options 属性が省略された場合、FileInfo オブジェクトを保持します。スペースで区切られたオプション(たとえば、command-options="-1 -dirs -links")を使用します。

バージョン 4.2 以降、GETMGETPUTMPUT コマンドは FileExistsMode プロパティ(名前空間サポートを使用する場合は mode)をサポートします。これは、ローカルファイルが存在する場合(GET および MGET)またはリモートファイルが存在する場合(PUT および MPUT)の動作に影響します。サポートされているモードは REPLACEAPPENDFAILIGNORE です。下位互換性のために、PUT および MPUT 操作のデフォルトモードは REPLACE です。GET および MGET 操作の場合、デフォルトは FAIL です。

バージョン 5.0 から、setWorkingDirExpression() (XML の working-dir-expression)オプションが FtpOutboundGateway (XML の <int-ftp:outbound-gateway>)で提供されます。実行時にクライアントの作業ディレクトリを変更できます。式はリクエストメッセージに対して評価されます。前の作業ディレクトリは、各ゲートウェイ操作の後に復元されます。

Java 構成を使用した構成

次の Spring Boot アプリケーションは、Java 構成で送信ゲートウェイを構成する方法の例を示しています。

@SpringBootApplication
public class FtpJavaApplication {

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

    @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() {
        FtpOutboundGateway ftpOutboundGateway =
                          new FtpOutboundGateway(ftpSessionFactory(), "ls", "'my_remote_dir/'");
        ftpOutboundGateway.setOutputChannelName("lsReplyChannel");
        return ftpOutboundGateway;
    }

}

Java DSL を使用した構成

次の Spring Boot アプリケーションは、送信ゲートウェイを Java DSL で構成する方法の例を示しています。

@SpringBootApplication
public class FtpJavaApplication {

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

    @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 FtpOutboundGatewaySpec ftpOutboundGateway() {
        return Ftp.outboundGateway(ftpSessionFactory(),
            AbstractRemoteFileOutboundGateway.Command.MGET, "payload")
            .options(AbstractRemoteFileOutboundGateway.Option.RECURSIVE)
            .regexFileNameFilter("(subFtpSource|.*1.txt)")
            .localDirectoryExpression("'localDirectory/' + #remoteDirectory")
            .localFilenameExpression("#remoteFileName.replaceFirst('ftpSource', 'localTarget')");
    }

    @Bean
    public IntegrationFlow ftpMGetFlow(AbstractRemoteFileOutboundGateway<FTPFile> ftpOutboundGateway) {
        return f -> f
            .handle(ftpOutboundGateway)
            .channel(c -> c.queue("remoteFileOutputChannel"));
    }

}

送信ゲートウェイの部分的な成功 (mget および mput)

mget および mput を使用して)複数のファイルに対して操作を実行すると、1 つ以上のファイルが転送された後、しばらく時間が経過する場合があります。この場合(バージョン 4.2 以降)、PartialSuccessException がスローされます。通常の MessagingException プロパティ(failedMessage および cause)と同様に、この例外には 2 つの追加プロパティがあります。

  • partialResults: 正常な転送結果。

  • derivedInput: リクエストメッセージから生成されたファイルのリスト(たとえば、mput 用に転送するローカルファイル)。

これらの属性により、正常に転送されたファイルと転送されなかったファイルを判別できます。

再帰的な mput の場合、PartialSuccessException にはネストされた PartialSuccessException 出現箇所があります。

次のディレクトリ構造を考慮してください。

root/
|- file1.txt
|- subdir/
   | - file2.txt
   | - file3.txt
|- zoo.txt

file3.txt で例外が発生した場合、ゲートウェイによってスローされた PartialSuccessException には、file1.txtsubdirzoo.txt の derivedInput と file1.txt の partialResults があります。その cause は、file2.txt の derivedInput と file2.txt の file3.txt および partialResults を備えた別の PartialSuccessException です。