這是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