从自定义ItemReader

时间:2017-04-07 04:46:11

标签: java spring spring-batch

我目前有一个应用程序,我试图诊断设置中我做错了什么,并且没有运气确定为什么它不能在非常具体的情况下工作

首先是我正在使用的代码。

Configuration.java

@EnableBatchProcessing
@SpringBootApplication(scanBasePackages="com.lcbo")
@EnableIntegration
public class COnfig {

    @Autowired
    private JobBuilderFactory jobBuilderFactory;

    @Autowired
    private StepBuilderFactory stepBuilderFactory;

    @Autowired
    private LCBOInventoryTrackerProperties inventoryTrackerProperties;

    @Bean
    public Job processLCBOInventory(@Qualifier("getLCBOStoreDataStep") final Step getLCBOStoreDataStep) {
        return jobBuilderFactory
                .get("processLCBOInventory")
                .incrementer(new RunIdIncrementer())
                .start(getLCBOStoreDataStep)
                .build();

    }

    /**
     * This tasklet downloads the .zip file, unzips, and saves it in the appropriate folder under resources.
     * Execute at 6am daily
     *
     //     * @param AcquireDataFileTasklet acquireDataFiles
     * @return Step - returns Step status; either SUCCESS or FAILURE
     */

    @Bean
    public Step getCurrentLCBODataStep(final AcquireDataFileTasklet acquireDataFiles,
                                       final ExecutionContextPromotionListener listener) {
        return stepBuilderFactory
                .get("getCurrentLCBODataStep")
                .tasklet(acquireDataFiles)
                .allowStartIfComplete(true)
                .listener(listener)
                .build();
    }

    @Bean
    public Step getLCBOStoreDataStep(final LCBOStoreReader lcboStoreReader,
                                     final LCBOStoreWriter lcboStoreWriter) {

        return stepBuilderFactory
                .get("getLCBOStoreDataStep")
                .<LCBOStore, LCBOStore>chunk(inventoryTrackerProperties.getDefaults().getChunkSize())
                .reader(lcboStoreReader)
                .writer(lcboStoreWriter)
                .build();
    }
}

读者类

@Component
public class LCBOStoreReader extends AbstractLCBOReader implements ItemReader, InterstepDataRetriever {

    private static final Logger log = LoggerFactory.getLogger(LCBOStoreReader.class);

    @Override
    public ItemReader<LCBOStore> read() throws UnexpectedInputException, ParseException, NonTransientResourceException {
        Class<LCBOStore> classType = LCBOStore.class;

        return createCSVReader(classType, currentCSVFilePath, inventoryTrackerProperties.getLCBOFilPropertiess().getStores());
    }
/*
    @Override
    public void beforeStep(final StepExecution stepExecution) {
        JobExecution jobExecution = stepExecution.getJobExecution();
        ExecutionContext jobContext = jobExecution.getExecutionContext();
        this.currentWorkingDate = (String) jobContext.get("currentWorkingDateKey");
    }
*/
    @Override
    public void retrieveInterstepDataFromJobContext(final ExecutionContext jobContext) {
        this.currentCSVFilePath = (String) jobContext.get("currentCSVFilePathKey");
    }
}

和它扩展的类(因为FlatFileItemReader设置被多个读者使用)

public abstract class AbstractLCBOReader {

    @Autowired
    protected LCBOInventoryTrackerProperties inventoryTrackerProperties;

    protected String currentCSVFilePathKey;
    protected String currentCSVFilePath;

    private static final Logger log = LoggerFactory.getLogger(AbstractLCBOReader.class);

    protected <T> ItemReader<T> createCSVReader(final Class<T> classType,
                                                 final String currentCSVFilePath,
                                                 final LCBOFileDetailsProperties properties) {

        FlatFileItemReader<T> reader = new FlatFileItemReader<>();
        // Skip a line to ignore the header information in these files
        reader.setLinesToSkip(properties.getNumberOfLinesToSkipInFile());
        reader.setResource(new FileSystemResource(currentCSVFilePath + File.separator + properties.getFileName()));
        reader.setLineMapper(createLineMapper(classType, properties));
        reader.setRecordSeparatorPolicy(new DefaultRecordSeparatorPolicy());
        reader.setEncoding("utf8");

        return reader;
    }

    private <T> LineMapper<T> createLineMapper(final Class<T> classType, final LCBOFileProperties.LCBOFileDetailsProperties properties) {
        DefaultLineMapper<T> lineMapper = new DefaultLineMapper<>();
        lineMapper.setLineTokenizer(createLineTokenizer(properties));
        lineMapper.setFieldSetMapper(createFieldSetMapper(classType));

        return lineMapper;
    }

    private <T> FieldSetMapper<T> createFieldSetMapper(final Class<T> classType) {
        BeanWrapperFieldSetMapper<T> fieldSetMapper = new BeanWrapperFieldSetMapper<>();
        fieldSetMapper.setTargetType(classType);

        return fieldSetMapper;
    }

