SMB 支援

Spring Integration 提供對 SMB 檔案傳輸操作的支援。

伺服器訊息塊 (SMB) 是一種簡單的網路協議,允許您將檔案傳輸到共享檔案伺服器。

專案需要此依賴項

  • Maven

  • Gradle

<dependency>
    <groupId>org.springframework.integration</groupId>
    <artifactId>spring-integration-smb</artifactId>
    <version>7.0.0</version>
</dependency>
compile "org.springframework.integration:spring-integration-smb:7.0.0"

概述

Java CIFS 客戶端庫已被選為 CIFS/SMB 網路協議的 Java 實現。它的 SmbFile 抽象被簡單地包裝到 Spring Integration 的“遠端檔案”基礎中,例如 SmbSessionSmbRemoteFileTemplate 等。

SMB 通道介面卡和支援類實現與現有 (S)FTP 或 AWS S3 協議元件完全相似。因此,如果您熟悉這些元件,使用起來會非常簡單。

Spring Integration 透過提供三個客戶端端點來支援透過 SMB 傳送和接收檔案:入站通道介面卡、出站通道介面卡和出站閘道器。它還提供了方便的基於名稱空間的配置選項來定義這些客戶端元件。

要使用 SMB 名稱空間,請將以下內容新增到 XML 檔案的頭部

xmlns:int-smb="http://www.springframework.org/schema/integration/smb"
xsi:schemaLocation="http://www.springframework.org/schema/integration/smb
    https://www.springframework.org/schema/integration/smb/spring-integration-smb.xsd"

SMB 會話工廠

在配置 SMB 介面卡之前,您必須配置一個 SMB 會話工廠。您可以使用常規的 bean 定義來配置 SMB 會話工廠,如以下示例所示

SmbSessionFactory 暴露了設定具有最小/最大版本 SMB 協議的選項。例如,支援 SMB 2.1 的最小版本和 SMB 3.1.1 的最大版本

@Bean
public SmbSessionFactory smbSessionFactory() {
    SmbSessionFactory smbSession = new SmbSessionFactory();
    smbSession.setHost("myHost");
    smbSession.setPort(445);
    smbSession.setDomain("myDomain");
    smbSession.setUsername("myUser");
    smbSession.setPassword("myPassword");
    smbSession.setShareAndDir("myShareAndDir");
    smbSession.setSmbMinVersion(DialectVersion.SMB210);
    smbSession.setSmbMaxVersion(DialectVersion.SMB311);
    return smbSession;
}

SmbSessionFactory 可以使用自定義的 org.codelibs.jcifs.smb.CIFSContext 進行初始化。

SMB 協議最小/最大版本的設定必須在您的 org.codelibs.jcifs.smb.CIFSContext 實現中完成。
@Bean
public SmbSessionFactory smbSessionFactory() {
    SmbSessionFactory smbSession = new SmbSessionFactory(new MyCIFSContext());
    smbSession.setHost("myHost");
    smbSession.setPort(445);
    smbSession.setDomain("myDomain");
    smbSession.setUsername("myUser");
    smbSession.setPassword("myPassword");
    smbSession.setShareAndDir("myShareAndDir");
    return smbSession;
}

SMB 會話快取

SmbSessionFactory 在每次請求 Session 時都會啟動一個新連線。在大多數情況下,這不是必需的,並且可以快取 Session。為此,前面提到的 SmbSessionFactory 應該被包裝到 CachingSessionFactory 的例項中

@Bean
public CachingSessionFactory cachingSessionFactory(SmbSessionFactory smbSessionFactory) {
    cachingSessionFactory cachingSessionFactory = new CachingSessionFactory(smbSessionFactory, 10);
    cachingSessionFactory.setSessionWaitTimeout(1000);
    return cachingSessionFactory;
}

然後它的 bean 可以注入到下面描述的通道介面卡中。

SMB 入站通道介面卡

為了在本地下載 SMB 檔案,提供了 SmbInboundFileSynchronizingMessageSource。它是 AbstractInboundFileSynchronizingMessageSource 的簡單擴充套件,需要注入 SmbInboundFileSynchronizer。對於過濾遠端檔案,您仍然可以使用任何現有的 FileListFilter 實現,但提供了特定的 SmbRegexPatternFileListFilterSmbSimplePatternFileListFilter

