【问题标题】:Spring Batch Footer ValidationSpring Batch 页脚验证
【发布时间】:2014-02-07 21:35:24
【问题描述】:

我正在使用 Spring 批处理来处理带有页眉、详细信息和页脚记录的文件。 页脚包含文件中的记录总数。 如果详细记录计数与页脚中的计数不匹配,则不应处理该文件。

我正在使用处理页眉、详细信息和页脚记录的自定义行标记器。当遇到页脚记录时,如果计数与详细记录计数匹配,我将抛出异常。

但我面临的问题是,如果块大小设置为 10 之类的小数字并且文件有 20 条记录,则前 10 条详细记录将被保存到数据库中,即使页脚计数与总数匹配记录。

有没有办法在调用 Writer 之前使用文件中的记录数来验证页脚计数?

谢谢。

【问题讨论】:

  • 如果文件很小,你可以设置一个高提交间隔来强制单个块处理,但这是一种肮脏的方式
  • 还有其他更好的方法比如预验证吗?我不想将块大小设置得太高。
  • 你知道最后一条记录是多少字节吗?
  • @jyn 有很多选择。我会编写一个仅读取文件并进行验证的 tasklet,如果验证通过,我将转到您现在拥有的下一步并进行正常插入。
  • 如果找到的记录数量与页脚的数量匹配但写入某些记录失败会怎样?文件还正确吗?

标签: spring-batch


【解决方案1】:

您需要的是一个定义了页脚回调处理程序的阅读器。我遇到过类似的问题,this link 帮了我很多! 请参阅 Atefeh Zareh 的最后一篇文章。他还包含了 xml 配置。

关于前十个被持久化,您可以在主要处理步骤之前进行另一个验证步骤,该步骤将仅检查标题和尾部计数。不要在编写器中编写任何持久化逻辑。如果计数失败,请停止作业,使其不进入处理步骤。

【讨论】:

  • 感谢宙斯,但这不是我想要的,我已经能够解析页脚并保存信息。我想在处理文件之前对其进行验证,因此定义了一个 tasklet 来检查页脚计数匹配,然后在 tasklet 成功时调用加载步骤。
【解决方案2】:

通过编写我们自己的 Item Reader 以及 Item 类来处理 Header、Footer、Data 记录并查找 Header、Footer、Data 记录的计数

ItemReader 类

public class AggregateItemReader<T> implements ItemStreamReader<ResultHolder> {


private ItemStreamReader<AggregateItem<T>> itemReader;

@Override
public ResultHolder read() throws Exception {
    ResultHolder holder = new ResultHolder();

    while (process(itemReader.read(), holder)) {
        continue;
    }

    if (!holder.isExhausted()) {
        return holder;
    }
    else {
        return null;
    }
}

private boolean process(AggregateItem<T> value, ResultHolder holder) {
    // finish processing if we hit the end of file
    if (value == null) {
        LOG.debug("Exhausted ItemReader");
        holder.setExhausted(true);
        return false;
    }

    // start a new collection
    if (value.isHeader()) {
        LOG.debug("Header Record detected");
        holder.addHeaderRecordCount();
        return true;
    }

    // mark we are finished with current collection
    if (value.isFooter()) {
        LOG.debug("Tailer Record detected");
        holder.addTailerRecordCount();
        holder.setFiledRecordCount(value.getFieldSet().readInt(3));
        System.out.println("###########################################"+holder.getDataRecordCount()+"############################################");
        return false;
    }

    // add a simple record to the current collection

    holder.addDataRecordCount();
    return true;
}

物品类别是

public class AggregateItem<T> {

@SuppressWarnings("unchecked")
public static <T> AggregateItem<T> getData(FieldSet fs) {
    return new AggregateItem(fs, false, false, true);
}

@SuppressWarnings("unchecked")
public static <T> AggregateItem<T> getFooter(FieldSet fs) {
    return new AggregateItem(fs, false, true, false);
}


@SuppressWarnings("unchecked")
public static <T> AggregateItem<T> getHeader(FieldSet fs) {
    return new AggregateItem(fs, true, false, false);
}

private boolean data = false;
private FieldSet fieldSet;

private boolean footer = false;

private boolean header = false;

private T item;

public AggregateItem(FieldSet fs, boolean header, boolean footer, boolean data) {
    this(null);
    this.header = header;
    this.footer = footer;
    this.data = data;
    this.fieldSet = fs;
}


public AggregateItem(T item) {
    super();
    this.item = item;
}

public FieldSet getFieldSet() {
    return fieldSet;
}


public T getItem() {
    return item;
}

public boolean isData() {
    return data;
}


public boolean isFooter() {
    return footer;
}


public boolean isHeader() {
    return header;
}

}

ResultHolder 类是

public class ResultHolder implements {
private Integer headerRecordCount = 0;
private Integer dataRecordCount = 0;
private Integer tailerRecordCount = 0;
private Integer filedRecordCount;//this is to save record count given in source File
private boolean exhausted = false;//setters & getters

}

如有任何疑问,请随时发送邮件至 sk.baji6@gmail.com

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-08-22
    • 1970-01-01
    • 1970-01-01
    • 2020-05-26
    • 2017-05-11
    • 2012-11-28
    • 1970-01-01
    • 2019-06-09
    相关资源
    最近更新 更多