首页 > 解决方案 > Spring Integration 新文件回调?

问题描述

我正在使用FileWritingMessageHandler一个自定义FileNameGenerator的间隔生成新文件名(类似于滚动文件追加器log4j)。

@Slf4j
@Getter
@AllArgsConstructor
public class RolloverFileNameGenerator extends AbstractExpressionEvaluator implements FileNameGenerator {
  private final Map<CachedFileEvaluation, String> cache;
  private final RoundedBucketIntervalCalculator intervalCalculator;
  private final Map<String, Object> commonContext;
  private final Expression nameExpression;

  @SuppressWarnings("unchecked")
  public RolloverFileNameGenerator(final RoundedBucketIntervalCalculator intervalCalculator,
                                   final String nameExpression, final Map<String, Object> context, final int cacheMaxSize) {
    this(new LRUMap(cacheMaxSize), intervalCalculator, context, EXPRESSION_PARSER.parseExpression(nameExpression));
  }

  @SuppressWarnings("unchecked")
  public RolloverFileNameGenerator(final RoundedBucketIntervalCalculator intervalCalculator, final String nameExpression, final Map<String, Object> context) {
    this(null, intervalCalculator, context, EXPRESSION_PARSER.parseExpression(nameExpression));
  }

  @Override
  public String generateFileName(final Message<?> message) {
    return generateFileName(message, DateTime.now());
  }

  public String generateFileName(final Message<?> message, final DateTime dateTime) {
    final Interval interval = intervalCalculator.getInterval(dateTime);

    if (cache == null) {
      return evaluateFilenameFromMessage(message, interval);
    }

    final Optional<String> cached = cache.entrySet().stream()
        .filter(entry -> entry.getKey().isBetweenInclusive(dateTime))
        .findFirst()
        .map(Map.Entry::getValue);

    return cached.orElseGet(() -> {
      final String evaluatedValue = evaluateFilenameFromMessage(message, interval);
      cache.putIfAbsent(new CachedFileEvaluation(interval), evaluatedValue);
      return evaluatedValue;
    });
  }

  private String evaluateFilenameFromMessage(final Message<?> message, final Interval interval) {
    final Object evaluated = this.evaluateExpression(nameExpression, new RolloverEvaluationContext(commonContext, interval, message));

    if (evaluated == null) {
      throw new IllegalArgumentException("Evaluated expression is valid, but it resulted with a null");
    }

    if (!(evaluated instanceof String)) {
      throw new IllegalArgumentException(String.format("Evaluated expression is valid, but it didn't result in a String. Evaluated result: (%s) %s", evaluated.getClass(), evaluated));
    }

    return (String) evaluated;
  }

  @Data
  @AllArgsConstructor
  public class CachedFileEvaluation {
    private Interval interval;

    public boolean isBetweenInclusive(final DateTime date) {
      return interval.contains(date) || interval.getEnd().isEqual(date);
    }
  }

  @Getter
  @AllArgsConstructor
  private class RolloverEvaluationContext {
    private final Map<String, Object> ctx;
    private final Interval interval;
    private final Message<?> message;
  }
}

根据我的配置:

@Bean
@ConditionalOnProperty(prefix = "com.github.alturkovic.rollover.writer", name = "initialize", havingValue = "true", matchIfMissing = true)
public FileWritingMessageHandler fileWritingMessageHandler(final RolloverFileNameGenerator rolloverFileNameGenerator) {
  final Writer writer = properties.getWriter();

  final FileWritingMessageHandler handler = new FileWritingMessageHandler(new File(properties.getDirectory()));
  handler.setAppendNewLine(writer.isAppendNewLine());
  handler.setAutoCreateDirectory(writer.isAutoCreateDirectory());
  handler.setFileExistsMode(writer.getMode());
  handler.setFlushInterval(writer.getFlushInterval());
  handler.setFileNameGenerator(rolloverFileNameGenerator);
  handler.setOutputChannelName("nullChannel");
  return handler;
}

每次必须创建一个新文件时,我都想给它写一个 CSV 标头。我已经调查过了FileWritingMessageHandler,但我无法弄清楚如何完成我想要做的事情。

如果可以在不更改FileWritingMessageHandler源代码的情况下完成此操作,有人能指出我正确的方向吗?

标签: javaspringspring-integration

解决方案


您可以保留一些状态并简单地将标题写入RolloverFileNameGenerator.generateFileName().

if (!newName.equals(lastName) {
    // write header
}

推荐阅读