@Bean
public SmbInboundFileSynchronizer smbInboundFileSynchronizer() {
    SmbInboundFileSynchronizer fileSynchronizer =
        new SmbInboundFileSynchronizer(smbSessionFactory());
    fileSynchronizer.setFilter(compositeFileListFilter());
    fileSynchronizer.setRemoteDirectory("mySharedDirectoryPath");
    fileSynchronizer.setDeleteRemoteFiles(true);
    return fileSynchronizer;
}

@Bean
public CompositeFileListFilter<SmbFile> compositeFileListFilter() {
    CompositeFileListFilter<SmbFile> filters = new CompositeFileListFilter<>();
    filters.addFilter(new SmbRegexPatternFileListFilter("^(?i).+((\\.txt))$"));
    return filters;
}

@Bean
public MessageChannel smbFileInputChannel() {
    return new DirectChannel();
}

@Bean
@InboundChannelAdapter(value = "smbFileInputChannel",
                       poller = @Poller(fixedDelay = "2000"))
public MessageSource<File> smbMessageSource() {
    SmbInboundFileSynchronizingMessageSource messageSource =
        new SmbInboundFileSynchronizingMessageSource(smbInboundFileSynchronizer());
    messageSource.setLocalDirectory(new File("myLocalDirectoryPath"));
    messageSource.setAutoCreateLocalDirectory(true);
    return messageSource;
}

對於 XML 配置,提供了 <int-smb:inbound-channel-adapter> 元件。

從 6.2 版開始,您可以使用 SmbLastModifiedFileListFilter 根據上次修改策略過濾 SMB 檔案。此過濾器可以配置一個 age 屬性,以便只有早於此值的檔案才能透過過濾器。預設年齡為 60 秒,但您應該選擇一個足夠大的年齡,以避免過早地獲取檔案(例如,由於網路故障)。有關更多資訊,請參閱其 Javadoc。

相比之下,從 6.5 版開始,引入了 SmbRecentFileListFilter,只接受不早於給定 age 的檔案。

使用 Java DSL 進行配置

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

@SpringBootApplication
public class SmbJavaApplication {

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

    @Bean
    public SmbSessionFactory smbSessionFactory() {
        SmbSessionFactory smbSession = new SmbSessionFactory();
        smbSession.setHost("myHost");
        smbSession.setPort(445);
        smbSession.setDomain("myDomain");
        smbSession.setUsername("myUser");
        smbSession.setPassword("myPassword");
        smbSession.setShareAndDir("myShareAndDir");
        smbSession.setSmbMinVersion(DialectVersion.SMB210);
        smbSession.setSmbMaxVersion(DialectVersion.SMB311);
        return smbSession;
    }

    @Bean
    public IntegrationFlow smbInboundFlow() {
        return IntegrationFlow
            .from(Smb.inboundAdapter(smbSessionFactory())
                    .preserveTimestamp(true)
                    .remoteDirectory("smbSource")
                    .regexFilter(".*\\.txt$")
                    .localFilename(f -> f.toUpperCase() + ".a")
                    .localDirectory(new File("d:\\smb_files")),
                        e -> e.id("smbInboundAdapter")
                    .autoStartup(true)
                    .poller(Pollers.fixedDelay(5000)))
            .handle(m -> System.out.println(m.getPayload()))
            .get();
    }
}

SMB 流式入站通道介面卡

此介面卡生成一個載荷型別為 InputStream 的訊息,允許在不寫入本地檔案系統的情況下獲取檔案。由於會話保持開啟狀態,因此消費應用程式負責在檔案被消費後關閉會話。會話在 closeableResource 頭部 (IntegrationMessageHeaderAccessor.CLOSEABLE_RESOURCE) 中提供。標準框架元件,例如 FileSplitterStreamTransformer,會自動關閉會話。有關這些元件的更多資訊,請參閱檔案拆分器流轉換器。以下示例顯示瞭如何配置 inbound-streaming-channel-adapter

