In my spring boot app, I have to read a lot of data from the DB convert it to a CSV file and upload it to a SFTP server. Since the file can be huge I cannot read the whole file in memory and then upload. It will to be streamed and appended on the SFTP server.
I am using the atmoz/sftp docker container as my SFTP server and it works fine.
For Spring boot client side - Spring Integration - SFTP Outbound Channel Adapter seems promising to me. Using the following code I was able to upload the file to the SFTP server:
@SpringBootApplication
public class SftpIngApplication {
public static void main(String[] args) throws FileNotFoundException {
ConfigurableApplicationContext context =
new SpringApplicationBuilder(SftpIngApplication.class)
.web(WebApplicationType.SERVLET)
.run(args);
MyGateway gateway = context.getBean(MyGateway.class);
gateway.sendToSftp(new File("/home/john/sftp-ing/notes.txt"));
}
@Bean
public SessionFactory<SftpClient.DirEntry> sftpSessionFactory() {
DefaultSftpSessionFactory factory = new DefaultSftpSessionFactory(true);
factory.setHost("localhost");
factory.setPort(2222);
factory.setUser("foo");
factory.setPassword("pass");
factory.setAllowUnknownKeys(true);
return new CachingSessionFactory<>(factory);
}
@MessagingGateway
public interface MyGateway {
@Gateway(requestChannel = "toSftpChannel")
void sendToSftp(File file);
}
@Bean
public SftpRemoteFileTemplate sftpRemoteFileTemplate(SessionFactory<SftpClient.DirEntry> sftpSessionFactory) {
return new SftpRemoteFileTemplate(sftpSessionFactory);
}
@Bean
public IntegrationFlow sftpOutboundFlow(SessionFactory<SftpClient.DirEntry> sftpSessionFactory) {
return IntegrationFlow.from("toSftpChannel")
.handle(Sftp.outboundAdapter(sftpSessionFactory, FileExistsMode.REPLACE)
.useTemporaryFileName(false)
.remoteDirectory("upload")
).get();
}
}
However this example uses new File("/home/john/sftp-ing/notes.txt")
to upload the file. Simply replacing it with FileInputStream also uploads the file but not with the same name and extension i.e. bar.txt. The file is uploaded as 67157c1b-439d-9f3b-f2be-88eff908e39c.msg
.
It seems to me that the stream is open and some how needs to closed probably however I am not sure what would be the best way to do this. Can someone please help me out with this?
It is indeed correct to use an
InputStream
for your use-case as a payload for transferring to SFTP. What you are missing is a file name to be provided as well.The default
FileNameGenerator
in theRemoteFileTemplate
is aDefaultFileNameGenerator
with the logic like this:The mentioned expression is this:
Since you don't provide that
FileHeaders.FILENAME
, you end up with that generated name based on message id.Just consider to populated a
FileHeaders.FILENAME
header with expected file name before you send anInputStream
to yoursftpOutboundFlow
!