Spring batch Spring批处理:如何获取读取的所有行的错误?

Spring batch Spring批处理:如何获取读取的所有行的错误?,spring-batch,Spring Batch,我正在使用FlatFileItemReader读取文件。我插入DefaultLineMapper和我自己的自定义FieldSetMapper(myMapper) 目前在myMapper中,当发生错误时,我只需将其记录下来。我想积累文件中所有行的所有错误,然后将它们保存到文件中 我正在考虑实施我自己的Tasklet。但从我所读到的内容来看,建议只在您的步骤没有进行面向块的处理时才这样做 另一个选项是使用ItemListenerSupport或ItemReadListener并实现onReadErr

我正在使用FlatFileItemReader读取文件。我插入DefaultLineMapper和我自己的自定义FieldSetMapper(myMapper)

目前在myMapper中,当发生错误时,我只需将其记录下来。我想积累文件中所有行的所有错误,然后将它们保存到文件中

我正在考虑实施我自己的Tasklet。但从我所读到的内容来看,建议只在您的步骤没有进行面向块的处理时才这样做

另一个选项是使用ItemListenerSupport或ItemReadListener并实现onReadError()方法。但如果我这样做,我不确定我如何能够访问一个全局/共享对象,该对象包含所有行的所有错误列表

我一直在这两种选择之间来回奔波,试图让它们发挥作用,但没有取得多大成功。非常感谢您的建议

*****编辑*****

我认为我的代码不是任何非标准的东西。我定义了错误日志作业参数:

Map<String, JobParameter> jobParametersMap ...
jobParametersMap.put("errorsFile", new JobParameter(errorsFileURI));
映射作业参数映射。。。
jobParametersMap.put(“errorsFile”,新的JobParameter(errorsFileURI));
我的xml配置如下所示:

<job ...>
  <step ...>
  <step id="import">
    <tasklet>
      <chunk reader="importReader" writer="importWriter" .../>
    </tasklet>
  </step>
</job>

<bean id="importReader" class="MyImportReader" scope="step">
  <property name="resource" .../>
  <property name="lineMapper">
    <bean class = "...DefaultLineMapper">
      ...
      <property name="fieldSetMapper" ref="importMapper"/>
    </bean>
  </property>
  <property name="errorsFile" value="#jobParameters['errorsFile']}"/>
</bean>

<bean id="importWriter" ...scope="step">
  ...
  <property name="errorsFile" value="#jobParameters['errorsFile']}"/>
</bean>

...
...
Reader类扩展FlatFileItemReader并实现ItemReadListener。编写器实现BatchLoadableWriter和StepExecutionListener

如您所见,我将errorsFile传递给读者和作者。作者使用errorsFile已经有一段时间了,而我只是将它添加到阅读器中。这两个类都有一个用于errorsFile的getter/setter

它们之间的区别在于,在Writer中,@overrided write()方法验证并写入文件中的所有项。因此,所有错误都会立即写入errorsFile。此外,如果存在错误,将设置一个标志(hasErrors),并在@overrided afterStep()方法中检查该标志的值。如果为true,则返回ExitStatus.FAILED

而在读卡器中,doRead()方法会为每个项调用一次。如果有错误,我可以将其写入errorsFile,并且可以像编写器那样设置标志。但该标志将仅为该行/项目设置

假设我导入了10行。前5个有错误,后5个没有。调用afterRead()时,它将检查最后处理的项的标志值,该项没有错误,因此hasErrors将为false。不好的。或者最好重写onReadError()。但是什么会导致调用该方法,映射程序中的错误

有些事情告诉我,实现自己的阅读器和/或让它实现ItemReadListener可能不是实现这一点的方法。对我来说,似乎我需要把这些逻辑的一部分或全部放在读者的“父母”中。。。那将是。。。小工?但是我在网上读到过很多关于实现自己的Tasklet来执行块处理的文章,这是不推荐的;它只能用于简单的任务


我感到茫然……P.>我认为你应该考虑使用步骤和工作范围。从阅读器中,您可以将错误详细信息保存到这些作用域中,然后在以后的阶段引用这些信息。我会小心不要在这里记录太多的信息


在作业开始时,生成并命名错误文件,并将其保存到作业/步骤范围。如果读卡器有错误,它可以将详细信息写入文件。在流程结束时,您仍然有一个对错误文件名的引用,以及记录的详细信息

继续关注这个问题,以防它能帮助其他人

最后,我实现了一个自定义LineMapper,并在该类的mapLine(String line,int lineNumber)方法中,将行号保存到executionContext中,从而实现了我想要的功能:

public class MyLineMapper implements LineMapper<MyPojo>,
  InitializingBean, StepExecutionListener {

  private ExecutionContext _executionContext;

  public MyPojo mapLine(String line, int lineNumber)
    throws Exception {

  _executionContext.put("lineNumber", lineNumber);

  MyPojo myPojo = fieldSetMapper.mapFieldSet(tokenizer.tokenize(line));
  return myPojo;
}
公共类MyLineMapper实现了LineMapper,
初始化Bean,StepExecutionListener{
私有ExecutionContext\u ExecutionContext;
公共MyPojo映射行(字符串行、整数行号)
抛出异常{
_executionContext.put(“行号”,行号);
MyPojo MyPojo=fieldSetMapper.mapFieldSet(tokenizer.tokenize(line));
返回myPojo;
}
因为我需要访问ExecutionContext,所以我让这个类也实现了StepExecutionListener

然后在我的自定义FieldMapper中,我还实现了StepExecutionListener,这样我就可以从ExecutionContext中获取行号,并使用它记录行号错误:

public class MyFieldMapper implements LineMapper<MyPojo>,
  InitializingBean, StepExecutionListener {

  private ExecutionContext _executionContext;

  @Override
  public MyPojo mapFieldSet(final FieldSet fieldSet)
    throws BindException {

    String currentLineNumber =
      (_executionContext.get("lineNumber") != null) ? String
      .valueOf(_executionContext.get("lineNumber")) : "-";

    if (some kind of error) {
      logError(currentLineNumber, errorMsg);
公共类MyFieldMapper实现LineMapper,
初始化Bean,StepExecutionListener{
私有ExecutionContext\u ExecutionContext;
@凌驾
公共MyPojo映射字段集(最终字段集字段集)
抛出绑定异常{
字符串currentLineNumber=
(_executionContext.get(“lineNumber”)!=null)?字符串
.valueOf(_executionContext.get(“行号”):“-”;
如果(某种错误){
日志错误(currentLineNumber,errorMsg);
然后,我在我的编写器的beforeWrite()方法中检查errorFile是否存在。如果存在,则意味着在读取/验证时发生某种错误,我抛出异常

这样,我就可以记录csv文件所有行的所有读取/验证错误,而不会在出现第一个错误时退出并停止处理


希望有一天这能帮助其他人!

但是这需要实现我自己的阅读器吗?或者我可以在FieldMapper中实现吗?我想我的问题是,我应该把这段代码放在哪里?阅读器(默认的FlatFileItemReader)为文件中的每一行执行。如果读取/验证失败,我想将错误添加到错误列表中。我应该将将用于将列表放入作业或步骤范围的代码放在哪里?在所有处理完成后,我应该将用于将错误打印到文件中的代码放在哪里?实际上,我知道如何将列表作为作业参数传递。但我应该在哪里将从范围中获取列表的代码放入1)添加到列表中(每次读取),2)打印出其内容(之后