<int-smb:inbound-streaming-channel-adapter id="smbInbound"
            channel="smbChannel"
            session-factory="sessionFactory"
            filename-pattern="*.txt"
            filename-regex=".*\.txt"
            filter="filter"
            filter-expression="@myFilterBean.check(#root)"
            remote-file-separator="/"
            comparator="comparator"
            max-fetch-size="1"
            remote-directory-expression="'foo/bar'">
        <int:poller fixed-rate="1000" />
</int-smb:inbound-streaming-channel-adapter>

只允許使用 filename-patternfilename-regexfilterfilter-expression 中的一個。

SmbStreamingMessageSource 介面卡基於記憶體中的 SimpleMetadataStore,透過 SmbPersistentAcceptOnceFileListFilter 防止遠端檔案重複。預設情況下,此過濾器也適用於檔名模式(或正則表示式)。如果需要允許重複,可以使用 AcceptAllFileListFilter。任何其他用例都可以透過 CompositeFileListFilter(或 ChainFileListFilter)處理。Java 配置(文件後面)展示了一種在處理後刪除遠端檔案以避免重複的技術。

有關 SmbPersistentAcceptOnceFileListFilter 及其使用方式的更多資訊,請參閱遠端持久檔案列表過濾器

當需要獲取檔案時,使用 max-fetch-size 屬性限制每次輪詢獲取的檔案數量。在叢集環境中執行時,將其設定為 1 並使用持久過濾器。有關更多資訊,請參閱入站通道介面卡:控制遠端檔案獲取

介面卡將遠端目錄和檔名分別放在 FileHeaders.REMOTE_DIRECTORYFileHeaders.REMOTE_FILE 頭部。FileHeaders.REMOTE_FILE_INFO 頭部提供額外的遠端檔案資訊(預設以 JSON 表示)。如果將 SmbStreamingMessageSource 上的 fileInfoJson 屬性設定為 false,則該頭部包含一個 SmbFileInfo 物件。

使用 Java 配置進行配置

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

@SpringBootApplication
public class SmbJavaApplication {

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

    @Bean
    @InboundChannelAdapter(channel = "stream")
    public MessageSource<InputStream> smbMessageSource() {
        SmbStreamingMessageSource messageSource = new SmbStreamingMessageSource(template());
        messageSource.setRemoteDirectory("smbSource/");
        messageSource.setFilter(new AcceptAllFileListFilter<>());
        messageSource.setMaxFetchSize(1);
        return messageSource;
    }

    @Bean
    @Transformer(inputChannel = "stream", outputChannel = "data")
    public org.springframework.integration.transformer.Transformer transformer() {
        return new StreamTransformer("UTF-8");
    }

    @Bean
    public SmbRemoteFileTemplate template() {
        return new SmbRemoteFileTemplate(smbSessionFactory());
    }

    @ServiceActivator(inputChannel = "data", adviceChain = "after")
    @Bean
    public MessageHandler handle() {
        return System.out::println;
    }

    @Bean
    public ExpressionEvaluatingRequestHandlerAdvice after() {
        ExpressionEvaluatingRequestHandlerAdvice advice = new ExpressionEvaluatingRequestHandlerAdvice();
        advice.setOnSuccessExpression(
                "@template.remove(headers['file_remoteDirectory'] + headers['file_remoteFile'])");
        advice.setPropagateEvaluationFailures(true);
        return advice;
    }

}

請注意,在此示例中,轉換器下游的訊息處理器有一個 advice,它在處理後刪除遠端檔案。

入站通道介面卡:控制遠端檔案獲取

有關完全相同的通用功能,請參閱SFTP:控制遠端檔案獲取

SMB 出站通道介面卡

對於將檔案寫入 SMB 共享,以及對於 XML <int-smb:outbound-channel-adapter> 元件,我們使用 SmbMessageHandler。在 Java 配置的情況下,SmbMessageHandler 應該提供 SmbSessionFactory(或 SmbRemoteFileTemplate)。

@Bean
@ServiceActivator(inputChannel = "storeToSmbShare")
public MessageHandler smbMessageHandler(SmbSessionFactory smbSessionFactory) {
    SmbMessageHandler handler = new SmbMessageHandler(smbSessionFactory);
    handler.setRemoteDirectoryExpression(
        new LiteralExpression("remote-target-dir"));
    handler.setFileNameGenerator(m ->
        m.getHeaders().get(FileHeaders.FILENAME, String.class) + ".test");
    handler.setAutoCreateDirectory(true);
    return handler;
}

