使用共享资源拆分文件并处理每个部分

时间:2016-03-02 16:20:49

标签: java spring file spring-integration splitter

我使用spring集成来轮询文件。此单个文件包含多个报告。我想将文件拆分为报告文件并保存为不同的文件。

<int-file:inbound-channel-adapter id="filesIn"
        directory="file:${fileInDirectory}" 
        filename-pattern="*.txt" 
        prevent-duplicates="true">
    <int:poller id="poller" fixed-delay="5000"/>
    </int-file:inbound-channel-adapter>

<int:service-activator input-channel="filesIn"
                                   output-channel="filesOut"
                                   ref="handler"/>

<int-file:outbound-channel-adapter id="filesOut"
                                   directory="file:${archiveDirectory}"
                                   delete-source-files="true"/>

在处理程序内部,处理程序内部的处理方法如下所示。

public List<ReportContent> splitTextToReports(File file){ 
     // split the file
     // store the file content text to ReportContent object
     // add to a List of ReportContent
}

ReportContent 包含以下字段

  • reportData(将保存在新文件中的文本)

  • REPORTTYPE

  • reportDate

每个ReportContent都需要另一个处理。

  • 根据报告类型查找保存报告的报告路径。这是通过服务电话完成的。
  • 将报告数据保存在表格中

以下是处理上述方法返回的列表的每个元素的方法。

public void processReportContent (ReportContent reportContent){
   // process report content and save the file in the relevant place
}

问题的两个部分。

  1. 如何在读取第一个主文件后使用拆分器接管。因此,每个报告的处理可以完成分割对象的一部分。
  2. 查找报告路径的服务应在所有拆分对象之间使用公共HashMap。如果此哈希映射中存在基于报告类型的值,则它将从此映射中检索。否则,应执行单独的API调用以使用报告类型检索报告路径。报告类型和从此API调用接收的值(报告)将存储在地图中。 Map的重要性在于避免进行不必要的API调用。

2 个答案:

答案 0 :(得分:2)

1。 而不是<int:service-activator input-channel="filesIn"...我会添加一个链

<int:chain id="processor" input-channel="filesIn" output-channel="filesOut">
    <int:splitter>
        <bean class="...your impl of org.springframework.integration.splitter.AbstractMessageSplitter..."/>
    </int:splitter>
</int:chain>

并将您的splitTextToReports逻辑移动到此拆分器中。因此,在拆分器之后的链中,您将拥有ReportContent个实例的平坦流。

2。 在拆分器之后在链中添加转换步骤。将processReportContent逻辑放在这里。转换结果:您的报告在有效负载中的字符串,以及&#39;文件名中的文件名&#39;消息头变量。

您的变压器的API可能是这样的

interface ReportContentTransformer {
   Message<?> transform(ReportContent content);
}

链条看起来像

<int:chain id="processor" input-channel="filesIn" output-channel="filesOut">
    <int:splitter>
       ...
    </int:splitter>
    <int:transformer ref="...ref on your ReportContentTransformer interface implementation bean..." method="transform"/>
</int:chain>

3。 添加到您的outbound-channel-adapter属性

filename-generator-expression="headers.get('filename')"

在文件存储时使用filename变量中的文件名。

答案 1 :(得分:1)

要并行处理项目,<splitter>总是有一个技巧,比如下游ExecutorChannel,所以在分割项目的迭代过程中,我们会在发送前一个项目后立即移动到下一个项目。“ p>

此外,为了获得更好的吞吐量,splitter支持Iterator进行流式传输。

我打算为你的任务建议FileSplitter,但我想你不是按行划分,而是由其他识别器划分。也许你的内容只是XML或JSON,它可以很容易地确定部分内容。

从这里开始,为您的案例提供一些Iterator实施可能并不那么容易。

但我觉得没关系。您已经具有拆分逻辑并构建了List<ReportContent>

关于ConcurrentMap

当下一次调用同一个密钥只返回缓存中的值时,如何查看{“1}} Spring对”硬“服务的支持?

为此,您可以使用@Cacheable上的directory-expression

<int-file:outbound-channel-adapter>

您也可以接受与文件名相同的技术。

注意:请注意文件名的默认标头:<int-file:outbound-channel-adapter directory-expression="@reportPathService.getPath(payload)" />