获取onSkipInRead项的路径

时间:2014-08-25 09:06:02

标签: spring-batch

有没有办法获取失败的读取输入文件的位置,以便在SkipListener中使用它?

例:

我的SkipListener移动了每个无法处理或写入错误位置的文件:

@Override
    public void onSkipInWrite(MyFileObject arg0, Throwable arg1) {
        logger.error("onSkipInWrite ");
        logToErrorDirectory(arg0.getPath(), arg1);

    }

@Override
    public void onSkipInProcess(MyFileObject arg0, Throwable arg1) {
        logger.error("onSkipInProcess ");
        logToErrorDirectory(arg0.getPath(), arg1);

    }

@Override
    public void onSkipInRead(Throwable arg1) {
        // WHAT TO DO HERE

    }

当一个Item(准确的.xml文件)也无法读取时,我需要做同样的事情。

我的配置:

<bean id="ExportPatentReader"
        class="org.springframework.batch.item.file.MultiResourceItemReader"
        scope="step">
        <property name="resources" value="file:SomeFolder/*.xml'</property>
        <property name="delegate" ref="staxPatentReader"></property>
        <property name="strict" value="true"></property>
    </bean>

<bean id="staxPatentReader" class="org.springframework.batch.item.xml.StaxEventItemReader"
        scope="step">
        <property name="fragmentRootElementName" value="Root" />
        <property name="unmarshaller" ref="patentMarshaller" />
    </bean>

    <bean id="patentMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
        <property name="classesToBeBound">
            <list>
                <value>com.company.MyFileObject</value>
            </list>
        </property>
    </bean>

MyFileObject我可以轻松获取资源并移动文件,但问题出在此之前。 典型的情况是格式错误的xml文件仍然需要移动到错误目录,但由于它仍未编组,我无法找到获取它的资源路径的方法。

--------------------- UPDATE --------------------- < /强>

根据@Michael Minella的建议,我使用排序的Resources[]MultiResourceItemReader.resourceIndex来获取失败的文件。对于 commit-interval = 1 工作完美!但是对于更大的ci没有运气:(。

我调整后的听众部分:

@Override
    public void onSkipInRead(Throwable arg0) {
        logger.error("onSkipInRead ");

        ExecutionContext stepContext = stepExecution.getExecutionContext();
        logger.info("ExecutionContext: " + stepContext.toString());
        logger.info("stepExecution: " + stepExecution.toString());

        Arrays.sort(resources, comparator);

        Resource errorResource = resources[stepContext.getInt("MultiResourceItemReader.resourceIndex")+1];

        // NOT WORKING
        Resource errorResource2 = resources[stepExecution.getReadCount()+1];
        try {
            // INCORRECT PATH FOR CI>1
            logger.info("Path: " + errorResource.getFile().getCanonicalPath());
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

private Comparator<Resource> comparator = new Comparator<Resource>() {

        /**
         * Compares resource filenames.
         */
        @Override
        public int compare(Resource r1, Resource r2) {
            return r1.getFilename().compareTo(r2.getFilename());
        }

    };

@Override
public void beforeStep(StepExecution arg0) {
    stepExecution = arg0;
}

问题可能是每次提交完成并且ExecutionContext已更新但无法找到解决方法。

对于日志记录期间的更新事项,打印的stepExecution看起来像这样:StepExecution: id=6, version=2, name=partitionedStep:partition4, status=STARTED, exitStatus=EXECUTING, readCount=10, filterCount=0, writeCount=10 readSkipCount=2, writeSkipCount=0, processSkipCount=0, commitCount=1, rollbackCount=0, exitDescription=所以我想也许正确的索引可以是Items per commit + MultiResourceReader.index <的组合/ p>

另一件事......我在开始时忘了提到我使用partitioner来阅读文件,虽然不确定这是否会影响结果。

我使用SkipListener的次数越多,我认为更简单的解决方案是编写自定义阅读器以至少替换StaxEventReader:D

2 个答案:

答案 0 :(得分:1)

MultiResourceItemReader通过索引跟踪ExecutionContext中正在处理的文件。当Resource []被注入阅读器时,我们按文件名对数组进行排序。之后,我们将每个更新的当前文件的索引存储在步骤ExecutionContext中。我认为您可以在SkipListener中实施相同的逻辑。将相同的资源数组注入侦听器,对其进行排序,然后将索引从ExecutionContext中拉出。您可以在此处MultiResourceItemReader的代码中看到此操作:https://github.com/spring-projects/spring-batch/blob/master/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/MultiResourceItemReader.java

答案 1 :(得分:0)

我放弃了提议的解决方案,因为我无法使用commit-interval&gt; 1

解决了我的问题的一个肮脏的解决方案:

Custom Reader替换StaxEventItemReader ==&gt;

onSkipInRead() read() ==&gt;

Custom Reader中添加了read()的逻辑


为了解决this问题,我强制MultiResourceItemReader仅在 @Override public void setResource(Resource arg0) { resource = arg0; // true for new resource ResourceState = true; } @Override public MyFileObject read() throws Exception { MyFileObject item = null; /* * Run only for a new Resource */ if (ResourceState == true) { logger.debug("Reading: " + resource.getFileName()); try { // Actual reading item = (MyFileObject) unmarshaller.unmarshal(resource.getFile()); } catch (Exception e) { logger.error("Error while reading: " + resource.getFilename()); logToErrorDirectory(resource, errorPath, e); } /* * Finished reading, resourceState=false */ ResourceState = false; } return item; } 读取新资源时才会运行:

{{1}}

并不是这个解决方案的粉丝,但解决了我的问题!