0

我想做的是跟踪删除的文件并应用某些逻辑(获取 id 并更新实体)。我发现我们可以在通道适配器中传递一个监视事件列表,包括

FileReadingMessageSource.WatchEventType.DELETE

但是当我从文件夹中删除文件时,我看不到任何触发的事件,并且从未应用过转换器

@Bean
public IntegrationFlow integrationFlow(FileToMovieTransformer fileToMovieTransformer) {

    return this.integrationFlowBuilder()
            .transform(fileToMovieTransformer)
            .channel(movieHandlerChannel())
            .get();

}

    private IntegrationFlowBuilder integrationFlowBuilder() {

    return IntegrationFlows.from(

            Files.inboundAdapter(new File(localFilmFolder))
                    .autoCreateDirectory(true)
                    .useWatchService(true)
                    .watchEvents(FileReadingMessageSource.WatchEventType.CREATE, FileReadingMessageSource.WatchEventType.DELETE)
                    .patternFilter("*.xml"),

            e -> e.poller(Pollers.fixedDelay(10, TimeUnit.SECONDS)
            ));
}
4

2 回答 2

1

我会说你对待DELETE错误的方式:

/**
 * Directory entry deleted.
 *
 * <p> When a directory is registered for this event then the {@link WatchKey}
 * is queued when it is observed that an entry is deleted or renamed out of
 * the directory. The event {@link WatchEvent#count count} for this event
 * is always {@code 1}.
 */
public static final WatchEvent.Kind<Path> ENTRY_DELETE =
    new StdWatchEventKind<Path>("ENTRY_DELETE", Path.class);

因此,已经没有什么可以作为消息发送给下游了。我们在这里肯定会谈论FileReadingMessageSource. 但是DELETE再也没有什么可读的了。我错过了什么吗?

到目前为止,这是我们在 Docs 中的内容:

这些ENTRY_DELETE事件对ResettableFileListFilter实现有影响,因此,它们的文件是为remove()操作提供的。这意味着(启用此事件时),诸如 的过滤器AcceptOnceFileListFilter将删除文件,这意味着,如果出现具有相同名称的文件,它将通过过滤器并作为消息发送。

因此,要在事件发生时实现您想做的任何DELETE事情,您需要实施ResettableFileListFilter并与SimplePatternFileListFilter您一起将它们组合到CompositeFileListFilter.

当文件被删除时,该DELETE事件被发出,我们最终得到如下逻辑:

if (event.kind() == StandardWatchEventKinds.ENTRY_DELETE) {
    if (getFilter() instanceof ResettableFileListFilter) {
        ((ResettableFileListFilter<File>) getFilter()).remove(file);
    }

其中提到的CompositeFileListFilter肯定实现了这ResettableFileListFilter一点,并将委托给您自己的实现。

于 2018-04-19T13:00:56.863 回答
1

感谢@Artem,这是完整的代码示例,似乎对我很有效

    private IntegrationFlowBuilder integrationFlowBuilder() {

    final List<FileListFilter<File>> defaultFilters = new ArrayList<>(2);

    defaultFilters.add(new IgnoreHiddenFileListFilter());
    defaultFilters.add(new AcceptOnceFileListFilter<>());
    defaultFilters.add(new SimplePatternFileListFilter("*.xml"));
    defaultFilters.add(myCustomRemovalFilter);

    CompositeFileListFilter fileListFilter = new CompositeFileListFilter<>(defaultFilters);

    return IntegrationFlows.from(

            Files.inboundAdapter(new File(localFilmFolder))
                    .autoCreateDirectory(true)
                    .filter(fileListFilter)
                    .useWatchService(true)
                    .watchEvents(FileReadingMessageSource.WatchEventType.CREATE, FileReadingMessageSource.WatchEventType.DELETE),

            e -> e.poller(Pollers.fixedDelay(10, TimeUnit.SECONDS)
            ));
} 

过滤器看起来像

@Component
public class MyCustomRemovalFilter implements ResettableFileListFilter<File> {

private static final Logger LOGGER = LogManager.getLogger(MyCustomRemovalFilter.class);

@Override
public boolean remove(File xmlFile) {

    if (xmlFile == null) {
        return true;
    }
    // TODO you own on removal logic 
}

@Override
public List<File> filterFiles(File[] files) {

    if (files == null || files.length == 0) {
        return Collections.emptyList();
    }
    return Arrays.asList(files);
}
}
于 2018-04-19T14:16:58.940 回答