Spring integration 使用Spring集成和批处理读取CSV文件并将其插入数据库

Spring integration 使用Spring集成和批处理读取CSV文件并将其插入数据库,spring-integration,spring-batch,Spring Integration,Spring Batch,我有一个监控FTP文件夹中特定csv文件的应用程序foo.csv,一旦找到该文件,它会将其拉到我的本地并生成一个新的输出格式bar.csv,然后应用程序会将新文件bar.csv发送回FTP文件夹,并将其从本地删除 现在,我想介绍一个进程,该进程将读取bar.csv,并将其插入数据库表中,然后再将其发送到FTP服务器 我假设这可以使用Spring批处理集成来完成,但我找不到如何做到这一点 下面是我的申请代码,供参考和建议 public IntegrationFlow localToFtpFlow(

我有一个监控FTP文件夹中特定csv文件的应用程序
foo.csv
,一旦找到该文件,它会将其拉到我的本地并生成一个新的输出格式
bar.csv
,然后应用程序会将新文件
bar.csv
发送回FTP文件夹,并将其从本地删除

现在,我想介绍一个进程,该进程将读取
bar.csv
,并将其插入数据库表中,然后再将其发送到FTP服务器

我假设这可以使用Spring批处理集成来完成,但我找不到如何做到这一点

下面是我的申请代码,供参考和建议

public IntegrationFlow localToFtpFlow(Branch myBranch) {

    return IntegrationFlows.from(Files.inboundAdapter(new File(myBranch.getBranchCode()))
                    .filter(new ChainFileListFilter<File>()
                            .addFilter(new RegexPatternFileListFilter("final" + myBranch.getBranchCode() + ".csv"))
                            .addFilter(new FileSystemPersistentAcceptOnceFileListFilter(metadataStore(dataSource), "foo"))),//FileSystemPersistentAcceptOnceFileListFilter
            e -> e.poller(Pollers.fixedDelay(10_000)))
            .enrichHeaders(h ->h.headerExpression("file_originalFile", "new java.io.File('"+ myBranch.getBranchCode() +"/FEFOexport" + myBranch.getBranchCode() + ".csv')",true))
            .transform(p -> {
                LOG.info("Sending file " + p + " to FTP branch " + myBranch.getBranchCode());
                return p;
            })

            .log()
            .transform(m -> {
                        this.defaultSessionFactoryLocator.addSessionFactory(myBranch.getBranchCode(),createNewFtpSessionFactory(myBranch));
                        LOG.info("Adding factory to delegation");
                        return m;
            })

            .publishSubscribeChannel(s ->
                    s.subscribe(f -> f.transform(fileMessageToJobRequest()).handle(jobLaunchingGateway()).channel("nullChannel"))
                    .subscribe(h -> h.handle(Ftp.outboundAdapter(createNewFtpSessionFactory(myBranch), FileExistsMode.REPLACE)
                                     .useTemporaryFileName(true)
                                     .autoCreateDirectory(false)
                                     .remoteDirectory(myBranch.getFolderPath()), e -> e.advice(expressionAdvice()))))
            /*.handle(Ftp.outboundAdapter(createNewFtpSessionFactory(myBranch), FileExistsMode.REPLACE)
                    .useTemporaryFileName(true)
                    .autoCreateDirectory(false)
                    .remoteDirectory(myBranch.getFolderPath()), e -> e.advice(expressionAdvice()))*/
            .get();
}

@Bean
public FileMessageToJobRequest fileMessageToJobRequest(){
    FileMessageToJobRequest fileMessageToJobRequest = new FileMessageToJobRequest();
    fileMessageToJobRequest.setFileParameterName("input.file.name");
    fileMessageToJobRequest.setJob(orderJob);
    return fileMessageToJobRequest;
}

@Bean
public JobLaunchingGateway jobLaunchingGateway() {
    SimpleJobLauncher simpleJobLauncher = new SimpleJobLauncher();
    //simpleJobLauncher.setJobRepository(jobRepository);
    simpleJobLauncher.setTaskExecutor(new SyncTaskExecutor());
    JobLaunchingGateway jobLaunchingGateway = new JobLaunchingGateway(simpleJobLauncher);

    return jobLaunchingGateway;
}

您需要考虑在<代码> IpgReTraseFuxs/Cuth>定义中使用<代码> PuxSudio BoeBohanChhanle()/Cyto>。将您的

.handle(Ftp.outboundAdapter())
作为一个订阅者放置(最好是第二个)。作为第一个,它应该类似于
.handle(jobLaunchingGateway).channel(“nullChannel”)

您可以在Spring批处理中阅读关于
JobLaunchingGateway

关键是,您希望将同一消息发送到多个地方。因此,
PublishSubscribeChannel
是最好的方式:

我建议您将这些订阅者完全按照这个顺序排列,因为您确实希望在发送到FTP之前将其存储到DB中。如果没有
执行器,第二个订户将等待第一个订户完成其工作

.channel(“nullChannel”)
在那里是必需的,因为
JobLaunchingGateway
实际上是一个网关,它返回一个
jobsecution
作为应答。既然你对此不感兴趣,你只需要忽略它。当然,您可以在该网关之后使用另一个
handle()
以某种方式处理此
JobExecution
。关键是不要从第一个订阅者那里返回任何东西作为回复。它会以某种方式阻止你的主流

更新

我认为
.transform(fileMessageToJobRequest())
必须在
作业启动网关之前到达下面的第一个订户:

 .publishSubscribeChannel(s ->
                s.subscribe(f -> f.transform(fileMessageToJobRequest()).handle(jobLaunchingGateway()).channel("nullChannel"))
                .subscribe(h -> h.handle(Ftp.outboundAdapter(createNewFtpSessionFactory(myBranch), ...))
关键是,您希望将相同的文件发送到下一个
句柄()
,但在该转换器上游之后,它将被更改为
JobLaunchRequest
,这对
jobLaunchingGateway
有好处,但对
Ftp.outboundAdapter()
没有好处

您的例外情况:

Caused by: java.lang.NullPointerException
    at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:98)
导致这段代码:
Assert.notNull(jobParameters,“jobParameters不能为null”)。因此,
jobParametersBuilder.toJobParameters()
的计算结果为
null

我帮不了你这么多自定义代码

更新2

嗯。看起来您的问题在
JobLaunchingGateway
bean定义中。在那里,您可以显式地执行
新的simplejoblancher()
,而无需
作业存储库
注入


Spring Boot的
BatchConfigureConfiguration
中似乎有一个
BasicBatchConfigurer
,可以将它注入到这个
JobLaunchingGateway
中。因此,我们将通过NPE。之后还有其他错误,但这已经是一个不同的故事了。

你需要考虑在<代码>整数流定义中使用<代码> PuxSudio BoeBohanChhanle()/Cyto>。将您的
.handle(Ftp.outboundAdapter())
作为一个订阅者放置(最好是第二个)。作为第一个,它应该类似于
.handle(jobLaunchingGateway).channel(“nullChannel”)

您可以在Spring批处理中阅读关于
JobLaunchingGateway

关键是,您希望将同一消息发送到多个地方。因此,
PublishSubscribeChannel
是最好的方式:

我建议您将这些订阅者完全按照这个顺序排列,因为您确实希望在发送到FTP之前将其存储到DB中。如果没有
执行器,第二个订户将等待第一个订户完成其工作

.channel(“nullChannel”)
在那里是必需的,因为
JobLaunchingGateway
实际上是一个网关,它返回一个
jobsecution
作为应答。既然你对此不感兴趣,你只需要忽略它。当然,您可以在该网关之后使用另一个
handle()
以某种方式处理此
JobExecution
。关键是不要从第一个订阅者那里返回任何东西作为回复。它会以某种方式阻止你的主流

更新

我认为
.transform(fileMessageToJobRequest())
必须在
作业启动网关之前到达下面的第一个订户:

 .publishSubscribeChannel(s ->
                s.subscribe(f -> f.transform(fileMessageToJobRequest()).handle(jobLaunchingGateway()).channel("nullChannel"))
                .subscribe(h -> h.handle(Ftp.outboundAdapter(createNewFtpSessionFactory(myBranch), ...))
关键是,您希望将相同的文件发送到下一个
句柄()
,但在该转换器上游之后,它将被更改为
JobLaunchRequest
,这对
jobLaunchingGateway
有好处,但对
Ftp.outboundAdapter()
没有好处

您的例外情况:

Caused by: java.lang.NullPointerException
    at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:98)
导致这段代码:
Assert.notNull(jobParameters,“jobParameters不能为null”)。因此,
jobParametersBuilder.toJobParameters()
的计算结果为
null

我帮不了你这么多自定义代码

更新2

嗯。看起来您的问题在
JobLaunchingGateway
bean定义中。在那里,您可以显式地执行
新的simplejoblancher()
,而无需
作业存储库
注入


Spring Boot的
BatchConfigureConfiguration
中似乎有一个
BasicBatchConfigurer
,可以将它注入到这个
JobLaunchingGateway
中。因此,我们将通过NPE。之后还有其他错误,但这已经是另一回事了…

谢谢Artem,我就快到了,我添加了所有需要的类和方法,但是getti