当前位置: 首页 > 知识库问答 >
问题:

将lineNumber存储在stepExecutionContext中并访问它

申黎明
2023-03-14

我试图通过将其存储在ExecutionContext中来跟踪csv文件中每个项的lineNumber。Reader是一个带有修改过的Linemapper的FlatFileItemReader。下面是它的代码:

public class MyLineMapper<T> implements LineMapper<T>, InitializingBean {

private LineTokenizer tokenizer;

private FieldSetMapper<T> fieldSetMapper;

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

        ExecutionContext value = new ExecutionContext();
        value.putInt("name", lineNumber);


        return fieldSetMapper.mapFieldSet(tokenizer.tokenize(line));
    }
    catch(Exception ex){
        throw new FlatFileParseException("Parsing error at line: " + lineNumber + 
                ", input=[" + line + "]", ex, line, lineNumber); 
    }
}

public void setLineTokenizer(LineTokenizer tokenizer) {
    this.tokenizer = tokenizer;
}

public void setFieldSetMapper(FieldSetMapper<T> fieldSetMapper) {
    this.fieldSetMapper = fieldSetMapper;
}

public void afterPropertiesSet() {
    Assert.notNull(tokenizer, "The LineTokenizer must be set");
    Assert.notNull(fieldSetMapper, "The FieldSetMapper must be set");
}

}
public class CustomItemProcessor implements ItemProcessor<Report, Report> {

private int field;


public int getField() {
    return field;
}


public void setField(int field) {
    this.field = field;
}


@Override
public Report process(Report item) throws Exception {

    System.out.println("Processing " + item.getId() + "in line " + field);
    return item;
}

}
<bean id="report" class="com.example.model.Report" scope="prototype" />
<bean id="itemProcessor" class="com.example.CustomItemProcessor" scope="step">
    <property name="field" value="#{stepExecutionContext[name]}"></property>
</bean>

<batch:job id="helloWorldJob">
    <batch:step id="step1">
        <batch:tasklet>
            <batch:chunk reader="cvsFileItemReader" writer="xmlItemWriter"
                processor="itemProcessor" commit-interval="10">
            </batch:chunk>
        </batch:tasklet>
    </batch:step>
</batch:job>

<bean id="cvsFileItemReader" class="org.springframework.batch.item.file.FlatFileItemReader">

    <property name="resource" value="classpath:cvs/input/report.csv" />

    <property name="lineMapper">
        <bean class="com.example.MyLineMapper">
            <property name="lineTokenizer">
                <bean
                    class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer">
                    <property name="names" value="id,sales,qty,staffName,date" />
                </bean>
            </property>
            <property name="fieldSetMapper">
                <bean class="com.example.ReportFieldSetMapper"/>
            </property>
        </bean>
    </property>

</bean>

<bean id="xmlItemWriter" class="org.springframework.batch.item.xml.StaxEventItemWriter">
    <property name="resource" value="file:xml/outputs/report.xml" />
    <property name="marshaller" ref="reportMarshaller" />
    <property name="rootTagName" value="report" />
</bean>

<bean id="reportMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
    <property name="classesToBeBound">
        <list>
            <value>com.example.model.Report</value>
        </list>
    </property>
</bean>

和例外:

10:34:48.146 [main] DEBUG o.s.b.core.step.tasklet.TaskletStep - Rollback for RuntimeException: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.itemProcessor' defined in class path resource [spring/batch/jobs/job-hello-world.xml]: Initialization of bean failed; nested exception is org.springframework.beans.TypeMismatchException: Failed to convert property value of type 'null' to required type 'int' for property 'field'; nested exception is java.lang.IllegalArgumentException: Cannot convert value of type [null] to required type [int] for property 'field': PropertyEditor [org.springframework.beans.propertyeditors.CustomNumberEditor] returned
inappropriate value of type [null]
10:34:48.155 [main] DEBUG o.s.t.support.TransactionTemplate - Initiating transaction rollback on application exception
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.itemProcessor' defined in class path resource [spring/batch/jobs/job-hello-world.xml]: Initialization of bean failed; nested exception is org.springframework.beans.TypeMismatchException: Failed to convert property value of type 'null' to required type 'int' for property 'field'; nested exception is java.lang.IllegalArgumentException: Cannot convert value of type [null] to required type [int] for
property 'field': PropertyEditor [org.springframework.beans.propertyeditors.CustomNumberEditor] returned inappropriate value of type [null]

共有1个答案

万俟小林
2023-03-14

让您的MyLineMapper实现StepExecutionListener,并在StepExecutionListener.beforeStep()`中绑定当前步骤执行上下文,而不是创建新的上下文。

public class MyLineMapper<T> implements LineMapper<T>, InitializingBean, StepExecutionContext {
  ExecutionContext stepExecution;

  public void beforeStep(ExecutionContext stepExecution) { this.stepExecution = stepExecution;}

  public T mapLine(String line, int lineNumber) throws Exception {
    this.stepExecution.putInt("name", lineNumber);
    // rest of your code..
  }
}

您还可以查看ItemCountAware接口;不是完全一样的事情,但(也许)可以对你的需要有用。

 类似资料:
  • 问题内容: 我需要一个tasklet,将所有文件存储在arraylist目录中。列表的大小存储在作业执行上下文中。稍后,可以在另一个步骤中从另一个Tasklet访问此计数。它是如何做到的。我试图将其存储在jobexecution上下文中,在运行时抛出无法修改的集合异常, 还在步骤注释中存储了步骤执行参考。仍然无法实现。请让我知道如何在两个小任务之间共享数据。 问题答案: 你至少有4种可能性: 使用

  • 在处理基于浏览器的应用程序时,关于安全存储JWT令牌的主题已经提出了很多问题。大家一致认为,应该使用仅限http的安全cookie。然而,当涉及短期访问令牌和长期刷新令牌时,存储JWT令牌似乎存在许多变化。 我发现了以下变化: 1.仅将JWT访问令牌和刷新令牌存储在http安全cookie中 赞成的意见: 无法从Javascript访问访问令牌和刷新令牌 欺骗: 引入CSRF漏洞,因此也必须添加C

  • 我需要从消费者内部访问saga存储库,以读取与正在消费的消息相关的saga的当前状态。 场景:我有一个外部服务,当这个服务使用来自传奇的事件时,我想看看传奇是否仍然处于正确的状态,因为如果同时传奇改变了状态,消费者必须跳过事件。 如何:我当然可以通过使用它的本机框架来查询选择的saga存储库实现,但是我想使用一个抽象,一个接口,从消费者内部加载saga状态,以便将来能够切换到不同的存储库实现。 感

  • 我正试图实现一些清理工具。越来越多的制造商出于某种“安全原因”禁止根设备,禁止不请求解锁。 在API28之后,这段代码将出现错误: 但我相信将来会被杀的。 那么,有什么优雅的方法来管理SDCard吗?

  • 对于vue-axios auth by api_token,我使用助手文件api.js。

  • 问题内容: 我只是做一个简单的应用程序来学习与redux异步。我已经使所有工作正常进行,现在我只想在网页上显示实际状态。现在,我实际上如何在render方法中访问商店的状态? 这是我的代码(所有内容都在一页中,因为我只是在学习): 因此,在状态的render方法中,我想列出商店中的所有内容。 谢谢 问题答案: 您应该创建单独的组件,该组件将侦听状态更改并在每次状态更改时进行更新: