2016-09-14 28 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