2

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

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

在下面的代码中,我在 int-sftp:inbound-channel-adapter 中设置了 filename-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();

已使用此链接作为我的参考 - 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:\Users\503017993\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");
4

1 回答 1

2

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

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

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

有关详细信息,请参阅参考手册。您在问题中提到的示例也带来了一些网关片段。

于 2018-01-30T14:13:11.997 回答