使用MultiResourceItemReader

时间:2016-01-13 13:06:45

标签: spring spring-batch

用例: 我想推出一个以员工ID作为工作参数的工作,这将是多个员工ID。 在文件系统中,文件将驻留,其中包含员工ID作为文件名的一部分(它是远程文件系统,而不是本地) 我需要处理文件名包含employee-id的文件并将其传递给阅读器。

我正在考虑使用MultiResourceItemReader,但我很困惑如何将文件名与文件系统中的Employee Id(作业参数)进行匹配。

请建议。

2 个答案:

答案 0 :(得分:1)

MultiResourceItemReader有一个方法setResources(Resources[] resources),它允许您指定要使用显式列表或通配符表达式(或两者)读取的资源。

示例(显式列表):

<bean class="org.springframework.batch.item.file.MultiResourceItemReader">
    <property name="resources">
        <list>
             <value>file:C:/myFiles/employee-1.csv</value>
             <value>file:C:/myFiles/employee-2.csv</value>
        </list>
    </property>
</bean>

示例(通配符):

<bean class="org.springframework.batch.item.file.MultiResourceItemReader">
    <property name="resources" value="file:C:/myFiles/employee-*.csv" />
</bean>

如您所知,您可以使用#{jobParameters['key']}

在配置中使用作业参数
<bean class="org.springframework.batch.item.file.MultiResourceItemReader">
    <property name="resources" value="file:C:/myFiles/employee-#{jobParameters['id']}.csv" />
</bean>

不幸的是,通配符表达式无法通过分隔符(id1,id2,id3 ...)管理值列表上的OR表达式。而且我猜你不知道你有多少不同的值要声明一个带有预定数量变量的显式列表。

然而,一个可行的解决方案是使用Spring Batch的Loop机制和经典FlatFileItemReader。原则基本上是将最后一步的next=""设置为第一步,直到您用完所有要阅读的项目为止。如果需要,我将提供代码示例。

修改

假设您有一个块可以一次读取一个文件。首先,您需要将来自job参数的当前id放在上下文中,以便将其传递给读者。

public class ParametersManagerTasklet implements Tasklet, StepExecutionListener {

    private Integer count = 0;
    private Boolean repeat = true;

    @Override
    public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {

        // Get job parameter and split
        String[] ids = chunkContext.getStepContext().getJobParameters().getString(PARAMETER_KEY).split(DELIMITER); 
        // Check for end of list
        if (count >= ids.length) {
            // Stop loop
            repeat = false;
        } else {
            // Save current id and increment counter
            chunkContext.getStepContext().getJobExecutionContext().put(CURRENT_ID_KEY, ids[count++]; 
        }
    }

    @Override
    public ExitStatus afterStep(StepExecution stepExecution) {

        if (!repeat) {
            return new ExitStatus("FINISHED");
        } else {
            return new ExitStatus("CONTINUE");
        }
    }
}

现在,您在XML中声明此步骤并创建一个循环:

<batch:step id="ParametersStep">
    <batch:tasklet>
        <bean class="xx.xx.xx.ParametersManagerTasklet" />
    </batch:tasklet>
    <batch:next on="CONTINUE" to="ReadStep" />
    <batch:end on="FINISHED" />
</batch:step>

<batch:step id="ReadStep">
    <batch:tasklet>
        <batch:chunk commit-interval="10">
            <batch:reader>
                <bean class="org.springframework.batch.item.file.MultiResourceItemReader">
                    <property name="resources" value="file:C:/myFiles/employee-#{jobExecutionContext[CURRENT_ID_KEY]}.csv" />
                </bean>
            </batch:reader>
            <batch:writer>
            </batch:writer>
        </batch:chunk>
    </batch:tasklet>
    <batch:next on="*" to="ParametersStep" />
</batch:step>

答案 1 :(得分:1)

您可以编写自己的FactoryBean来执行自定义资源搜索。

public class ResourcesFactoryBean extends AbstractFactoryBean<Resource[]> {
    String[] ids;
    String path;

    public void setIds(String[] ids) {
        this.ids = ids;
    }

    public void setPath(String path) {
        this.path = path;
    }

    @Override
    protected Resource[] createInstance() throws Exception {
        final List<Resource> l = new ArrayList<Resource>();
        final PathMatchingResourcePatternResolver x = new PathMatchingResourcePatternResolver();
        for(final String id : ids)
        {
            final String p = String.format(path, id);
            l.addAll(Arrays.asList(x.getResources(p)));
        }
        return l.toArray(new Resource[l.size()]);
    }

    @Override
    public Class<?> getObjectType() {
        return Resource[].class;
    }
}

---

<bean id="reader" class="org.springframework.batch.item.file.MultiResourceItemReader" scope="step">
  <property name="delegate" ref="itemReader" />
    <property name="resources">
      <bean class="ResourcesFactoryBean">
        <property name="path"><value>file:C:/myFiles/employee-%s.cvs</value>    </property>
        <property name="ids">
          <value>#{jobParameters['id']}</value>
        </property>
      </bean>
   </property>
</bean>

jobParameter 'id'是以逗号分隔的ID列表。