2017-04-07 89 views
1

我目前有一個應用程序,我試圖診斷什麼在我做了不正確的設置,並沒有任何運氣,以確定爲什麼它不工作以外的非常具體情況。當從自定義項目讀取器訪問FlatFileItemReader

首先我正在使用的代碼。

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模式,還是有它,所以它的配置文件中,它工作正常。然而,我無法弄清楚如何在這些配置中使用作業和步驟上下文(構造函數在您可以訪問步驟和jobContext之前執行,它似乎來自於我的測試,並且在放入Config類時我永遠不會知道如何訪問)。此外,至少對於我來說,讓它自己的文件中的Reader代碼不會塞入構造函數中看起來更乾淨。

所以簡而言之,有沒有一種方法可以解決這個問題,讓它在自己的閱讀器類中工作?我是否做得不正確,並使用不好的做法?也許是兩者的混合?如果有什麼遺漏,請詢問,我會嘗試澄清。

+0

您的閱讀器返回'ItemReader ',因爲它應該在委託項讀取器上調用read方法並返回'YourObject'。讀取方法的全部目的是返回實際的對象而不是潛在的項目讀取器。 –

+0

'LCBOStoreReader.read()'可能會返回'LCBOStore',而不是'ItemReader' ... – OhadR

+0

知道這將是簡單的事情,閱讀功能正在按預期工作,只爲根csvParser類,沒有一個自動方式來讀取。無論哪種方式,感謝您的支持,它幫助我找到了解決方案。 – canadiancreed

回答

0

因此,我發現答案很簡單,在評論中提供了一些幫助。這是我的解決方案。

首先,粗體顯示的代碼添加到抽象類createCSVWriter方法

**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();** 
} 

手工完成的讀取調用將阻止其返回更多的則需要爲您的讀取器類。然後在讀者類中編輯以下內容

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

    return createCSVReader(classType, currentCSVFilePath, inventoryTrackerProperties.getLCBOFilPropertiess().getStores()); 
} 

這只是返回您創建的對象並因此問題解決。