    private LineTokenizer createLineTokenizer(final LCBOFileProperties.LCBOFileDetailsProperties properties) {
        LCBOFileProperties.Column[] columns = properties.getColumns();
        int[] columnIndexes = new int[columns.length];
        String[] columnNames = new String[columns.length];

        // populating the columnIndexes
        for (int i = 0; i < columns.length; i++) {
            columnIndexes[i] = columns[i].getColumnIndex();
            columnNames[i] = columns[i].getColumnName();
        }

        DelimitedLineTokenizer lineTokenizer = new DelimitedLineTokenizer();
        lineTokenizer.setIncludedFields(columnIndexes);
        lineTokenizer.setNames(columnNames);
        lineTokenizer.setDelimiter(",");
        lineTokenizer.setQuoteCharacter('"');

        return lineTokenizer;
    }
}

执行此操作时的错误是无法将对象从FlatFileItemreader强制转换为作为createCSVReader中第一个参数传递的对象。这是一个例子。

public class LCBOStore {

    private Long id;
    private String addressLineOne;
    private String addressLineTwo;
    private String city;
    private String postalCode;
    private String latitude;
    private String longitude;
    private String updatedAt; //Convert to Date

    public LCBOStore(final Long id, final String addressLineOne, final String addressLineTwo, final String city,
                     final String postalCode, final String latitude, final String longitude, final String updatedAt) {
        this.id = id;
        this.addressLineOne = addressLineOne;
        this.addressLineTwo = addressLineTwo;
        this.city = city;
        this.postalCode = postalCode;
        this.latitude = latitude;
        this.longitude = longitude;
        this.updatedAt = updatedAt;
    }

    public Long getId() {
        return id;
    }

    public String getAddressLineOne() {
        return addressLineOne;
    }

    public String getAddressLineTwo() {
        return addressLineTwo;
    }

    public String getCity() {
        return city;
    }

    public String getPostalCode() {
        return postalCode;
    }

    public String getLatitude() {
        return latitude;
    }

    public String getLongitude() {
        return longitude;
    }

    public String getUpdatedAt() {
        return updatedAt;
    }

    public void setId(final Long id) {
        this.id = id;
    }

    public void setAddressLineOne(final String addressLineOne) {
        this.addressLineOne = addressLineOne;
    }

    public void setAddressLineTwo(final String addressLineTwo) {
        this.addressLineTwo = addressLineTwo;
    }

    public void setCity(final String city) {
        this.city = city;
    }

    public void setPostalCode(final String postalCode) {
        this.postalCode = postalCode;
    }

    public void setLatitude(final String latitude) {
        this.latitude = latitude;
    }

    public void setLongitude(final String longitude) {
        this.longitude = longitude;
    }

    public void setUpdatedAt(final String updatedAt) {
        this.updatedAt = updatedAt;
    }

    @Override
    public String toString() {
        return "StoreDBModel [id=" + id + ", addressLineOne=" + addressLineOne + ", city=" + city 
                + ", postalCode=" + postalCode + ", latitude=" + latitude + ", longitude="
                + longitude + ", updatedAt=" + updatedAt + "]";
    }
}

现在,如果我将createCSVReader中存在的FlatFileItemReader模式移动到自定义Reader类的构造函数中,或者将它放在配置文件中,那么它可以正常工作。但是,我无法弄清楚如何在这些配置中使用作业和步骤上下文(构造函数在您可以访问step和jobContext之前执行它似乎来自我的测试,并且我无法确定如何在放入配置类。)。至少对我而言,将Reader代码放入构造函数中并没有填充它看起来更清晰。

所以简而言之,有没有办法解决这个问题,在其中拥有它自己的读者类会起作用?我这样做是错误的,并使用不良做法?也许是两者的混合?如果有任何遗漏,请随便提出,我将尝试澄清。

1 个答案:

答案 0 :(得分:0)

所以我发现答案非常简单,并在评论中提供了一些帮助。这是我的解决方案。

首先,将粗体代码添加到抽象类createCSVWriter方法

getPair id 8.9 => (8.9, 1.0)
getPair (\x -> x > 0) (-9.8) => (False, True)

手动执行读取调用将阻止它返回读取器类所需的内容。然后在阅读器类中编辑以下

**protected <T> T** createCSVReader(final Class<T> classType,
                                final String currentCSVFilePath,
                                final LCBOFileDetailsProperties properties) throws Exception {

    FlatFileItemReader<T> reader = new FlatFileItemReader<>();
    // Skip a line to ignore the header information in these files
    reader.setLinesToSkip(properties.getNumberOfLinesToSkipInFile());
    reader.setResource(new FileSystemResource(currentCSVFilePath + File.separator + properties.getFileName()));
    reader.setLineMapper(createLineMapper(classType, properties));
    reader.setRecordSeparatorPolicy(new DefaultRecordSeparatorPolicy());
    reader.setEncoding("utf8");

    **return reader.read();**
}

这只会返回您已创建的对象,从而解决问题。