2016-09-14 106 views
1

這是my earlier question關於使用彈簧集成複製文件的後續內容。如何使用FileWritingMessageHandler更改文件名

基本流程是遞歸掃描目錄以找到匹配的文件。一旦找到文件,將使用持久性元數據存儲來跟蹤文件,然後使用@ServiceActivator將文件複製到/處理文件夾。一個獨立的@InboundChannelAdapter用於掃描這個/處理文件夾,然後啓動一個彈簧批處理作業。

我面臨的問題是,我想重命名文件,因爲它被複制到/處理文件夾,但任何用於DefaultFilenameGenerator的表達式似乎都不起作用,因爲這些消息頭只有' id'和'timestamp',但我不能引用他們中的任何一個。

documentation的默認行爲的第二例子,看來要被執行:

  1. 評估表達針對該消息,並且如果結果是一個非空的字符串,將它作爲文件名。
  2. 否則,如果有效負載是java.io.File,則使用該文件的文件名。
  3. 否則,使用附加了.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(); 
    } 
} 

回答

1

FileReadingMessageSource後無file_name頭,所以你必須使用​​:

defaultFileNameGenerator.setExpression("headers.id + '_' + payload.name"); 
+0

再次感謝Artem,完美的工作。我猜是什麼讓我失望是因爲我正在嘗試'headers ['id']'而不是你顯示'headers.id'的正確格式。再次感謝! – rcurrie

+1

不,'headers ['id']'也可以。對於'file_name'你的問題是'null'。 'headers ['id']'是'MapAccessor',它是無效的。較短的'headers.id'是'PropertyAccessor',如果'Map'中沒有這樣一個'key',就會拋出'NPE'。但'ID'始終存在於'MessageHeaders'! :-) –

+0

啊,現在我明白了。感謝您一如既往的詳細解釋。我也嘗試過'defaultFileNameGenerator.setExpression(「headers ['id']」);'但是這被忽略了,原來的文件名被保留了下來,所以我沒有關注。 – rcurrie