首页 文章

Spring Batch:如何获取读取的所有行的错误?

提问于
浏览
0

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

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

我正在考虑实现自己的Tasklet . 但是从我读过的内容来看,如果你的步骤没有进行面向块的处理,建议只做这个 .

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

我一直在这两个选项之间来回试图让他们工作,没有太大的成功 . 任何建议都非常感谢 .

编辑

我的代码不是任何非标准的我不认为 . 我定义错误日志Job Param:

Map<String, JobParameter> jobParametersMap ...
jobParametersMap.put("errorsFile", new 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传递给Reader和Writer . Writer已经使用了errorsFile一段时间,而我只是将它添加到Reader中 . 这两个类都有一个针对errorsFile的getter / setter .

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

而对于Reader,每个Item都会调用一次doRead()方法 . 如果有错误,我可以将它写入errorsFile,我可以像Writer一样设置一个标志 . 但是只为该行/项设置标志 .

所以我要说我导入了10行 . 前5个有错误,后5个没有错误 . 当调用afterRead()时,它将检查最后处理的Item的标志值,该值没有错误,因此hasErrors将为false . 不好 . 或者最好覆盖onReadError() . 但是什么会导致调用该方法,Mapper中的错误?

有些东西告诉我实现自己的Reader,和/或让它实现ItemReadListener可能不是解决这个问题的方法 . 对我来说,似乎我需要将一些或所有这些逻辑放在Reader的“父”中......这将是......一个Tasklet?但是我已经在网上和其他地方读过,不推荐实现自己的Tasklet来执行块处理;它应该只用于简单的任务 .

我不知所措......

2 回答

  • 1

    只是跟进这个问题,以防它可以帮助其他人 .

    最后,我能够通过实现自定义LineMapper并在该类'mapLine(String line,int lineNumber)方法中执行我想要的操作,将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;
    }
    

    由于我需要访问ExecutionContext,因此我使该类也实现了StepExecutionListener .

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

    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);
    

    然后我在我的Writer的beforeWrite()方法中检查是否存在errorFile . 如果存在,那意味着在读取/验证时会出现某种错误,并且我会抛出异常 .

    这样我可以记录所有读取/验证错误,对于我的csv文件的所有行,而不是在发生第一个错误时退出和停止处理 .

    希望有一天这会帮助别人!

  • 0

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

    http://docs.spring.io/spring-batch/reference/html/configureStep.html#step-scope

    在作业开始时,生成并命名错误文件并将其保存到作业/步骤范围 . 如果您的Reader有错误,它可以将详细信息写入文件 . 在该过程结束时,您仍然可以使用记录的详细信息引用错误文件名 .

相关问题