【问题标题】:How to configure spring integration adapters to get and put a file via SFTP如何配置 Spring 集成适配器以通过 SFTP 获取和放置文件
【发布时间】:2020-08-07 00:17:44
【问题描述】:

我正在尝试使用 Spring Integration 实现以下场景:

输入通道应轮询 SFTP 站点以获取将其存储在本地“stfp-inbound”文件夹中的文件。 输出通道应将本地“sftp-outbound”文件夹中的现有文件推送到 SFTP 站点。 我从输入通道开始。到目前为止它一直有效,但它显然是非常静态的。

这是我目前的配置:

@Component
public class SftpClient {
    private static final Logger LOG = LoggerFactory.getLogger(SftpClient.class);

@Bean
public IntegrationFlow sftpInboundFlow() {
    return IntegrationFlows
        .from(Sftp.inboundAdapter(sftpSessionFactory())
                .preserveTimestamp(true)
                .remoteDirectory("data")
                .regexFilter(".*\\.txt$")
//                    .localFilenameExpression("#this.toUpperCase() + '.a'")
                .localDirectory(new File("ftp-inbound")),
             e -> e.id("sftpInboundAdapter")
                .autoStartup(true)
                .poller(Pollers.fixedDelay(5000)))
        .handle(m -> System.out.println(m.getPayload()))
        .get();
}

@Bean
public IntegrationFlow sftpOutboundFlow() {
    return IntegrationFlows.from("toSftpChannel")
        .handle(Sftp.outboundAdapter(sftpSessionFactory(), FileExistsMode.FAIL)
                     .useTemporaryFileName(false)
                     .remoteDirectory("/data")
        ).get();
}

@Bean
public SessionFactory<LsEntry> sftpSessionFactory() {
//      // with private key resource: catch MalformedURLException
//      try {
        DefaultSftpSessionFactory factory = new DefaultSftpSessionFactory(true);
        factory.setHost("myHost");
        factory.setPort(22);
        factory.setUser("myUser");
        factory.setPassword("myPassword");
//          factory.setPrivateKey(new FileUrlResource("/Users/myUser/.ssh/id_rsa"));
//          factory.setPrivateKeyPassphrase("passphrase");
        factory.setAllowUnknownKeys(true);
        return new CachingSessionFactory<LsEntry>(factory);
//      }
//      catch (MalformedURLException e) {
//          throw new IllegalArgumentException("malformed URL");
//      }
}

我需要建议来制定更动态的方法。 我想象一个带有公共方法 sftpGet()sftpPut() 的组件类来获取和放置文件,而通道是由集成流创建的,具有所需的参数进行 SFTP 传输:主机名、端口、用户、密码、远程目录、本地目录。

我怎样才能做到这一点?

我在类似的 TCP/IP 通道场景中得到了很好的提示,但我无法将这些解决方案转换为这种 SFTP 场景。

请指教!

在接受了 Gary 的建议后,我做了一个愚蠢的动态 Bean:

@Component
public class DynamicSftpTemplate implements InputStreamCallback {
    private static Logger LOG = LoggerFactory.getLogger(DynamicSftpTemplate.class);

    private String localDir;
    private String localFilename;

    public void getSftpFile(String sessionId, String host, int port, String user, String password,
            String remoteDir, String remoteFilename, String localDir, String localFilename) {
        LOG.debug("getSftpFile sessionId={}", sessionId);
        ioSftpFile(GET, host, port, user, password,
                remoteDir, remoteFilename, localDir, localFilename);
    }

    public void putSftpFile(String sessionId, String host, int port, String user, String password,
            String remoteDir, String remoteFilename, String localDir, String localFilename) {
        LOG.debug("putSftpFile sessionId={}", sessionId);
        ioSftpFile(PUT, host, port, user, password,
                remoteDir, remoteFilename, localDir, localFilename);
    }

    public void rmSftpFile(String sessionId, String host, int port, String user, String password,
            String remoteDir, String remoteFilename) {
        LOG.debug("rmSftpFile sessionId={}", sessionId);
        ioSftpFile(RM, host, port, user, password, remoteDir, remoteFilename, null, null);
    }

    private void ioSftpFile(SftpOperationType op, String host, int port, String user, String password,
            String remoteDir, String remoteFilename, String localDir, String localFilename) {
        LOG.debug("ioSftpFile op={}, host={}, port={}", op, host, port);
        LOG.debug("ioSftpFile user={}, password={}", user, password);
        SftpRemoteFileTemplate template = new SftpRemoteFileTemplate(sftpSessionFactory(host, port, user, password));
        template.setFileNameExpression(new LiteralExpression(remoteDir + "/" + remoteFilename));
        template.setRemoteDirectoryExpression(new LiteralExpression(remoteDir));

        //template.afterPropertiesSet();
        this.localDir = localDir;
        this.localFilename = localFilename;
        if (op == GET) {
            // template.get(buildGetMessage(remoteDir, remoteFilename), (InputStreamCallback) this);
            template.get(remoteDir + "/" + remoteFilename, this);
        }
        else if (op == PUT) {
            template.send(buildPutMessage(remoteDir, remoteFilename), FileExistsMode.REPLACE);          
        }
        else if (op == RM) {
            template.remove(remoteDir + "/" + remoteFilename);          
        }
        else {
            throw new IllegalArgumentException("invalid sftp operation, " + op);
        }
    }

    private DefaultSftpSessionFactory sftpSessionFactory(String host, int port, String user, String password) {
        LOG.debug("sftpSessionFactory");
        DefaultSftpSessionFactory factory = new DefaultSftpSessionFactory(true);
        factory.setHost(host);
        factory.setPort(port);
        factory.setUser(user);
        factory.setPassword(password);
        factory.setAllowUnknownKeys(true);
        return factory;
    }

    private Message<?> buildPutMessage(String remoteDir, String remoteFilename) {
        return MessageBuilder.withPayload(new File(this.localDir + "/" + this.localFilename))
                .setHeader("file_remoteDirectory", remoteDir)
                .setHeader("file_remoteFile", remoteFilename)
                .build();
    }

    public void doWithInputStream(InputStream is) throws IOException {
        LOG.debug("doWithInputStream");
        String fullPathName = this.localDir + "/" + this.localFilename;
        FileWriter w = new FileWriter(fullPathName);
        IOUtils.copy(is, w, "UTF-8");
        LOG.debug("doWithInputStream file {} written", fullPathName);
        w.close();
        is.close();
    }
}

【问题讨论】:

    标签: java spring-integration sftp spring-integration-dsl


    【解决方案1】:

    您可以使用SFTP Gateways 获取和放置文件(以及其他操作)。

    或者,您可以直接使用SftpRemoteFileTemplate

    【讨论】:

    • 我该怎么做?任何地方都有代码示例吗?所以你不会用 IntegrationFlow 来做?
    • 您可以使用IntegrationFlows中的网关;这里有一些在 SO 上使用模板的示例,但只需查看它的 java 文档;这很简单。
    • 非常感谢,加里!我发现了几个由 Spring Injektion 配置的示例,可以说是静态的。我正在寻找一个在运行时配置 SFTP 通道的示例,此时需要接收文件。
    • dynamic ftp sample。它使用 xml 配置,但同样的技术可以应用于 DSL。请参阅dynamic TCP sample 了解相关示例。
    • 我为您的 cmets 努力工作。我不同意将 Java Docs 视为直截了当的东西。但无论如何,加里,请你看看我在帖子中更新的代码。无论如何,它接近你所指示的吗?
    猜你喜欢
    • 1970-01-01
    • 2023-03-19
    • 1970-01-01
    • 1970-01-01
    • 2010-12-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多