我有一个Spring集成流程如下。
<int-file:inbound-channel-adapter id="filesIn"
directory="file:${incomingDir}"
filename-pattern="*.txt"
prevent-duplicates="true">
<int:poller id="poller" fixed-delay="5000"/>
</int-file:inbound-channel-adapter>
<int:splitter input-channel="filesIn"
ref="filesSplitterService"
method="splitFilesToReportContent"
output-channel="reportProcessIn"
/>
<int:channel id="reportProcessIn"/>
<int:chain input-channel="reportProcessIn" output-channel="reportProcessOut">
<int:service-activator ref="reportProcessorService" method="readReportMetaData" />
<int:service-activator ref="reportProcessorService" method="saveReportFileInFileSystem" />
<int:service-activator ref="reportProcessorService" method="saveReportMetaDataInDB" />
</int:chain>
<int:channel id="reportProcessOut"/>
<bean id="filesSplitterService" class="com.app.integration.FilesSplitter"/>
<bean id="reportProcessorService" class="com.app.reporting.integration.ReportProcessor"/>
传入文件由一个服务拆分,并创建一个 ReportContent 列表。
然后服务链获取 ReportContent 的每个元素,并从文件内容(如报告ID,报告类型)处理read_report_meta_data,将报告内容字符串保存到相应目录中的文件,并将报表元数据保存在数据库中。流量工作正常,但似乎有一个松散的结束。
我收到以下异常。
org.springframework.integration.MessageDeliveryException:Dispatcher 没有订阅者
我不需要聚合分割元素。在数据库中保存元数据后,就我而言,流程已完成。
但是我想在处理之后将原始文件(我分割成报告文件的主文件)移动到其他目录。我怎么能把这个逻辑融入其中?文件:出站通道似乎是这样做的方式,但我不明白如何做。
有没有办法根据readReportMetaData操作中读取的一些元数据来避免saveReportFileInSystem和saveReportMetaDataInDB操作。
为方便起见,我在下面给出了服务类的结构。
class:FilesSplitter
public List<ReportContent> splitFilesToReportContent(File file){
}
类:ReportProcessor
public ReportContent readReportMetaData(ReportContent reportContent) {
}
public ReportContent saveReportFileInFileSystem(ReportContent reportContent) {
}
public ReportContent saveReportMetaDataInDB(ReportContent reportContent) {
}
需要注意的一点是我没有使用邮件标题。我还没有觉得有必要使用,但我可以使用。我是Spring集成的新手,因此,任何改进此流程的建议都会有所帮助。
答案 0 :(得分:3)
<强> 1。我收到以下异常... org.springframework.integration.MessageDeliveryException
我想你在这里错过了file:outbound-channel-adapter
的定义。
<强> 2。但是我想在处理之后将原始文件(我分割成报告文件的主文件)移动到其他目录。我怎么能加入那个逻辑?
正如14.3.4 File Outbound Channel Adapter中所述,您应该使用delete-source-files
的{{1}}属性,但是(!)
...属性仅在入站消息具有文件有效内容或FileHeaders.ORIGINAL_FILE标头值包含源文件实例或表示原始文件路径的字符串时才有效。
所以,在你outbound-channel-adapter
中你应该处理原始消息。您不再拥有源文件作为有效负载。因此,只有一个选项是正确设置reportProcessorService
标头值。
第3。有没有办法根据readReportMetaData操作中读取的一些元数据来避免saveReportFileInSystem和saveReportMetaDataInDB操作?
是的,有。在EIP链中的FileHeaders.ORIGINAL_FILE
之后使用PayloadTypeRouter(如果可能的话,那么简单)或Configuring (Generic) Router
答案 1 :(得分:3)
我们通常Dispatcher has no subscribers
当SubscribableChannel
没有订阅者(就像你的reportProcessOut
)或者那些订阅者已被停止时,可以视为“没有订阅者”,太
如果您对该结果不感兴趣,我们通常建议您将<service-activator>
结果发送到nullChannel
。如果您无法使用标准的单向组件<outbound-channel-adapter>
来完成任务,那就是这种情况。
但是我想移动原始文件,即我分割成报告文件的主文件,
您可以使用<publish-subscriber-channel>
的第二个单向订阅者作为filesIn
。并且使用标准File.renameTo()
功能实现了这一目标。我没有理由用<int-file:outbound-channel-adapter>
之类的东西来打扰你。您已经在文件系统上了。所以,只需使用它的功能。当我们处理FTP,SFTP等远程文件时,我们需要文件适配器。
您可以使用Map<String, Object> headers
作为3服务方法的第二个参数,Framework将从请求Message<?>
为您注入适当的对象。
请参阅@Andriy Kryvtsun关于“避免saveReportFileInSystem”的回答。
作为替代方案,您可以使用<filter>
来跳过和删除因某些原因无法保存的邮件。