使用 Java DSL 進行配置

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

@SpringBootApplication
@IntegrationComponentScan
public class SmbJavaApplication {

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

    @Bean
    public SmbSessionFactory smbSessionFactory() {
        SmbSessionFactory smbSession = new SmbSessionFactory();
        smbSession.setHost("myHost");
        smbSession.setPort(445);
        smbSession.setDomain("myDomain");
        smbSession.setUsername("myUser");
        smbSession.setPassword("myPassword");
        smbSession.setShareAndDir("myShareAndDir");
        smbSession.setSmbMinVersion(DialectVersion.SMB210);
        smbSession.setSmbMaxVersion(DialectVersion.SMB311);
        return smbSession;
    }

    @Bean
    public IntegrationFlow smbOutboundFlow() {
        return IntegrationFlow.from("toSmbChannel")
                .handle(Smb.outboundAdapter(smbSessionFactory(), FileExistsMode.REPLACE)
                        .useTemporaryFileName(false)
                        .fileNameExpression("headers['" + FileHeaders.FILENAME + "']")
                        .remoteDirectory("smbTarget")
                ).get();
    }

    @MessagingGateway
    public interface MyGateway {

         @Gateway(requestChannel = "toSmbChannel")
         void sendToSmb(File file);
    }

}

SMB 出站閘道器

SMB 出站閘道器提供了一組有限的命令來與遠端 SMB 伺服器互動。支援的命令有

  • ls (列出檔案)

  • nlst (列出檔名)

  • get (檢索檔案)

  • mget (檢索檔案集)

  • rm (刪除檔案集)

  • mv (移動/重新命名檔案)

  • put (傳送檔案)

  • mput (傳送多個檔案)

使用 ls 命令

ls 列出遠端檔案並支援以下選項:

  • -1: 檢索檔名列表。預設是檢索 FileInfo 物件列表

  • -a: 包含所有檔案(包括以 . 開頭的檔案)

  • -f: 不對列表進行排序

  • -dirs: 包含目錄(預設排除)

  • -links: 包含符號連結(預設排除)

  • -R: 遞迴列出遠端目錄

此外,還以與 inbound-channel-adapter 相同的方式提供檔名過濾。

ls 操作產生的訊息載荷是檔名列表或 FileInfo 物件列表(取決於您是否使用 -1 開關)。這些物件提供修改時間、許可權等資訊。

file_remoteDirectory 頭部提供了 ls 命令操作的遠端目錄。

當使用遞迴選項 (-R) 時,fileName 包含任何子目錄元素,並表示檔案的相對路徑(相對於遠端目錄)。如果您使用 -dirs 選項,每個遞迴目錄也會作為列表中的一個元素返回。在這種情況下,我們建議您不要使用 -1 選項,因為您將無法區分檔案和目錄,而當您使用 FileInfo 物件時可以做到這一點。

使用 nlst 命令

nlst 列出遠端檔名,並且只支援一個選項。

  • -f: 不對列表進行排序

nlst 操作產生的訊息載荷是檔名列表。

file_remoteDirectory 頭部包含 nlst 命令作用的遠端目錄。

使用 get 命令

get 檢索遠端檔案並支援以下選項

  • -P: 保留遠端檔案的時間戳。

  • -stream: 以流形式檢索遠端檔案。

  • -D: 成功傳輸後刪除遠端檔案。如果傳輸被忽略(因為 FileExistsModeIGNORE 且本地檔案已存在),則不刪除遠端檔案。

file_remoteDirectory 頭部包含遠端目錄,file_remoteFile 頭部包含檔名。

get 操作產生的訊息載荷是一個 File 物件,表示檢索到的檔案。如果您使用 -stream 選項,載荷是 InputStream 而不是 File。對於文字檔案,常見的用例是將此操作與檔案拆分器流轉換器結合使用。當以流的形式消費遠端檔案時,您有責任在消費流後關閉 Session。為方便起見,SessioncloseableResource 頭部中提供,並且 IntegrationMessageHeaderAccessor 提供了便捷方法

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

框架元件,例如檔案拆分器流轉換器,在資料傳輸後會自動關閉會話。

