这是my earlier question关于使用弹簧集成复制文件的后续内容。如何使用FileWritingMessageHandler更改文件名
基本流程是递归扫描目录以找到匹配的文件。一旦找到文件,将使用持久性元数据存储来跟踪文件,然后使用@ServiceActivator将文件复制到/处理文件夹。一个独立的@InboundChannelAdapter用于扫描这个/处理文件夹,然后启动一个弹簧批处理作业。
我面临的问题是,我想重命名文件,因为它被复制到/处理文件夹,但任何用于DefaultFilenameGenerator的表达式似乎都不起作用,因为这些消息头只有' id'和'timestamp',但我不能引用他们中的任何一个。
从documentation的默认行为的第二例子,看来要被执行:
- 评估表达针对该消息,并且如果结果是一个非空的字符串,将它作为文件名。
- 否则,如果有效负载是java.io.File,则使用该文件的文件名。
- 否则,使用附加了.msg的消息ID作为文件名。
最后,我想用一个表达式是这样的:
headers['id'] + '_' + headers['file_name']
但什么我用的是不是被忽视,或错误的。下面的代码段试图使用页眉[“身份证”],但导致一个空字符串(我猜?),因此第二默认行为踢英寸
@Bean
@InboundChannelAdapter(channel = "sourceFileChannel", poller = @Poller(fixedRate = "5000", maxMessagesPerPoll = "-1"))
public MessageSource<File> sourceFiles() {
CompositeFileListFilter<File> filters = new CompositeFileListFilter<>();
filters.addFilter(new SimplePatternFileListFilter(filenamePattern));
filters.addFilter(persistentFilter());
FileReadingMessageSource source = new FileReadingMessageSource();
source.setAutoCreateDirectory(true);
source.setDirectory(new File(sourceDirectory));
source.setFilter(filters);
source.setUseWatchService(true);
return source;
}
@Bean
@InboundChannelAdapter(channel = "processingFileChannel", poller = @Poller(fixedRate = "5000", maxMessagesPerPoll = "-1"))
public MessageSource<File> processingFiles() {
CompositeFileListFilter<File> filters = new CompositeFileListFilter<>();
filters.addFilter(new SimplePatternFileListFilter(filenamePattern));
filters.addFilter(new AcceptOnceFileListFilter<>());
FileReadingMessageSource source = new FileReadingMessageSource();
source.setAutoCreateDirectory(true);
source.setDirectory(new File(processingDirectory));
source.setFilter(filters);
return source;
}
@Bean
@ServiceActivator(inputChannel = "sourceFileChannel")
public MessageHandler fileOutboundChannelAdapter() {
FileWritingMessageHandler adapter = new FileWritingMessageHandler(new File(processingDirectory));
adapter.setDeleteSourceFiles(false);
adapter.setAutoCreateDirectory(true);
adapter.setExpectReply(false);
adapter.setFileNameGenerator(defaultFileNameGenerator());
return adapter;
}
@Bean
public DefaultFileNameGenerator defaultFileNameGenerator() {
DefaultFileNameGenerator defaultFileNameGenerator = new DefaultFileNameGenerator();
defaultFileNameGenerator.setHeaderName("id");
//defaultFileNameGenerator.setExpression("headers['id']");
return defaultFileNameGenerator;
}
编辑
我使用的解决方法是自己扩展DefaultFileNameGenerator。然而,Artem在评论中恰当地展示了如何访问所需的部分。
这里是阿尔乔姆的妥善解决办法:
defaultFileNameGenerator.setExpression("headers.id + '_' + payload.name");
这里是解决办法代码:
public class FilenameGenerator extends DefaultFileNameGenerator {
public FilenameGenerator() {
super();
}
@Override
public String generateFileName(Message<?> message) {
return message.getHeaders().getId().toString() + "_" + ((File) message.getPayload()).getName();
}
}
再次感谢Artem,完美的工作。我猜是什么让我失望是因为我正在尝试'headers ['id']'而不是你显示'headers.id'的正确格式。再次感谢! – rcurrie
不,'headers ['id']'也可以。对于'file_name'你的问题是'null'。 'headers ['id']'是'MapAccessor',它是无效的。较短的'headers.id'是'PropertyAccessor',如果'Map'中没有这样一个'key',就会抛出'NPE'。但'ID'始终存在于'MessageHeaders'! :-) –
啊,现在我明白了。感谢您一如既往的详细解释。我也尝试过'defaultFileNameGenerator.setExpression(“headers ['id']”);'但是这被忽略了,原来的文件名被保留了下来,所以我没有关注。 – rcurrie