SMB 支援
Spring Integration 提供對使用 SMB 進行檔案傳輸操作的支援。
Server Message Block (SMB) 是一種簡單的網路協議,允許您將檔案傳輸到共享檔案伺服器。
您需要在專案中包含此依賴項:
-
Maven
-
Gradle
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-smb</artifactId>
<version>6.4.4</version>
</dependency>
compile "org.springframework.integration:spring-integration-smb:6.4.4"
概述
我們選擇 Java CIFS 客戶端庫作為 CIFS/SMB 網路協議的 Java 實現。它的 SmbFile
抽象被簡單地封裝到 Spring Integration 的“遠端檔案”基礎中,例如 SmbSession
、SmbRemoteFileTemplate
等。
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
可以使用自定義的 jcifs.CIFSContext
進行初始化。
SMB 協議最小/最大版本的設定必須在您實現 jcifs.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 入站通道介面卡
為了在本地下載 SMB 檔案,提供了 SmbInboundFileSynchronizingMessageSource
。它是 AbstractInboundFileSynchronizingMessageSource
的簡單擴充套件,需要注入 SmbInboundFileSynchronizer
。對於過濾遠端檔案,您仍然可以使用任何現有的 FileListFilter
實現,但也提供了特定的 SmbRegexPatternFileListFilter
和 SmbSimplePatternFileListFilter
。
@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
屬性,以便只有比該值舊的檔案才能透過過濾器。預設 age 為 60 秒,但您應該選擇一個足夠大的 age 值,以避免過早選取檔案(例如,由於網路故障)。有關更多資訊,請查閱其 Javadoc。
使用 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
) 中提供。標準框架元件,例如 FileSplitter
和 StreamTransformer
,會自動關閉會話。有關這些元件的更多資訊,請參閱 檔案拆分器 和 流轉換器。以下示例展示瞭如何配置 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-pattern
、filename-regex
、filter
或 filter-expression
中的一個。
SmbStreamingMessageSource
介面卡使用基於記憶體 SimpleMetadataStore
的 SmbPersistentAcceptOnceFileListFilter
來防止遠端檔案重複。預設情況下,此過濾器也應用於檔名模式(或正則表示式)。如果您需要允許重複,可以使用 AcceptAllFileListFilter
。任何其他用例都可以透過 CompositeFileListFilter
(或 ChainFileListFilter
)處理。Java 配置(文件稍後)展示了一種在處理後刪除遠端檔案以避免重複的技術。
有關 SmbPersistentAcceptOnceFileListFilter
及其使用方法的更多資訊,請參閱 遠端持久化檔案列表過濾器。
當需要獲取檔案時,使用 max-fetch-size
屬性限制每次輪詢獲取的檔案數量。在叢集環境中執行時,將其設定為 1
並使用持久化過濾器。有關更多資訊,請參閱 入站通道介面卡:控制遠端檔案獲取。
介面卡將遠端目錄和檔名分別放入 FileHeaders.REMOTE_DIRECTORY
和 FileHeaders.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
,該 advice
在處理後刪除遠端檔案。
入站通道介面卡:控制遠端檔案獲取
配置入站通道介面卡時,有兩個屬性需要考慮。與其他輪詢器一樣,max-messages-per-poll
可用於限制每次輪詢發出的訊息數量(如果準備就緒的訊息數量超過配置值)。max-fetch-size
可以限制一次從遠端伺服器檢索的檔案數量。
以下場景假定起始狀態是本地目錄為空:
-
max-messages-per-poll=2
和max-fetch-size=1
:介面卡獲取一個檔案,發出,然後獲取下一個檔案,發出,然後休眠直到下一次輪詢。 -
max-messages-per-poll=2
和max-fetch-size=2
:介面卡獲取這兩個檔案,然後發出每個檔案。 -
max-messages-per-poll=2
和max-fetch-size=4
:介面卡最多獲取四個檔案(如果可用),併發出前兩個(如果至少有兩個)。接下來的兩個檔案將在下一次輪詢時發出。 -
max-messages-per-poll=2
且max-fetch-size
未指定:介面卡獲取所有遠端檔案,併發出前兩個(如果至少有兩個)。後續檔案在隨後的輪詢中發出(每次兩個)。當所有檔案都消費完畢後,會再次嘗試遠端獲取,以獲取任何新檔案。
當部署應用程式的多個例項時,我們建議使用較小的 max-fetch-size ,以避免一個例項“搶佔”所有檔案而使其他例項飢餓。 |
max-fetch-size
的另一種用途是,如果您想停止獲取遠端檔案但繼續處理已獲取的檔案。透過在 MessageSource
上設定 maxFetchSize
屬性(透過程式設計、JMX 或 控制匯流排)可以有效阻止介面卡獲取更多檔案,但允許輪詢器繼續為之前已獲取的檔案發出訊息。如果屬性更改時輪詢器處於活動狀態,則更改將在下一次輪詢時生效。
可以為同步器提供一個 Comparator<SmbFile>
。當使用 maxFetchSize
限制獲取的檔案數量時,這非常有用。
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
開關)。這些物件提供修改時間、許可權等資訊。
ls
命令作用的遠端目錄在 file_remoteDirectory
頭中提供。
使用遞迴選項 (-R
) 時,fileName
包含任何子目錄元素,表示相對於遠端目錄的檔案相對路徑。如果使用 -dirs
選項,每個遞迴目錄也會作為列表中的一個元素返回。在這種情況下,建議不要使用 -1
選項,因為您將無法區分檔案和目錄,而使用 FileInfo
物件可以做到這一點。
使用 nlst
命令
nlst
列出遠端檔名,僅支援一個選項:
-
-f
: 不對列表進行排序。
nlst
操作產生的訊息載荷是一個檔名列表。
file_remoteDirectory
頭包含 nlst
命令作用的遠端目錄。
使用 get
命令
get
檢索遠端檔案,支援以下選項:
-
-P
: 保留遠端檔案的時間戳。 -
-stream
: 將遠端檔案檢索為流。 -
-D
: 成功傳輸後刪除遠端檔案。如果傳輸被忽略(因為FileExistsMode
是IGNORE
且本地檔案已存在),則不刪除遠端檔案。
file_remoteDirectory
頭包含遠端目錄,file_remoteFile
頭包含檔名。
get
操作產生的訊息載荷是一個 File
物件,表示檢索到的檔案。如果使用 -stream
選項,載荷是一個 InputStream
而不是 File
。對於文字檔案,一個常見的用例是將此操作與 檔案拆分器 或 流轉換器 結合使用。以流方式消費遠端檔案時,您負責在消費流後關閉 Session
。為方便起見,Session
在 closeableResource
頭中提供,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
: 成功傳輸後刪除每個遠端檔案。如果傳輸被忽略(因為FileExistsMode
是IGNORE
且本地檔案已存在),則不刪除遠端檔案。
mget
操作產生的訊息載荷是一個 List<File>
物件(即 File
物件列表,每個物件代表一個檢索到的檔案)。
如果 FileExistsMode 是 IGNORE ,則輸出訊息的載荷不再包含因檔案已存在而被忽略的檔案。之前,陣列包含所有檔案,包括已存在的檔案。 |
您用於確定遠端路徑的表示式應生成以 結尾的結果,例如
myfiles/
獲取 myfiles
下的整個樹。
您可以將遞迴 MGET
與 FileExistsMode.REPLACE_IF_MODIFIED
模式結合使用,以定期在本地同步整個遠端目錄樹。此模式將本地檔案的最後修改時間戳設定為遠端檔案的時間戳,無論是否使用 -P
(保留時間戳)選項。
使用遞迴 (
-R ) 的注意事項:模式將被忽略,並假定為 如果您過濾了子目錄,則不會對該子目錄執行額外的遍歷。 不允許使用 通常,您會在 |
持久化檔案列表過濾器現在有一個布林屬性 forRecursion
。將此屬性設定為 true
,也會設定 alwaysAcceptDirectories
,這意味著出站閘道器上的遞迴操作(ls
和 mget
)現在每次都會始終遍歷完整的目錄樹。這是為了解決目錄樹深處變更未被檢測到的問題。此外,forRecursion=true
會將檔案的完整路徑用作元資料儲存鍵;這解決了如果同一名稱的檔案在不同目錄中多次出現時過濾器無法正常工作的問題。重要:這意味著在持久化元資料儲存中,頂級目錄下的檔案將無法找到現有鍵。因此,此屬性預設為 false
;這可能會在未來的版本中更改。
您可以配置 SmbSimplePatternFileListFilter
和 SmbRegexPatternFileListFilter
透過將 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
屬性提供這些過濾器之一。
另請參閱 出站閘道器部分成功 (mget
和 mput
)。
使用 put
命令
put
將檔案傳送到遠端伺服器。訊息的載荷可以是 java.io.File
、byte[]
或 String
。使用 remote-filename-generator
(或表示式)命名遠端檔案。其他可用屬性包括 remote-directory
、temporary-remote-directory
及其對應的 *-expression
:use-temporary-file-name
和 auto-create-directory
。有關更多資訊,請參閱模式文件。
put
操作產生的訊息載荷是一個 String
,其中包含檔案傳輸後在伺服器上的完整路徑。
使用 mput
命令
mput
將多個檔案傳送到伺服器,支援以下選項:
-
-R
: 遞迴 - 傳送目錄和子目錄中所有(可能已過濾的)檔案。
訊息載荷必須是一個 java.io.File
(或 String
),代表一個本地目錄。也支援 File
或 String
的集合。
支援與 put
命令 相同的屬性。此外,您可以使用 mput-pattern
、mput-regex
、mput-filter
或 mput-filter-expression
中的一個來過濾本地目錄中的檔案。只要子目錄本身透過過濾器,該過濾器就支援遞迴。未透過過濾器的子目錄將不會被遞迴。
mput
操作產生的訊息載荷是一個 List<String>
物件(即傳輸後生成的遠端檔案路徑列表)。
另請參閱 出站閘道器部分成功 (mget
和 mput
)。
使用 rm
命令
rm
命令沒有選項。
如果刪除操作成功,則生成的訊息載荷為 Boolean.TRUE
。否則,訊息載荷為 Boolean.FALSE
。file_remoteDirectory
頭包含遠端目錄,file_remoteFile
頭包含檔名。
使用 mv
命令
mv
命令沒有選項。
expression
屬性定義“源”路徑,rename-expression
屬性定義“目標”路徑。預設情況下,rename-expression
為 headers['file_renameTo']
。此表示式不得求值為 null 或空 String
。如果需要,會建立所需的遠端目錄。結果訊息的載荷是 Boolean.TRUE
。file_remoteDirectory
頭包含原始遠端目錄,file_remoteFile
頭包含檔名。file_renameTo
頭包含新路徑。
remoteDirectoryExpression
可用於 mv
命令,以方便使用。如果“源”檔案不是完整的 檔案路徑,則 remoteDirectoryExpression
的結果將用作遠端目錄。這同樣適用於“目標”檔案,例如,如果任務只是重新命名某個目錄中的遠端檔案。
附加命令資訊
get
和 mget
命令支援 local-filename-generator-expression
屬性。它定義一個 SpEL 表示式,用於在傳輸期間生成本地檔案的名稱。求值上下文的根物件是請求訊息。remoteFileName
變數也可用。這對於 mget
特別有用(例如:local-filename-generator-expression="#remoteFileName.toUpperCase() + headers.foo"
)。
get
和 mget
命令支援 local-directory-expression
屬性。它定義一個 SpEL 表示式,用於在傳輸期間生成本地目錄的名稱。求值上下文的根物件是請求訊息。remoteDirectory
變數也可用。這對於 mget 特別有用(例如:local-directory-expression="'/tmp/local/' + #remoteDirectory.toUpperCase() + headers.myheader"
)。此屬性與 local-directory
屬性互斥。
對於所有命令,閘道器的 'expression' 屬性包含命令作用的路徑。對於 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"
)。
GET
、MGET
、PUT
和 MPUT
命令支援一個 FileExistsMode
屬性(使用名稱空間支援時是 mode
)。這會影響當本地檔案存在(GET
和 MGET
)或遠端檔案存在(PUT
和 MPUT
)時的行為。支援的模式有 REPLACE
、APPEND
、FAIL
和 IGNORE
。為了向後相容,PUT
和 MPUT
操作的預設模式是 REPLACE
。對於 GET
和 MGET
操作,預設模式是 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"));
}
}
出站閘道器部分成功(mget
和 mput
)
當對多個檔案執行操作(使用 mget
和 mput
)時,在傳輸一個或多個檔案後可能會發生異常。在這種情況下,會丟擲 PartialSuccessException
。除了通常的 MessagingException
屬性(failedMessage
和 cause
)之外,此異常還有兩個額外的屬性
-
partialResults
:成功的傳輸結果。 -
derivedInput
:根據請求訊息生成的檔案列表(例如mput
要傳輸的本地檔案)。
這些屬性使您能夠確定哪些檔案成功傳輸,哪些檔案未能成功傳輸。
在遞迴的 mput
情況下,PartialSuccessException
可能包含巢狀的 PartialSuccessException
例項。
考慮以下目錄結構
root/
|- file1.txt
|- subdir/
| - file2.txt
| - file3.txt
|- zoo.txt
如果異常發生在 file3.txt
上,則閘道器丟擲的 PartialSuccessException
的 derivedInput
為 file1.txt
、subdir
和 zoo.txt
,partialResults
為 file1.txt
。它的 cause
是另一個 PartialSuccessException
,其 derivedInput
為 file2.txt
和 file3.txt
,partialResults
為 file2.txt
。
遠端檔案資訊
SmbStreamingMessageSource
(SMB 流式入站通道介面卡)、SmbInboundFileSynchronizingMessageSource
(SMB 入站通道介面卡)以及 SmbOutboundGateway
(SMB 出站閘道器)的“讀取”命令在生成的訊息中提供關於遠端檔案的附加訊息頭
-
FileHeaders.REMOTE_HOST_PORT
- 檔案傳輸操作期間遠端會話連線到的主機:埠 對; -
FileHeaders.REMOTE_DIRECTORY
- 執行操作的遠端目錄; -
FileHeaders.REMOTE_FILE
- 遠端檔名;僅適用於單個檔案操作。
由於 SmbInboundFileSynchronizingMessageSource
不直接針對遠端檔案生成訊息,而是使用本地副本,AbstractInboundFileSynchronizer
在同步操作期間以 URI 風格(protocol://host:port/remoteDirectory#remoteFileName
)將遠端檔案的資訊儲存在 MetadataStore
(可外部配置)中。當輪詢本地檔案時,SmbInboundFileSynchronizingMessageSource
會檢索此元資料。當刪除本地檔案時,建議移除其元資料條目。為此,AbstractInboundFileSynchronizer
提供了一個 removeRemoteFileMetadata()
回撥。此外,還有一個用於元資料鍵的 setMetadataStorePrefix()
。當在這些元件之間共享同一個 MetadataStore
例項時,建議使此字首與基於 MetadataStore
的 FileListFilter
實現中使用的字首不同,以避免條目覆蓋,因為過濾器和 AbstractInboundFileSynchronizer
都使用相同的本地檔名作為元資料條目鍵。