以下示例顯示如何以流形式使用檔案:

<int-smb:outbound-gateway session-factory="smbSessionFactory"
                            request-channel="inboundGetStream"
                            command="get"
                            command-options="-stream"
                            expression="payload"
                            remote-directory="smbTarget"
                            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: 成功傳輸後刪除每個遠端檔案。如果傳輸被忽略,則不刪除遠端檔案,因為 FileExistsModeIGNORE 並且本地檔案已存在。

mget 操作產生的訊息載荷是一個 List<File> 物件(即一個 File 物件列表,每個物件表示一個檢索到的檔案)。

如果 FileExistsModeIGNORE,則輸出訊息的載荷不再包含由於檔案已存在而未獲取的檔案。以前,陣列包含所有檔案,包括那些已存在的檔案。

您使用的表示式確定遠端路徑應該產生以 * 結尾的結果,例如 myfiles/* 獲取 myfiles 下的完整樹。

您可以結合 FileExistsMode.REPLACE_IF_MODIFIED 模式使用遞迴 MGET,以定期在本地同步整個遠端目錄樹。此模式會將本地檔案的上次修改時間戳設定為遠端檔案的時間戳,而無論 -P(保留時間戳)選項如何。

使用遞迴 (-R) 時的注意事項

模式被忽略,並假定為 *。預設情況下,檢索整個遠端樹。但是,您可以透過提供 FileListFilter 來過濾樹中的檔案。您也可以透過這種方式過濾樹中的目錄。FileListFilter 可以透過引用或透過 filename-patternfilename-regex 屬性提供。例如,filename-regex="(subDir|.*1.txt)" 檢索遠端目錄和子目錄 subDir 中所有以 1.txt 結尾的檔案。但是,我們將在本注意事項之後描述一種替代方法。

如果您過濾子目錄,則不會對該子目錄進行額外的遍歷。

不允許使用 -dirs 選項(遞迴 mget 使用遞迴 ls 獲取目錄樹,並且目錄本身不能包含在列表中)。

通常,您會在 local-directory-expression 中使用 #remoteDirectory 變數,以便在本地保留遠端目錄結構。

持久檔案列表過濾器現在有一個布林屬性 forRecursion。將此屬性設定為 true,還會設定 alwaysAcceptDirectories,這意味著出站閘道器上的遞迴操作(lsmget)現在每次都會遍歷完整的目錄樹。這是為了解決目錄樹深處的變化未被檢測到的問題。此外,forRecursion=true 會導致檔案的完整路徑用作元資料儲存鍵;這解決了如果具有相同名稱的檔案在不同目錄中多次出現時過濾器無法正常工作的問題。重要提示:這意味著在頂層目錄下的檔案中,持久元資料儲存中的現有鍵將找不到。因此,此屬性預設為 false;這可能會在未來的版本中更改。

您可以將 SmbSimplePatternFileListFilterSmbRegexPatternFileListFilter 配置為始終透過目錄,方法是將 alwaysAcceptDirectorties 設定為 true。這樣做允許簡單模式的遞迴,如以下示例所示

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

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

您可以透過閘道器上的 filter 屬性提供這些過濾器之一。

使用 put 命令

put 將檔案傳送到遠端伺服器。訊息的載荷可以是 java.io.Filebyte[]Stringremote-filename-generator(或表示式)用於命名遠端檔案。其他可用屬性包括 remote-directorytemporary-remote-directory 及其 *-expression 等價物:use-temporary-file-nameauto-create-directory。有關更多資訊,請參閱模式文件

put 操作產生的訊息載荷是一個 String,其中包含傳輸後伺服器上檔案的完整路徑。

使用 mput 命令

mput 將多個檔案傳送到伺服器並支援以下選項

  • -R: 遞迴 — 傳送目錄和子目錄中的所有檔案(可能已過濾)

訊息載荷必須是表示本地目錄的 java.io.File(或 String)。也支援 FileString 的集合。

支援與put 命令相同的屬性。此外,您可以使用 mput-patternmput-regexmput-filtermput-filter-expression 之一過濾本地目錄中的檔案。只要子目錄本身透過過濾器,過濾器就可以與遞迴一起工作。未透過過濾器的子目錄不會進行遞迴。

mput 操作產生的訊息載荷是一個 List<String> 物件(即,傳輸產生的遠端檔案路徑列表)。

使用 rm 命令

rm 命令沒有選項。

如果刪除操作成功,則生成的訊息載荷為 Boolean.TRUE。否則,訊息載荷為 Boolean.FALSEfile_remoteDirectory 頭部包含遠端目錄,file_remoteFile 頭部包含檔名。

使用 mv 命令

mv 命令沒有選項。

expression 屬性定義“源”路徑,rename-expression 屬性定義“目標”路徑。預設情況下,rename-expressionheaders['file_renameTo']。此表示式不得評估為 null 或空 String。如有必要,將建立所需的任何遠端目錄。結果訊息的載荷為 Boolean.TRUEfile_remoteDirectory 頭部包含原始遠端目錄,file_remoteFile 頭部包含檔名。file_renameTo 頭部包含新路徑。

remoteDirectoryExpression 可以在 mv 命令中用於方便。如果“源”檔案不是完整的檔案路徑,則 remoteDirectoryExpression 的結果將用作遠端目錄。對於“目標”檔案也是如此,例如,如果任務只是重新命名某個目錄中的遠端檔案。

附加命令資訊

getmget 命令支援 local-filename-generator-expression 屬性。它定義了一個 SpEL 表示式,用於在傳輸期間生成本地檔名。評估上下文的根物件是請求訊息。remoteFileName 變數也可用。它對於 mget 特別有用(例如:local-filename-generator-expression="#remoteFileName.toUpperCase() + headers.foo")。

getmget 命令支援 local-directory-expression 屬性。它定義了一個 SpEL 表示式,用於在傳輸期間生成本地目錄的名稱。評估上下文的根物件是請求訊息。remoteDirectory 變數也可用。它對於 mget 特別有用(例如:local-directory-expression="'/tmp/local/' + #remoteDirectory.toUpperCase() + headers.myheader")。此屬性與 local-directory 屬性互斥。

對於所有命令,閘道器的“表示式”屬性都包含命令作用的路徑。對於 mget 命令,表示式可能會評估為 *,表示檢索所有檔案,somedirectory/\*,以及其他以 * 結尾的值。

以下示例顯示了配置為 ls 命令的閘道器:

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

傳送到 toSplitter 通道的訊息的載荷是 String 物件列表,每個物件都包含檔名。如果您省略了 command-options="-1",則載荷將是 FileInfo 物件列表。您可以將選項作為空格分隔的列表提供,例如 command-options="-1 -dirs -links"

GETMGETPUTMPUT 命令支援 FileExistsMode 屬性(在使用名稱空間支援時為 mode)。這會影響本地檔案存在(GETMGET)或遠端檔案存在(PUTMPUT)時的行為。支援的模式有 REPLACEAPPENDFAILIGNORE。為了向後相容,PUTMPUT 操作的預設模式是 REPLACE。對於 GETMGET 操作,預設模式是 FAIL

使用 Java 配置

以下 Spring Boot 應用程式展示瞭如何使用 Java 配置配置出站閘道器的示例

@SpringBootApplication
public class SmbJavaApplication {

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

    @Bean
    public SmbSessionFactory smbSessionFactory() {
        SmbSessionFactory smbSession = new SmbSessionFactory();
        smbSession.setHost("myHost");
        smbSession.setPort(445);
        smbSession.setDomain("myDomain");
        smbSession.setUsername("myUser");
        smbSession.setPassword("myPassword");
        smbSession.setShareAndDir("myShareAndDir");
        smbSession.setSmbMinVersion(DialectVersion.SMB210);
        smbSession.setSmbMaxVersion(DialectVersion.SMB311);
        return smbSession;
    }

    @Bean
    @ServiceActivator(inputChannel = "smbChannel")
    public MessageHandler handler() {
        SmbOutboundGateway smbOutboundGateway =
            new SmbOutboundGateway(smbSessionFactory(), "'my_remote_dir/'");
        smbOutboundGateway.setOutputChannelName("replyChannel");
        return smbOutboundGateway;
    }

}

使用 Java DSL 進行配置

以下 Spring Boot 應用程式顯示瞭如何使用 Java DSL 配置出站閘道器的示例:

@SpringBootApplication
public class SmbJavaApplication {

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

    @Bean
    public SmbSessionFactory smbSessionFactory() {
        SmbSessionFactory smbSession = new SmbSessionFactory();
        smbSession.setHost("myHost");
        smbSession.setPort(445);
        smbSession.setDomain("myDomain");
        smbSession.setUsername("myUser");
        smbSession.setPassword("myPassword");
        smbSession.setShareAndDir("myShareAndDir");
        smbSession.setSmbMinVersion(DialectVersion.SMB210);
        smbSession.setSmbMaxVersion(DialectVersion.SMB311);
        return smbSession;
    }

    @Bean
    public SmbOutboundGatewaySpec smbOutboundGateway() {
        return Smb.outboundGateway(smbSessionFactory(),
            AbstractRemoteFileOutboundGateway.Command.MGET, "payload")
            .options(AbstractRemoteFileOutboundGateway.Option.RECURSIVE)
            .regexFileNameFilter("(subSmbSource|.*.txt)")
            .localDirectoryExpression("'localDirectory/' + #remoteDirectory")
            .localFilenameExpression("#remoteFileName.replaceFirst('smbSource', 'localTarget')");
    }

    @Bean
    public IntegrationFlow smbFlow(AbstractRemoteFileOutboundGateway<SmbFile> smbOutboundGateway) {
        return f -> f
            .handle(smbOutboundGateway)
            .channel(c -> c.queue("remoteFileOutputChannel"));
    }

}

出站閘道器部分成功 (mgetmput)

當對多個檔案執行操作(透過使用 mgetmput)時,在一個或多個檔案傳輸之後可能會發生異常。在這種情況下,會丟擲 PartialSuccessException。除了通常的 MessagingException 屬性(failedMessagecause)之外,此異常還有兩個附加屬性

  • partialResults: 成功的傳輸結果。

  • derivedInput: 從請求訊息生成的(檔案)列表(例如,要傳輸的本地檔案,用於 mput)。

這些屬性讓您可以確定哪些檔案成功傳輸,哪些沒有。

在遞迴 mput 的情況下,PartialSuccessException 可能包含巢狀的 PartialSuccessException 例項。

考慮以下目錄結構:

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

如果在 file3.txt 上發生異常,則閘道器丟擲的 PartialSuccessExceptionderivedInputfile1.txtsubdirzoo.txtpartialResultsfile1.txt。其 cause 是另一個 PartialSuccessException,其 derivedInputfile2.txtfile3.txtpartialResultsfile2.txt

遠端檔案資訊

SmbStreamingMessageSource (SMB 流式入站通道介面卡)、SmbInboundFileSynchronizingMessageSource (SMB 入站通道介面卡) 和 SmbOutboundGateway 的“讀取”命令 (SMB 出站閘道器) 在訊息中提供額外的頭部,以生成有關遠端檔案的資訊

  • FileHeaders.REMOTE_HOST_PORT - 檔案傳輸操作期間遠端會話連線到的主機:埠對;

  • FileHeaders.REMOTE_DIRECTORY - 執行操作的遠端目錄;

  • FileHeaders.REMOTE_FILE - 遠端檔名;僅適用於單個檔案操作。

由於 SmbInboundFileSynchronizingMessageSource 不會針對遠端檔案生成訊息,而是使用本地副本,因此 AbstractInboundFileSynchronizer 在同步操作期間將遠端檔案資訊儲存在 MetadataStore(可以外部配置)中,URI 樣式為 (protocol://host:port/remoteDirectory#remoteFileName)。當輪詢本地檔案時,SmbInboundFileSynchronizingMessageSource 會檢索此元資料。當刪除本地檔案時,建議刪除其元資料條目。為此,AbstractInboundFileSynchronizer 提供了一個 removeRemoteFileMetadata() 回撥。此外,還有一個 setMetadataStorePrefix() 用於元資料鍵。建議此字首與基於 MetadataStoreFileListFilter 實現中使用的字首不同,當這些元件之間共享相同的 MetadataStore 例項時,以避免條目覆蓋,因為過濾器和 AbstractInboundFileSynchronizer 都使用相同的本地檔名作為元資料條目鍵。

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