如何配置Spring集成适配器以通过SFTP获取和放置文件。

huangapple go评论108阅读模式
英文:

How to configure spring integration adapters to get and put a file via SFTP

问题

以下是翻译的内容:

  1. 我正在尝试使用Spring Integration来实现以下情景:
  2. 输入通道应该轮询SFTP站点以获取文件,并将其存储在本地的“sftp-inbound”文件夹中。
  3. 输出通道应该将本地“sftp-outbound”文件夹中的现有文件推送到SFTP站点。
  4. 我首先处理了输入通道。到目前为止,它已经工作,但显然非常静态。
  5. 这是我的当前配置:
  6. @Component
  7. public class SftpClient {
  8. private static final Logger LOG = LoggerFactory.getLogger(SftpClient.class);
  9. @Bean
  10. public IntegrationFlow sftpInboundFlow() {
  11. return IntegrationFlows
  12. .from(Sftp.inboundAdapter(sftpSessionFactory())
  13. .preserveTimestamp(true)
  14. .remoteDirectory("data")
  15. .regexFilter(".*\\.txt$")
  16. .localDirectory(new File("ftp-inbound")),
  17. e -> e.id("sftpInboundAdapter")
  18. .autoStartup(true)
  19. .poller(Pollers.fixedDelay(5000)))
  20. .handle(m -> System.out.println(m.getPayload()))
  21. .get();
  22. }
  23. @Bean
  24. public IntegrationFlow sftpOutboundFlow() {
  25. return IntegrationFlows.from("toSftpChannel")
  26. .handle(Sftp.outboundAdapter(sftpSessionFactory(), FileExistsMode.FAIL)
  27. .useTemporaryFileName(false)
  28. .remoteDirectory("/data")
  29. ).get();
  30. }
  31. @Bean
  32. public SessionFactory<LsEntry> sftpSessionFactory() {
  33. DefaultSftpSessionFactory factory = new DefaultSftpSessionFactory(true);
  34. factory.setHost("myHost");
  35. factory.setPort(22);
  36. factory.setUser("myUser");
  37. factory.setPassword("myPassword");
  38. factory.setAllowUnknownKeys(true);
  39. return new CachingSessionFactory<LsEntry>(factory);
  40. }
  41. }
  42. 我需要建议以实现更加动态的方法。我想象一个组件类,具有公共方法sftpGet()和sftpPut()来获取和放置文件,而通道则由具有构成SFTP传输所需参数的集成流创建:主机名、端口、用户、密码、远程目录、本地目录。
  43. 我该如何实现这一点?
  44. 我从一个类似的TCP/IP通道情景中得到了一个好的提示,但我无法将这些解决方案转化为这个SFTP情景。
  45. 请提供建议!
  46. 在接受Gary的建议后,我创建了以下动态Bean
  47. @Component
  48. public class DynamicSftpTemplate implements InputStreamCallback {
  49. private static Logger LOG = LoggerFactory.getLogger(DynamicSftpTemplate.class);
  50. private String localDir;
  51. private String localFilename;
  52. public void getSftpFile(String sessionId, String host, int port, String user, String password,
  53. String remoteDir, String remoteFilename, String localDir, String localFilename) {
  54. LOG.debug("getSftpFile sessionId={}", sessionId);
  55. ioSftpFile(GET, host, port, user, password,
  56. remoteDir, remoteFilename, localDir, localFilename);
  57. }
  58. public void putSftpFile(String sessionId, String host, int port, String user, String password,
  59. String remoteDir, String remoteFilename, String localDir, String localFilename) {
  60. LOG.debug("putSftpFile sessionId={}", sessionId);
  61. ioSftpFile(PUT, host, port, user, password,
  62. remoteDir, remoteFilename, localDir, localFilename);
  63. }
  64. public void rmSftpFile(String sessionId, String host, int port, String user, String password,
  65. String remoteDir, String remoteFilename) {
  66. LOG.debug("rmSftpFile sessionId={}", sessionId);
  67. ioSftpFile(RM, host, port, user, password, remoteDir, remoteFilename, null, null);
  68. }
  69. private void ioSftpFile(SftpOperationType op, String host, int port, String user, String password,
  70. String remoteDir, String remoteFilename, String localDir, String localFilename) {
  71. LOG.debug("ioSftpFile op={}, host={}, port={}", op, host, port);
  72. LOG.debug("ioSftpFile user={}, password={}", user, password);
  73. SftpRemoteFileTemplate template = new SftpRemoteFileTemplate(sftpSessionFactory(host, port, user, password));
  74. template.setFileNameExpression(new LiteralExpression(remoteDir + "/" + remoteFilename));
  75. template.setRemoteDirectoryExpression(new LiteralExpression(remoteDir));
  76. this.localDir = localDir;
  77. this.localFilename = localFilename;
  78. if (op == GET) {
  79. template.get(remoteDir + "/" + remoteFilename, this);
  80. }
  81. else if (op == PUT) {
  82. template.send(buildPutMessage(remoteDir, remoteFilename), FileExistsMode.REPLACE);
  83. }
  84. else if (op == RM) {
  85. template.remove(remoteDir + "/" + remoteFilename);
  86. }
  87. else {
  88. throw new IllegalArgumentException("invalid sftp operation, " + op);
  89. }
  90. }
  91. private DefaultSftpSessionFactory sftpSessionFactory(String host, int port, String user, String password) {
  92. DefaultSftpSessionFactory factory = new DefaultSftpSessionFactory(true);
  93. factory.setHost(host);
  94. factory.setPort(port);
  95. factory.setUser(user);
  96. factory.setPassword(password);
  97. factory.setAllowUnknownKeys(true);
  98. return factory;
  99. }
  100. private Message<?> buildPutMessage(String remoteDir, String remoteFilename) {
  101. return MessageBuilder.withPayload(new File(this.localDir + "/" + this.localFilename))
  102. .setHeader("file_remoteDirectory", remoteDir)
  103. .setHeader("file_remoteFile", remoteFilename)
  104. .build();
  105. }
  106. public void doWithInputStream(InputStream is) throws IOException {
  107. LOG.debug("doWithInputStream");
  108. String fullPathName = this.localDir + "/" + this.localFilename;
  109. FileWriter w = new FileWriter(fullPathName);
  110. IOUtils.copy(is, w, "UTF-8");
  111. LOG.debug("doWithInputStream file {} written", fullPathName);
  112. w.close();
  113. is.close();
  114. }
  115. }
