将标头值从文件提升到作业执行上下文

时间:2014-09-17 18:35:27

标签: java spring spring-batch

我有一个文件,其中第一行包含字段名称作为标题,如下所示:

Id;ToyName;ToyType;ToyColor
1;abc;abc;red
2;pqr;pqr;blue
3;xyz;xyz;orange

我的读者如下:

<beans:bean id="MyFileItemReader" class="org.springframework.batch.item.file.FlatFileItemReader" scope="step">
<beans:property name="linesToSkip" value="1"/>
<beans:property name="skippedLinesCallback" ref="headerSkipCallback" />
<beans:property name="resource" ref="MyInputFileResource" />
<beans:property name="lineMapper">
            <beans:bean class="org.springframework.batch.item.file.mapping.DefaultLineMapper">
                <beans:property name="lineTokenizer">
                    <beans:bean class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer">
                            <beans:property name="delimiter" value=";"/>
                            <beans:property name="names" value="#{jobExecutionContext['columnsFromFileHeader']}" />
                    </beans:bean>
                </beans:property>
                <beans:property name="fieldSetMapper">
                    <beans:bean class="mypackage.MyFieldSetMapper">
                    </beans:bean>
                </beans:property> 
            </beans:bean>
    </beans:property> 
</beans:bean>

因此,我实现了一个标题行回调,以读取跳过的标题行。

<beans:bean id="headerSkipCallback" class="mypackage.HeaderLineHandler" scope="step">
</beans:bean>

和班级:

public class HeaderLineHandler implements LineCallbackHandler {
  public void handleLine(final String headerLine) { 
           System.out.println(headerLine);
}}

这样可以正常工作,并打印文件中的标题行。

现在我想在names

DefaultLineTokenizer属性中使用文件头中的这些字段名称

因此,为了将标题行放在上下文中,我实现了一个上下文注入类,如下所示:

public class StepExecutionListenerCtxInjector {

    private ExecutionContext stepExecutionCtx;
    private ExecutionContext jobExecutionCtx;

    @BeforeStep
    public void beforeStep(final StepExecution stepExecution) {
        this.stepExecutionCtx = stepExecution.getExecutionContext();
        this.jobExecutionCtx = stepExecution.getJobExecution().getExecutionContext();
    }


    public ExecutionContext getStepExecutionCtx() {
        return this.stepExecutionCtx;
    }

    public ExecutionContext getJobExecutionCtx() {
        return this.jobExecutionCtx;
    }
}

并将我的标题行处理程序更改为:

<beans:bean id="headerSkipCallback" class="mypackage.HeaderLineHandler" scope="step">
    <beans:property name="stepExecutionListener" ref="stepExecutionListener" />
</beans:bean>

和班级:

public class HeaderLineHandler implements LineCallbackHandler {

private StepExecutionListenerCtxInjector stepExecutionListener;
public void handleLine(final String headerLine) {

           this.stepExecutionListener.getJobExecutionCtx().put("columnsFromFileHeader", headerLine.replaceAll(";", ","));
}

// getter setters
}

这里我将标题行保存为作业执行上下文中的columnsFromFile键。

但是,当我尝试在DefaultLineTokenizer中访问它时:

<beans:property name="names" value="#{jobExecutionContext['columnsFromFileHeader']}" />

我得到空指针异常:

org.springframework.batch.item.file.FlatFileParseException: Parsing error at line: 2 in resource=[file [C:\myFile.dat]], input=[1;abc;abc;red]
at org.springframework.batch.item.file.FlatFileItemReader.doRead(FlatFileItemReader.java:182)

Caused by: 
java.lang.NullPointerException
at org.springframework.batch.item.file.transform.AbstractLineTokenizer.tokenize(AbstractLineTokenizer.java:113) 

如何将属性中文件的标题行用于DefaultLineTokenizer

1 个答案:

答案 0 :(得分:0)

DelimitedLineTokenizer设为非匿名bean并将其注入HeaderLineHandler;在HeaderLineHandler.handleLine()使用DelimitedLineTokenizer.names输入参数设置handleLine() 我无法测试它,但应该可行。