代码之家  ›  专栏  ›  技术社区  ›  dimzak

获取onSkipInRead项的路径

  •  1
  • dimzak  · 技术社区  · 10 年前

    是否有方法获取无法读取的输入文件的位置,以便在 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
    
        }
    

    当项目( .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文件,它仍然需要移动到错误目录 但由于它仍然是未编组的,我无法找到获取它的资源路径的方法。

    ---------------------更新---------------------

    根据@Michael Minella的建议,我使用了排序 Resources[] 以及 MultiResourceItemReader.resourceIndex 以获取失败的文件。对于 提交间隔=1 工作得很好!但对于更大的词,没有运气:(。

    我调整后的Listener部分:

    @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: 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

    还有一件事我忘了在开头提到我使用了 partitioner 用于读取文件,尽管不确定这是否会影响结果。

    我玩得越多 SkipListener(跳过侦听器) 我越认为,一个更简单的解决方案是编写一个定制的阅读器,以至少替换 StaxEventReader :天

    2 回复  |  直到 10 年前
        1
  •  2
  •   Michael Minella    10 年前

    这个 MultiResourceItemReader ExecutionContext 通过索引。当 Resource [] 被注入到读取器中,我们按文件名对数组进行排序。之后,我们将当前文件的索引存储在步骤的 执行上下文 每次更新。我想你可以在你的 SkipListener 。将相同的资源数组注入侦听器,对其进行排序,然后从 执行上下文 。您可以在 多资源项读取器 在这里: https://github.com/spring-projects/spring-batch/blob/master/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/MultiResourceItemReader.java

        2
  •  0
  •   Community CDub    8 年前

    我放弃了建议的解决方案,因为我无法让它与提交间隔一起工作>1.

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

    Custom Reader 替换 StaxEventItemReader ==>

    添加的逻辑 onSkipInRead() 在里面 read() 属于 自定义读取器 ==>


    为了解决 this 我修补的问题 read() 仅当新资源被 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;
        }
    

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