是否可以动态更改入站通道适配器的文件名正则表达式

Is it possible to dynamically change the filename-regex of inbound-channel-adapter

在我们的应用程序中,有大量文件从远程计算机下载到本地计算机(代码为 运行 的服务器)。我们选择使用 Spring SFTP 进行下载。我们仍处于开发过程中。

当用户选择文件并单击 UI 中的按钮下载该文件时,下载过程将启动。多个用户可能同时选择不同的文件并将它们从远程计算机下载到本地计算机(代码为 运行 的服务器)。远程机器(以及下载发生的路径)和本地机器(以及文件下载的路径)对于所有下载请求都是相同的,只是文件名不同。

在我下面的代码中,我在 int-sftp:inbound-channel-adapter 中设置文件名正则表达式。问题是文件名正则表达式是静态的。我需要动态设置文件名正则表达式。因为每个用户将下载不同的文件。我不能在 filename-regex 中使用 regex,因为只需要下载选定的文件。

是否可以动态设置。我必须对我的代码做哪些更改才能做到这一点。欢迎所有建议。提前致谢。

<bean id="sftpSessionFactory" class="org.springframework.integration.file.remote.session.CachingSessionFactory">
    <constructor-arg ref="defaultSftpSessionFactory" />
</bean>

<bean id="defaultSftpSessionFactory"
      class="org.springframework.integration.sftp.session.DefaultSftpSessionFactory">
    <property name="host" value="${sftp.host}"/>
    <property name="privateKey" value="${sftp.private.keyfile}"/>
    <property name="privateKeyPassphrase" value="${sftp.passphrase}"/>
    <property name="port" value="${sftp.port}"/>
    <property name="user" value="${sftp.username}"/>
    <property name="allowUnknownKeys" value="true"/>
</bean>

<bean class="com.rizwan.test.sftp_inbound_channel_adapter.EmbeddedSftpServer">
    <property name="port" value="${sftp.port}"/>
    <property name="defaultSftpSessionFactory" ref="defaultSftpSessionFactory"/>
</bean>

<int-sftp:inbound-channel-adapter id="sftpInbondAdapter"
        auto-startup="false"
        channel="receiveChannel"
        session-factory="sftpSessionFactory"
        local-directory="file:local-dir"
        remote-directory="si.sftp.sample"
        auto-create-local-directory="true"
        delete-remote-files="false"
        filename-regex="a.txt">
    <int:poller fixed-rate="0" max-messages-per-poll="-1"/>
</int-sftp:inbound-channel-adapter>

<int:channel id="receiveChannel">
    <int:queue/>
</int:channel>

下面是我在 main 方法中的 java 代码。

PollableChannel localFileChannel = context.getBean("receiveChannel", PollableChannel.class);
SourcePollingChannelAdapter adapter = context.getBean(SourcePollingChannelAdapter.class);
adapter.start();
adapter.stop();
Message<?> received = localFileChannel.receive();

已使用此 link 作为我的参考 - https://github.com/spring-projects/spring-integration-samples/tree/master/basic/sftp


根据 Artem Bilan 给出的答案发布配置以使其工作。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:int-sftp="http://www.springframework.org/schema/integration/sftp"
xsi:schemaLocation="http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/integration/sftp http://www.springframework.org/schema/integration/sftp/spring-integration-sftp.xsd">

<import resource="SftpSampleCommon.xml"/>

<int:gateway id="gw" service-interface="com.rizwan.test.sftp_outbound_gateway.ToSftpFlowGateway"
    default-request-channel="toGet"/>

<int-sftp:outbound-gateway id="gatewayGET"
    local-directory="C:\Users3017993\Perforce\rizwan.shaikh1_G7LGTPC2E_7419\NGI\DEV\Jetstream_Branches\C360_Falcon2_1_Main\sftp-outbound-gateway"
    session-factory="sftpSessionFactory"
    request-channel="toGet"
    remote-directory="/si.sftp.sample"
    command="get"
    command-options="-P"
    expression="payload">
    <int-sftp:request-handler-advice-chain>
        <int:retry-advice />
    </int-sftp:request-handler-advice-chain>
</int-sftp:outbound-gateway>
</beans>

Java代码:

ConfigurableApplicationContext ctx = new ClassPathXmlApplicationContext(
            "classpath:/META-INF/spring-context.xml");
DownloadRemoteFileGateway downloadGateway = ctx.getBean(DownloadRemoteFileGateway.class);
String downloadedFilePath = downloadGateway.downloadRemoteFile("si.sftp.sample/2ftptest");

你所追求的方法是完全错误的。您没有考虑不同用户对组件的并发访问。现在让我们想象一下,我们将能够从最终用户的角度更改 filename-regex。其中之一想要下载 his/her 自己的文件,因此 he/she 设置了适当的模式并调用 adapter.start()。同时另一个用户想要下载 his/her 文件。瞧 - 我们有一个竞争条件,因为当组件在用户范围内不起作用时,您正在同时更改组件的状态。 SourcePollingChannelAdapter 的性质是 活跃 。一旦启动它,后台计划任务将旋转此组件直到停止。

解决方案中的另一个瓶颈是对 PollableChannel 的访问。让我们想象一下,我们可以使 SourcePollingChannelAdapter 在用户上下文中工作,并且我们没有任何并发​​突变和竞争条件。但是,当此组件下载文件时,它会将消息发送到 PollableChannel。是否保证一个用户不会从这个队列中为另一个用户提取文件?..

您的解决方案需要的应该是被动的和无状态的。这确实必须由最终用户和 return 在同一个线程中的一些答案发起。为此,您应该查看 <int-sftp:outbound-gateway> 及其 getmget 命令。正是这个人能够从您发送的 Message 中获取文件 name/pattern,从 SFTP 下载它并 return 将其发送给调用者。您可以将 @MessagingGateway 放在该 SFTP 网关的前面,并且只需要来自 MVC 控制器的纯 Java 代码。

有关详细信息,请参阅 Reference Manual。您在问题中提到的示例也带来了一些网关代码段。