英文:

I'm trying to implement the following scenario using Spring Integration:

The input channel should poll a SFTP site to get a file storing it in a local "stfp-inbound" folder.
The output channel should push an existing file in a local "sftp-outbound" folder to the SFTP site.
I started with the input channel. It had worked so far but it is obviously very static.

This is my config so far:

  1. @Component
  2. public class SftpClient {
  3. private static final Logger LOG = LoggerFactory.getLogger(SftpClient.class);
  4. @Bean
  5. public IntegrationFlow sftpInboundFlow() {
  6. return IntegrationFlows
  7. .from(Sftp.inboundAdapter(sftpSessionFactory())
  8. .preserveTimestamp(true)
  9. .remoteDirectory(&quot;data&quot;)
  10. .regexFilter(&quot;.*\\.txt$&quot;)
  11. // .localFilenameExpression(&quot;#this.toUpperCase() + &#39;.a&#39;&quot;)
  12. .localDirectory(new File(&quot;ftp-inbound&quot;)),
  13. e -&gt; e.id(&quot;sftpInboundAdapter&quot;)
  14. .autoStartup(true)
  15. .poller(Pollers.fixedDelay(5000)))
  16. .handle(m -&gt; System.out.println(m.getPayload()))
  17. .get();
  18. }
  19. @Bean
  20. public IntegrationFlow sftpOutboundFlow() {
  21. return IntegrationFlows.from(&quot;toSftpChannel&quot;)
  22. .handle(Sftp.outboundAdapter(sftpSessionFactory(), FileExistsMode.FAIL)
  23. .useTemporaryFileName(false)
  24. .remoteDirectory(&quot;/data&quot;)
  25. ).get();
  26. }
  27. @Bean
  28. public SessionFactory&lt;LsEntry&gt; sftpSessionFactory() {
  29. // // with private key resource: catch MalformedURLException
  30. // try {
  31. DefaultSftpSessionFactory factory = new DefaultSftpSessionFactory(true);
  32. factory.setHost(&quot;myHost&quot;);
  33. factory.setPort(22);
  34. factory.setUser(&quot;myUser&quot;);
  35. factory.setPassword(&quot;myPassword&quot;);
  36. // factory.setPrivateKey(new FileUrlResource(&quot;/Users/myUser/.ssh/id_rsa&quot;));
  37. // factory.setPrivateKeyPassphrase(&quot;passphrase&quot;);
  38. factory.setAllowUnknownKeys(true);
  39. return new CachingSessionFactory&lt;LsEntry&gt;(factory);
  40. // }
  41. // catch (MalformedURLException e) {
  42. // throw new IllegalArgumentException(&quot;malformed URL&quot;);
  43. // }
  44. }

I need advice to make a more dynamic approach.
I imagin a component class with public methods sftpGet() and sftpPut() to get and put a file, whereas the channels are created by integration flows with the required parameters that made up a SFTP transfer: hostname, port, user, password, remote dir, local dir.

How can I achieve that?

I got a good hint with a similar TCP/IP channel scenario but I couldn't transform those solution to this SFTP scenario.

Please advice!

After taking in Gary's recommendations I did the foolowing dynamic Bean:

  1. @Component
  2. public class DynamicSftpTemplate implements InputStreamCallback {
  3. private static Logger LOG = LoggerFactory.getLogger(DynamicSftpTemplate.class);
  4. private String localDir;
  5. private String localFilename;
  6. public void getSftpFile(String sessionId, String host, int port, String user, String password,
  7. String remoteDir, String remoteFilename, String localDir, String localFilename) {
  8. LOG.debug(&quot;getSftpFile sessionId={}&quot;, sessionId);
  9. ioSftpFile(GET, host, port, user, password,
  10. remoteDir, remoteFilename, localDir, localFilename);
  11. }
  12. public void putSftpFile(String sessionId, String host, int port, String user, String password,
  13. String remoteDir, String remoteFilename, String localDir, String localFilename) {
  14. LOG.debug(&quot;putSftpFile sessionId={}&quot;, sessionId);
  15. ioSftpFile(PUT, host, port, user, password,
  16. remoteDir, remoteFilename, localDir, localFilename);
  17. }
  18. public void rmSftpFile(String sessionId, String host, int port, String user, String password,
  19. String remoteDir, String remoteFilename) {
  20. LOG.debug(&quot;rmSftpFile sessionId={}&quot;, sessionId);
  21. ioSftpFile(RM, host, port, user, password, remoteDir, remoteFilename, null, null);
  22. }
  23. private void ioSftpFile(SftpOperationType op, String host, int port, String user, String password,
  24. String remoteDir, String remoteFilename, String localDir, String localFilename) {
  25. LOG.debug(&quot;ioSftpFile op={}, host={}, port={}&quot;, op, host, port);
  26. LOG.debug(&quot;ioSftpFile user={}, password={}&quot;, user, password);
  27. SftpRemoteFileTemplate template = new SftpRemoteFileTemplate(sftpSessionFactory(host, port, user, password));
  28. template.setFileNameExpression(new LiteralExpression(remoteDir + &quot;/&quot; + remoteFilename));
  29. template.setRemoteDirectoryExpression(new LiteralExpression(remoteDir));
  30. //template.afterPropertiesSet();
  31. this.localDir = localDir;
  32. this.localFilename = localFilename;
  33. if (op == GET) {
  34. // template.get(buildGetMessage(remoteDir, remoteFilename), (InputStreamCallback) this);
  35. template.get(remoteDir + &quot;/&quot; + remoteFilename, this);
  36. }
  37. else if (op == PUT) {
  38. template.send(buildPutMessage(remoteDir, remoteFilename), FileExistsMode.REPLACE);
  39. }
  40. else if (op == RM) {
  41. template.remove(remoteDir + &quot;/&quot; + remoteFilename);
  42. }
  43. else {
  44. throw new IllegalArgumentException(&quot;invalid sftp operation, &quot; + op);
  45. }
  46. }
  47. private DefaultSftpSessionFactory sftpSessionFactory(String host, int port, String user, String password) {
  48. LOG.debug(&quot;sftpSessionFactory&quot;);
  49. DefaultSftpSessionFactory factory = new DefaultSftpSessionFactory(true);
  50. factory.setHost(host);
  51. factory.setPort(port);
  52. factory.setUser(user);
  53. factory.setPassword(password);
  54. factory.setAllowUnknownKeys(true);
  55. return factory;
  56. }
  57. private Message&lt;?&gt; buildPutMessage(String remoteDir, String remoteFilename) {
  58. return MessageBuilder.withPayload(new File(this.localDir + &quot;/&quot; + this.localFilename))
  59. .setHeader(&quot;file_remoteDirectory&quot;, remoteDir)
  60. .setHeader(&quot;file_remoteFile&quot;, remoteFilename)
  61. .build();
  62. }
  63. public void doWithInputStream(InputStream is) throws IOException {
  64. LOG.debug(&quot;doWithInputStream&quot;);
  65. String fullPathName = this.localDir + &quot;/&quot; + this.localFilename;
  66. FileWriter w = new FileWriter(fullPathName);
  67. IOUtils.copy(is, w, &quot;UTF-8&quot;);
  68. LOG.debug(&quot;doWithInputStream file {} written&quot;, fullPathName);
  69. w.close();
  70. is.close();
  71. }
  72. }

答案1

得分: 0

你可以使用SFTP网关来获取和放置文件(以及其他操作)。

或者,您可以直接使用SftpRemoteFileTemplate

英文:

You can use SFTP Gateways to get and put files (amongst other operations).

Or, you can just use an SftpRemoteFileTemplate directly.

huangapple
  • 本文由 发表于 2020年8月7日 08:17:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/63293487.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定