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

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

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

问题

以下是翻译的内容:

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

输入通道应该轮询SFTP站点以获取文件,并将其存储在本地的“sftp-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$")
                    .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() {
        DefaultSftpSessionFactory factory = new DefaultSftpSessionFactory(true);
        factory.setHost("myHost");
        factory.setPort(22);
        factory.setUser("myUser");
        factory.setPassword("myPassword");
        factory.setAllowUnknownKeys(true);
        return new CachingSessionFactory<LsEntry>(factory);
    }
}

我需要建议以实现更加动态的方法。我想象一个组件类,具有公共方法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));

        this.localDir = localDir;
        this.localFilename = localFilename;
        if (op == GET) {
            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) {
        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();
    }
}
英文:

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:

@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(&quot;data&quot;)
                .regexFilter(&quot;.*\\.txt$&quot;)
//                    .localFilenameExpression(&quot;#this.toUpperCase() + &#39;.a&#39;&quot;)
                .localDirectory(new File(&quot;ftp-inbound&quot;)),
             e -&gt; e.id(&quot;sftpInboundAdapter&quot;)
                .autoStartup(true)
                .poller(Pollers.fixedDelay(5000)))
        .handle(m -&gt; System.out.println(m.getPayload()))
        .get();
}

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

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

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:

@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(&quot;getSftpFile sessionId={}&quot;, 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(&quot;putSftpFile sessionId={}&quot;, 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(&quot;rmSftpFile sessionId={}&quot;, 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(&quot;ioSftpFile op={}, host={}, port={}&quot;, op, host, port);
		LOG.debug(&quot;ioSftpFile user={}, password={}&quot;, user, password);
		SftpRemoteFileTemplate template = new SftpRemoteFileTemplate(sftpSessionFactory(host, port, user, password));
		template.setFileNameExpression(new LiteralExpression(remoteDir + &quot;/&quot; + 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 + &quot;/&quot; + remoteFilename, this);
		}
		else if (op == PUT) {
			template.send(buildPutMessage(remoteDir, remoteFilename), FileExistsMode.REPLACE);			
		}
		else if (op == RM) {
			template.remove(remoteDir + &quot;/&quot; + remoteFilename);			
		}
		else {
			throw new IllegalArgumentException(&quot;invalid sftp operation, &quot; + op);
		}
	}

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

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

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

答案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:

确定