SMB Support
Spring 集成通过 SMB 提供对文件传输操作的支持。
Spring Integration provides support for file transfer operations with SMB.
Server Message Block(SMB)是一种简单的网络协议,可让您将文件传输到共享文件服务器。
The Server Message Block (SMB) is a simple network protocol that lets you transfer files to a shared file server.
你需要将此依赖项包含在你的项目中:
You need to include this dependency into your project:
-
Maven
-
Gradle
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-smb</artifactId>
<version>{project-version}</version>
</dependency>
compile "org.springframework.integration:spring-integration-smb:{project-version}"
Overview
已选择 Java CIFS客户端库作为 CIFS/SMB 网络协议的 Java 实现。它的 SmbFile`抽象简单地封装到 Spring Integration 的“Remote File”基础中,例如 `SmbSession
、`SmbRemoteFileTemplate`等。
The Java CIFS Client Library has been chosen as a Java implementation for the CIFS/SMB networking protocol.
Its SmbFile
abstraction is simply wrapped to the Spring Integration "Remote File" foundations like SmbSession
, SmbRemoteFileTemplate
, etc.
SMB 信道适配器和支持类实现与 (S)FTP 或 AWS S3 协议的现有组件完全类似。因此,如果您熟悉那些组件,那么使用起来将非常简单。
The SMB Channel Adapters and support classes implementations are fully similar to existing components for (S)FTP or AWS S3 protocols. So, if you familiar with those components it is pretty straightforward to use.
Spring 集成通过提供三个客户端端点来支持通过 SMB 发送和接收文件:入站信道适配器、出站信道适配器和出站网关。它还提供了基于名称空间的便捷配置选项,用于定义这些客户端组件。
Spring Integration supports sending and receiving files over SMB by providing three client-side endpoints: inbound channel adapter, outbound channel adapter, and outbound gateway. It also provides convenient namespace-based configuration options for defining these client components.
要使用 SMB 名称空间,请将以下内容添加到 XML 文件的标头中:
To use the SMB namespace, add the following to the header of your XML file:
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 Session Factory
在配置 SMB 适配器之前,您必须配置一个 SMB 会话工厂。您可以使用常规 Bean 定义配置 SMB 会话工厂,如下面的示例所示:
Before configuring the SMB adapter, you must configure an SMB session factory. You can configure the SMB session factory with a regular bean definition, as the following examples show:
SmbSessionFactory
公开了用于设置具有最小/最大版本的 SMB 协议的选项。例如,支持 SMB 2.1 的最小版本和 SMB 3.1.1 的最大版本:
The SmbSessionFactory
exposes options to set the SMB protocol with Min/Max versions.
For example, supporting a minimum version of SMB 2.1 and a maximum version of the 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
初始化。
The SmbSessionFactory
can be initialized with a custom jcifs.CIFSContext
.
SMB 协议最小/最大版本的设置必须在 |
Setting of the SMB protocol Min/Max versions must be done in your implementation of |
@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 Inbound Channel Adapter
要本地下载 SMB 文件,提供了 SmbInboundFileSynchronizingMessageSource
。它是 AbstractInboundFileSynchronizingMessageSource
的简单扩展,它需要 SmbInboundFileSynchronizer
注入。对于筛选远程文件,您仍然可以使用任何现有的 FileListFilter
实现,但提供了特别的 SmbRegexPatternFileListFilter
和 SmbSimplePatternFileListFilter
。
To download SMB files locally the SmbInboundFileSynchronizingMessageSource
is provided.
It is simple extension of the AbstractInboundFileSynchronizingMessageSource
which requires SmbInboundFileSynchronizer
injection.
For filtering remote files you still can use any existing FileListFilter
implementations, but particular SmbRegexPatternFileListFilter
and SmbSimplePatternFileListFilter
are provided.
@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>
组件。
For XML configuration the <int-smb:inbound-channel-adapter>
component is provided.
从 6.2 版本开始,您可以使用 SmbLastModifiedFileListFilter
基于上次修改策略来筛选 SMB 文件。该筛选器可使用 age
属性进行配置,以便只有比该值更旧的文件才通过筛选器传递。年龄默认为 60 秒,但您应该选择足够大的年龄以避免提早选择文件(例如,由于网络故障)。更多信息请查看其 Javadoc。
Starting with version 6.2, you can filter SMB files based on last-modified strategy using SmbLastModifiedFileListFilter
.
This filter can be configured with an age
property so that only files older than this value are passed by the filter.
The age defaults to 60 seconds, but you should choose an age that is large enough to avoid picking up a file early (due to, say, network glitches.
Look into its Javadoc for more information.
Configuring with the Java DSL
以下 Spring Boot 应用程序展示了如何使用 Java DSL 配置入站适配器的示例:
The following Spring Boot application shows an example of how to configure the inbound adapter with the 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 Streaming Inbound Channel Adapter
此适配器生成有效负载类型为 InputStream`的消息,从而允许获取文件而不写入本地文件系统。由于会话仍然保持打开状态,因此消耗应用程序负责在文件被消耗时关闭会话。会话在 `closeableResource`标题 (`IntegrationMessageHeaderAccessor.CLOSEABLE_RESOURCE
) 中提供。诸如 FileSplitter`和 `StreamTransformer`之类的标准框架组件会自动关闭会话。请参阅 File Splitter和 Stream Transformer以获取有关这些组件的更多信息。以下示例显示如何配置 `inbound-streaming-channel-adapter
:
This adapter produces message with payloads of type InputStream
, letting files be fetched without writing to the local file system.
Since the session remains open, the consuming application is responsible for closing the session when the file has been consumed.
The session is provided in the closeableResource
header (IntegrationMessageHeaderAccessor.CLOSEABLE_RESOURCE
).
Standard framework components, such as the FileSplitter
and StreamTransformer
, automatically close the session.
See File Splitter and Stream Transformer for more information about these components.
The following example shows how to configure an 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
中的一个。
Only one of filename-pattern
, filename-regex
, filter
, or filter-expression
is allowed.
SmbStreamingMessageSource`适配器基于内存中的 `SimpleMetadataStore`防止远程文件的重复,`SmbPersistentAcceptOnceFileListFilter`基于内存中的 `SimpleMetadataStore
。默认情况下,此过滤器也适用于文件名模式(或正则表达式)。如果您需要允许重复,可以使用 AcceptAllFileListFilter
。任何其他用例都可以由 CompositeFileListFilter
(或 ChainFileListFilter
)处理。Java 配置 (later in the document) 展示了一种在处理后删除远程文件以避免重复的技术。
The SmbStreamingMessageSource
adapter prevents duplicates for remote files with SmbPersistentAcceptOnceFileListFilter
based on the in-memory SimpleMetadataStore
.
By default, this filter is also applied with the filename pattern (or regex).
If you need to allow duplicates, you can use AcceptAllFileListFilter
.
Any other use cases can be handled by CompositeFileListFilter
(or ChainFileListFilter
).
The Java configuration (later in the document) shows one technique to remove the remote file after processing to avoid duplicates.
有关 SmbPersistentAcceptOnceFileListFilter
及其如何使用方式的更多信息,请参阅 Remote Persistent File List Filters。
For more information about the SmbPersistentAcceptOnceFileListFilter
, and how it is used, see Remote Persistent File List Filters.
使用 max-fetch-size`属性来限制每次 poll 时获取的文件数量(如果需要获取)。将其设置为 `1
,并在群集环境中运行时使用持久过滤器。有关更多信息,请参阅 Inbound Channel Adapters: Controlling Remote File Fetching。
Use the max-fetch-size
attribute to limit the number of files fetched on each poll when a fetch is necessary.
Set it to 1
and use a persistent filter when running in a clustered environment.
See Inbound Channel Adapters: Controlling Remote File Fetching for more information.
适配器将远程目录和文件名分别放入 FileHeaders.REMOTE_DIRECTORY
和 FileHeaders.REMOTE_FILE
标头中。FileHeaders.REMOTE_FILE_INFO
标头提供其他远程文件信息(默认以 JSON 格式表示)。如果您将 SmbStreamingMessageSource
上的 fileInfoJson
属性设置为 false
,则标头将包含 SmbFileInfo
对象。
The adapter puts the remote directory and file name in the FileHeaders.REMOTE_DIRECTORY
and FileHeaders.REMOTE_FILE
headers, respectively.
The FileHeaders.REMOTE_FILE_INFO
header provides additional remote file information (represented in JSON by default).
If you set the fileInfoJson
property on the SmbStreamingMessageSource
to false
, the header contains an SmbFileInfo
object.
Configuring with Java Configuration
以下 Spring Boot 应用展示了如何通过 Java 配置来配置入站适配器的一个示例:
The following Spring Boot application shows an example of how to configure the inbound adapter with Java configuration:
@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;
}
}
请注意,在此示例中,转换器下游的消息处理程序有一个“建议”,可在处理后移除远程文件。
Notice that, in this example, the message handler downstream of the transformer has an advice
that removes the remote file after processing.
Inbound Channel Adapters: Controlling Remote File Fetching
在配置入站信道适配器时,您应该考虑两个属性。与所有轮询器一样,max-messages-per-poll
可用于限制每次轮询发出的消息数量(如果准备就绪的消息多于配置的值)。max-fetch-size
可以限制一次从远程服务器检索的文件数量。
There are two properties that you should consider when you configure inbound channel adapters.
max-messages-per-poll
, as with all pollers, can be used to limit the number of messages emitted on each poll (if more than the configured value are ready).
max-fetch-size
can limit the number of files retrieved from the remote server at one time.
以下场景假设起始状态是一个空本地目录:
The following scenarios assume the starting state is an empty local directory:
-
max-messages-per-poll=2
andmax-fetch-size=1
: The adapter fetches one file, emits it, fetches the next file, emits it, and then sleeps until the next poll. -
max-messages-per-poll=2
andmax-fetch-size=2
): The adapter fetches both files and then emits each one. -
max-messages-per-poll=2
andmax-fetch-size=4
: The adapter fetches up to four files (if available) and emits the first two (if there are at least two). The next two files are emitted on the next poll. -
max-messages-per-poll=2
andmax-fetch-size
not specified: The adapter fetches all remote files and emits the first two (if there are at least two). The subsequent files are emitted on subsequent polls (two at a time). When all files are consumed, the remote fetch is attempted again, to pick up any new files.
当您部署应用程序的多个实例时,我们建议使用较小的 max-fetch-size
,以避免一个实例 “grabbing” 所有文件并使其他实例匮乏。
When you deploy multiple instances of an application, we recommend a small max-fetch-size
, to avoid one instance “grabbing” all the files and starving other instances.
如果您想停止获取远程文件但继续处理已获取的文件,则 @{69} 的另一种用途是。对 @{71}(通过编程、使用 JMX 或 @{72})设置 @{70} 属性会有效阻止适配器获取更多文件,但允许轮询器继续为先前已获取的文件发出消息。如果属性更改时轮询器处于活动状态,则更改将在下次轮询中生效。
Another use for max-fetch-size
is if you want to stop fetching remote files but continue to process files that have already been fetched.
Setting the maxFetchSize
property on the MessageSource
(programmatically, with JMX, or with a control bus) effectively stops the adapter from fetching more files but lets the poller continue to emit messages for files that have previously been fetched.
If the poller is active when the property is changed, the change takes effect on the next poll.
可以向同步器提供 Comparator<SmbFile>
。在使用 maxFetchSize
限制获取的文件数量时,这很有用。
The synchronizer can be provided with a Comparator<SmbFile>
.
This is useful when restricting the number of files fetched with maxFetchSize
.
SMB Outbound Channel Adapter
对于将文件写入 SMB 共享以及 XML <int-smb:outbound-channel-adapter>
组件,我们使用 SmbMessageHandler
。在 Java 配置中,SmbMessageHandler
应与 SmbSessionFactory
(或 SmbRemoteFileTemplate
)一起提供。
For writing files to an SMB share, and for XML <int-smb:outbound-channel-adapter>
component we use the SmbMessageHandler
.
In case of Java configuration a SmbMessageHandler
should be supplied with the SmbSessionFactory
(or 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;
}
Configuring with the Java DSL
以下 Spring Boot 应用程序显示了如何使用 Java DSL 配置出站适配器的示例:
The following Spring Boot application shows an example of how to configure the outbound adapter using the 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 Outbound Gateway
SMB 出站网关提供了一组有限的命令来与远程 SMB 服务器进行交互。支持的命令包括:
The SMB outbound gateway provides a limited set of commands to interact with a remote SMB server. The supported commands are:
-
ls
(list files) -
nlst
(list file names) -
get
(retrieve file) -
mget
(retrieve file(s)) -
rm
(remove file(s)) -
mv
(move/rename file) -
put
(send file) -
mput
(send multiple files)
Using the ls
Command
ls
列出远程文件并支持以下选项:
ls
lists remote files and supports the following options:
-
-1
: Retrieve a list of filenames. The default is to retrieve a list ofFileInfo
objects -
-a
: Include all files (including those starting with '.') -
-f
: Do not sort the list -
-dirs
: Include directories (excluded by default) -
-links
: Include symbolic links (excluded by default) -
-R
: List the remote directory recursively
此外,文件名筛选以与 inbound-channel-adapter
相同的方式提供。
In addition, filename filtering is provided in the same manner as the inbound-channel-adapter
.
ls
操作产生的消息负载是一份文件名列表或 FileInfo
对象列表(取决于您是否使用 -1
开关)。这些对象提供修改时间、权限等信息。
The message payload resulting from an ls
operation is a list of file names or a list of FileInfo
objects (depending on whether you usr the -1
switch).
These objects provide information such as modified time, permissions, and others.
ls
命令操作的远程目录在 file_remoteDirectory
标头中提供。
The remote directory that the ls
command acted on is provided in the file_remoteDirectory
header.
使用递归选项 (-R
) 时,fileName
包括任何子目录元素,并表示文件相对于远程目录的相对路径。如果您使用 -dirs
选项,每个递归目录也会作为列表中的元素返回。在这种情况下,我们建议您不要使用 -1
选项,因为您无法像使用 FileInfo
对象那样区分文件与目录。
When using the recursive option (-R
), the fileName
includes any subdirectory elements and represents the relative path to the file (relative to the remote directory).
If you use the -dirs
option, each recursive directory is also returned as an element in the list.
In this case, we recommend that you not use the -1
option, because you would not be able to distinguish files from directories, which you can do when you use FileInfo
objects.
Using nlst
Command
nlst
列出远程文件名并仅支持一个选项:
nlst
lists remote file names and supports only one option:
-
-f
: Do not sort the list
nlst
操作返回的消息有效负载是一个文件名列表。
The message payload resulting from an nlst
operation is a list of file names.
file_remoteDirectory
标头包含 nlst
命令对其执行操作的远程目录。
The file_remoteDirectory
header holds the remote directory on which the nlst
command acted.
Using the get
Command
get
检索远程文件并支持以下选项:
get
retrieves a remote file and supports the following options:
-
-P
: Preserve the timestamp of the remote file. -
-stream
: Retrieve the remote file as a stream. -
-D
: Delete the remote file after successful transfer. The remote file is not deleted if the transfer is ignored, because theFileExistsMode
isIGNORE
and the local file already exists.
file_remoteDirectory
标头包含远程目录,file_remoteFile
标头包含文件名。
The file_remoteDirectory
header holds the remote directory, and the file_remoteFile
header holds the filename.
由`get`操作产生的消息有效负载是一个表示已检索文件的`File`对象。如果您使用`-stream`选项,则有效负载将是`InputStream`,而不是`File`。对于文本文件,一种常见用例是将此操作与file splitter或stream transformer结合使用。在将远程文件作为流使用时,您应负责在使用流后关闭`Session`。为方便起见,`Session`在`closeableResource`标头中提供,而`IntegrationMessageHeaderAccessor`提供便利方法:
The message payload resulting from a get
operation is a File
object representing the retrieved file.
If you use the -stream
option, the payload is an InputStream
rather than a File
.
For text files, a common use case is to combine this operation with a file splitter or a stream transformer.
When consuming remote files as streams, you are responsible for closing the Session
after the stream is consumed.
For convenience, the Session
is provided in the closeableResource
header, and IntegrationMessageHeaderAccessor
offers convenience method:
Closeable closeable = new IntegrationMessageHeaderAccessor(message).getCloseableResource();
if (closeable != null) {
closeable.close();
}
框架组件(如File Splitter和Stream Transformer)在数据传输后自动关闭会话。
Framework components, such as the File Splitter and Stream Transformer, automatically close the session after the data is transferred.
以下示例显示了如何将文件作为流使用:
The following example shows how to consume a file as a stream:
<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" />
如果您在自定义组件中消耗输入流,那么必须关闭 |
If you consume the input stream in a custom component, you must close the |
<int:service-activator input-channel="closeSession"
expression="headers['closeableResource'].close()" />
Using the mget
Command
mget
根据模式检索多个远程文件,并支持以下选项:
mget
retrieves multiple remote files based on a pattern and supports the following options:
-
-P
: Preserve the timestamps of the remote files. -
-R
: Retrieve the entire directory tree recursively. -
-x
: Throw an exception if no files match the pattern (otherwise, an empty list is returned). -
-D
: Delete each remote file after successful transfer. If the transfer is ignored, the remote file is not deleted, because theFileExistsMode
isIGNORE
and the local file already exists.
mget
操作产生的消息有效负载是一个 List<File>
对象(即,一个 File
对象的 List
,每个文件都表示一个已检索的文件)。
The message payload resulting from an mget
operation is a List<File>
object (that is, a List
of File
objects, each representing a retrieved file).
如果 FileExistsMode
为 IGNORE
,则输出消息的有效载荷不再包含由于文件已存在而未提取的文件。以前,该数组包含所有文件,包括已存在的文件。
If the FileExistsMode
is IGNORE
, the payload of the output message no longer contain files that were not fetched due to the file already existing.
Previously, the array contained all files, including those that already existed.
您用来确定远程路径的表达式应产生一个以 结尾的结果,例如
myfiles/
获取 myfiles
下的完整树。
The expression you use determine the remote path should produce a result that ends with for example
myfiles/
fetches the complete tree under myfiles
.
您可以结合 FileExistsMode.REPLACE_IF_MODIFIED
模式使用递归 MGET
,来定期在本地同步整个远程目录树。此模式将本地文件的上次修改时间戳设置为远程文件的上次修改时间戳,无论 -P
(保留时间戳)选项如何设置。
You can use a recursive MGET
, combined with the FileExistsMode.REPLACE_IF_MODIFIED
mode, to periodically synchronize an entire remote directory tree locally.
This mode sets the local file’s last modified timestamp to the remote file’s timestamp, regardless of the -P
(preserve timestamp) option.
-R
)模式会被忽略,而假定为 *
。默认情况下,将检索整个远程树。但是,您可以通过提供 FileListFilter
来筛选树中的文件。您还可以通过此方式筛选树中的目录。可以通过引用或 filename-pattern
或 filename-regex
属性来提供 FileListFilter
。例如,filename-regex="(subDir|.*1.txt)"
检索远程目录中所有以 1.txt
结尾的文件和子目录 subDir
。但是,我们将在本注释之后描述另一种可用的替代方案。
The pattern is ignored and *
is assumed.
By default, the entire remote tree is retrieved.
However, you can filter files in the tree by providing a FileListFilter
.
You can also filter directories in the tree this way.
A FileListFilter
can be provided by reference or by filename-pattern
or filename-regex
attributes.
For example, filename-regex="(subDir|.*1.txt)"
retrieves all files ending with 1.txt
in the remote directory and the subdirectory subDir
.
However, we describe an alternative available after this note.
如果您筛选一个子目录,则不会对该子目录执行任何其他遍历。
If you filter a subdirectory, no additional traversal of that subdirectory is performed.
不允许 -dirs
选项(递归 mget
使用递归 ls
获得目录树,而目录本身不能包含在列表中)。
The -dirs
option is not allowed (the recursive mget
uses the recursive ls
to obtain the directory tree and the directories themselves cannot be included in the list).
通常,您会在 local-directory-expression
中使用 #remoteDirectory
变量,以便在本地保留远程目录结构。
Typically, you would use the #remoteDirectory
variable in the local-directory-expression
so that the remote directory structure is retained locally.
持久的过滤文件列表现在有一个布尔属性 forRecursion
。将此属性设置为 true
,还将设置 alwaysAcceptDirectories
,这意味着出站网关(ls
和 mget
)上的递归操作现在将始终在每次遍历完整目录树。这是为了解决目录树中深处更改未被检测到的问题。此外,forRecursion=true
会导致使用文件的完整路径作为元数据存储键;这解决了在不同目录中多次出现具有相同名称的文件时过滤器无法正常工作的问题。重要提示:这意味着无法在顶级目录下的文件找到持久元数据存储中的现有键。因此,该属性默认为 false
;这可能会在未来版本中更改。
The persistent file list filters now have a boolean property forRecursion
.
Setting this property to true
, also sets alwaysAcceptDirectories
, which means that the recursive operation on the outbound gateways (ls
and mget
) will now always traverse the full directory tree each time.
This is to solve a problem where changes deep in the directory tree were not detected.
In addition, forRecursion=true
causes the full path to files to be used as the metadata store keys; this solves a problem where the filter did not work properly if a file with the same name appears multiple times in different directories.
IMPORTANT: This means that existing keys in a persistent metadata store will not be found for files beneath the top level directory.
For this reason, the property is false
by default; this may change in a future release.
您可以配置 SmbSimplePatternFileListFilter
和 SmbRegexPatternFileListFilter
,通过将 alwaysAcceptDirectories
设置为 true
来始终传递目录。这样做允许对简单模式进行递归,如下例所示:
You can configure the SmbSimplePatternFileListFilter
and SmbRegexPatternFileListFilter
to always pass directories by setting the alwaysAcceptDirectorties
to true
.
Doing so allows recursion for a simple pattern, as the following examples show:
<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
属性提供其中一个过滤器。
You can provide one of these filters by using the filter
property on the gateway.
另请参阅 xref:smb.adoc#smb-partial[Outbound Gateway Partial Success (mget
和 mput
)。
Using the put
Command
put`将文件发送到远程服务器。消息的有效负载可以是`java.io.File
、byte[]`或`String
。remote-filename-generator
(或表达式)用于命名远程文件。其他可用的属性包括`remote-directory`、temporary-remote-directory`及其
*-expression`等价物:use-temporary-file-name`和`auto-create-directory
。有关更多信息,请参阅 schema documentation。
put
sends a file to the remote server.
The payload of the message can be a java.io.File
, a byte[]
, or a String
.
A remote-filename-generator
(or expression) is used to name the remote file.
Other available attributes include remote-directory
, temporary-remote-directory
and their *-expression
equivalents: use-temporary-file-name
and auto-create-directory
.
See the schema documentation for more information.
put
操作产生的消息有效负载是一个 String
,其中包含文件在服务器上的完整路径,以便在传输后使用。
The message payload resulting from a put
operation is a String
that contains the full path of the file on the server after transfer.
Using the mput
Command
mput
将多个文件发送到服务器,并支持以下选项:
mput
sends multiple files to the server and supports the following option:
-
-R
: Recursive — send all files (possibly filtered) in the directory and subdirectories
消息有效负载必须是一个表示本地目录的 java.io.File
(或 String
)。还支持 File
或 String
的集合。
The message payload must be a java.io.File
(or String
) that represents a local directory.
A collection of File
or String
is also supported.
支持与put
command相同的属性。此外,您还可以使用`mput-pattern`、mput-regex
、`mput-filter`或`mput-filter-expression`中的一个属性过滤本地目录中的文件。只要子目录本身通过筛选,该筛选器就会与递归一起使用。未通过筛选的子目录不会被递归。
The same attributes as the put
command are supported.
In addition, you can filter files in the local directory with one of mput-pattern
, mput-regex
, mput-filter
, or mput-filter-expression
.
The filter works with recursion, as long as the subdirectories themselves pass the filter.
Subdirectories that do not pass the filter are not recursed.
mput
操作产生的消息有效负载是一个 List<String>
对象(即,传输产生的远程文件路径的一个 List
)。
The message payload resulting from an mput
operation is a List<String>
object (that is, a List
of remote file paths resulting from the transfer).
另请参阅 xref:smb.adoc#smb-partial[Outbound Gateway Partial Success (mget
和 mput
)。
Using the rm
Command
rm
命令没有选项。
The rm
command has no options.
如果删除操作成功,则产生的消息有效负载为 Boolean.TRUE
。否则,消息有效负载为 Boolean.FALSE
。file_remoteDirectory
标头包含远程目录,file_remoteFile
标头包含文件名。
If the remove operation was successful, the resulting message payload is Boolean.TRUE
.
Otherwise, the message payload is Boolean.FALSE
.
The file_remoteDirectory
header holds the remote directory, and the file_remoteFile
header holds the file name.
Using the mv
Command
mv
命令没有选项。
The mv
command has no options.
expression
属性定义 “from” 路径,而 rename-expression
属性定义 “to” 路径。默认情况下,rename-expression
为 headers['file_renameTo']
。此表达式不得计算为 null 或空 String
。如有必要,将创建任何需要的远程目录。结果消息的有效内容是 Boolean.TRUE
。file_remoteDirectory
标题保存原始远程目录,而 file_remoteFile
标题保存文件名。file_renameTo
标题保存新路径。
The expression
attribute defines the “from” path, and the rename-expression
attribute defines the “to” path.
By default, the rename-expression
is headers['file_renameTo']
.
This expression must not evaluate to null or an empty String
.
If necessary, any remote directories needed are created.
The payload of the result message is Boolean.TRUE
.
The file_remoteDirectory
header holds the original remote directory, and the file_remoteFile
header holds the filename.
The file_renameTo
header holds the new path.
remoteDirectoryExpression
可以方便地在 mv
命令中使用。如果“from
”文件不是完整的文件路径,则 remoteDirectoryExpression
的结果用作远程目录。对于“to
”文件来说也是如此,例如,如果任务只是重命名某个目录中的远程文件。
The remoteDirectoryExpression
can be used in the mv
command for convenience.
If the “from” file is not a full file path, the result of remoteDirectoryExpression
is used as the remote directory.
The same applies for the “to” file, for example, if the task is just to rename a remote file in some directory.
Additional Command Information
get
和 mget
命令支持 local-filename-generator-expression
属性。它定义了一个 SpEL 表达式,以便在传输期间生成本地文件的名称。评估上下文的根对象是请求消息。还可以使用 remoteFileName
变量。对于 mget
来说特别有用(例如:local-filename-generator-expression="#remoteFileName.toUpperCase() + headers.foo"
)。
The get
and mget
commands support the local-filename-generator-expression
attribute.
It defines a SpEL expression to generate the names of local files during the transfer.
The root object of the evaluation context is the request message.
The remoteFileName
variable is also available.
It is particularly useful for mget
(for example: 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
属性互斥。
The get
and mget
commands support the local-directory-expression
attribute.
It defines a SpEL expression to generate the names of local directories during the transfer.
The root object of the evaluation context is the request message.
The remoteDirectory
variable is also available.
It is particularly useful for mget (for example: local-directory-expression="'/tmp/local/' + #remoteDirectory.toUpperCase() + headers.myheader"
).
This attribute is mutually exclusive with the local-directory
attribute.
对于所有命令,网关的“expression
”属性都保存了命令作用于其上的路径。对于 mget
命令,表达式可能计算为 ,这意味着要检索所有文件,
somedirectory/
和以 *
结尾的其他值。
For all commands, the 'expression' property of the gateway holds the path on which the command acts.
For the mget
command, the expression might evaluate to , meaning to retrieve all files,
somedirectory/
, and other values that end with *
.
以下示例显示了为 ls
命令配置的网关:
The following example shows a gateway configured for an ls
command:
<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"
)。
The payload of the message sent to the toSplitter
channel is a list of String
objects, each of which contains the name of a file.
If you omitted command-options="-1"
, the payload would be a list of FileInfo
objects.
You can provide options as a space-delimited list (for example, 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
。
The GET
, MGET
, PUT
, and MPUT
commands support a FileExistsMode
property (mode
when using the namespace support).
This affects the behavior when the local file exists (GET
and MGET
) or the remote file exists (PUT
and MPUT
).
The supported modes are REPLACE
, APPEND
, FAIL
, and IGNORE
.
For backwards compatibility, the default mode for PUT
and MPUT
operations is REPLACE
.
For GET
and MGET
operations, the default is FAIL
.
Configuring with Java Configuration
以下 Spring Boot 应用程序显示了如何使用 Java 配置配置出站网关的一个示例:
The following Spring Boot application shows an example of how to configure the outbound gateway with Java configuration:
@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;
}
}
Configuring with the Java DSL
以下 Spring Boot 应用程序显示了一个示例,演示如何使用 Java DSL 配置出站网关:
The following Spring Boot application shows an example of how to configure the outbound gateway with the 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"));
}
}
Outbound Gateway Partial Success (mget
and mput
)
当对多个文件执行操作(通过使用 mget
和 mput
)时,在传输了一个或多个文件之后,可能会发生异常。在这种情况下,将抛出一个 PartialSuccessException
。除了通常的 MessagingException
属性(failedMessage
和 cause
)之外,此异常还有两个附加属性:
When performing operations on multiple files (by using mget
and mput
) an exception can occur some time after one or more files have been transferred.
In this case a PartialSuccessException
is thrown.
As well as the usual MessagingException
properties (failedMessage
and cause
), this exception has two additional properties:
-
partialResults
: The successful transfer results. -
derivedInput
: The list of files generated from the request message (such as local files to transfer for anmput
).
这些属性使您可以确定哪些文件已成功传输,哪些文件尚未传输。
These attributes let you determine which files were successfully transferred and which were not.
在递归 mput
的情况下,PartialSuccessException
可能有嵌套的 PartialSuccessException
实例。
In the case of a recursive mput
, the PartialSuccessException
may have nested PartialSuccessException
instances.
考虑以下目录结构:
Consider the following directory structure:
root/
|- file1.txt
|- subdir/
| - file2.txt
| - file3.txt
|- zoo.txt
如果异常发生在 file3.txt
上,则网关引发的 PartialSuccessException
具有 file1.txt
、subdir
和 zoo.txt
的 derivedInput
,以及 file1.txt
的 partialResults
。其 cause
是另一个具有 file2.txt
和 file3.txt
的 derivedInput
和 file2.txt
的 partialResults
的 PartialSuccessException
。
If the exception occurs on file3.txt
, the PartialSuccessException
thrown by the gateway has derivedInput
of file1.txt
, subdir
, and zoo.txt
and partialResults
of file1.txt
.
Its cause
is another PartialSuccessException
with derivedInput
of file2.txt
and file3.txt
and partialResults
of file2.txt
.
Remote File Information
SmbStreamingMessageSource
(SMB Streaming Inbound Channel Adapter)、SmbInboundFileSynchronizingMessageSource
(SMB Inbound Channel Adapter)和`SmbOutboundGateway`(SMB Outbound Gateway)的“read”-command 在消息中提供附加标头以生成有关远程文件的信息:
The SmbStreamingMessageSource
(SMB Streaming Inbound Channel Adapter), SmbInboundFileSynchronizingMessageSource
(SMB Inbound Channel Adapter) and "read"-commands of the SmbOutboundGateway
(SMB Outbound Gateway) provide additional headers in the message to produce with an information about the remote file:
-
FileHeaders.REMOTE_HOST_PORT
- the host:port pair the remote session has been connected to during file transfer operation; -
FileHeaders.REMOTE_DIRECTORY
- the remote directory the operation has been performed; -
FileHeaders.REMOTE_FILE
- the remote file name; applicable only for single file operations.
由于 SmbInboundFileSynchronizingMessageSource
不会针对远程文件生成消息,而是使用本地副本,因此 AbstractInboundFileSynchronizer
在同步操作期间以 URI 样式(protocol://host:port/remoteDirectory#remoteFileName
)将有关远程文件的信息存储在 MetadataStore
(可以在外部配置)中。当轮询本地文件时,SmbInboundFileSynchronizingMessageSource
会检索此元数据。当本地文件被删除时,建议删除其元数据条目。AbstractInboundFileSynchronizer
为此提供了一个 removeRemoteFileMetadata()
回调。此外,还有一个 setMetadataStorePrefix()
要用于元数据键中。当这些组件在相同的 MetadataStore
实例之间共享时,建议此前缀不同于 MetadataStore
为基础的 FileListFilter
实现中所使用的前缀,以避免条目覆盖,因为筛选器和 AbstractInboundFileSynchronizer
为元数据条目键使用相同的本地文件名称。
Since the SmbInboundFileSynchronizingMessageSource
doesn’t produce messages against remote files, but using a local copy, the AbstractInboundFileSynchronizer
stores an information about remote file in the MetadataStore
(which can be configured externally) in the URI style (protocol://host:port/remoteDirectory#remoteFileName
) during synchronization operation.
This metadata is retrieved by the SmbInboundFileSynchronizingMessageSource
when local file is polled.
When local file is deleted, it is recommended to remove its metadata entry.
The AbstractInboundFileSynchronizer
provides a removeRemoteFileMetadata()
callback for this purpose.
In addition, there is a setMetadataStorePrefix()
to be used in the metadata keys.
It is recommended to have this prefix be different from the one used in the MetadataStore
-based FileListFilter
implementations, when the same MetadataStore
instance is shared between these components, to avoid entry overriding because both filter and AbstractInboundFileSynchronizer
use the same local file name for the metadata entry key.