如何使用springbatch将日期格式的文件中的日期以字符串形式保存在db中?

时间:2019-05-19 08:20:25

标签: spring-boot spring-batch

我正在使用Spring Batch将文件中的数据保存到远程服务器上,该文件已从远程服务器下载到本地目录中。此文件中的一个字段具有字符串格式的日期。

我的应用程序运行时,它给我一个错误,在异常消息中指出typeMismatch

这是我用来设置读取器/写入器的配置类:

package com.vsi.jobs.itemsubstitutionforoutofstock.batch.steps;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.database.JdbcBatchItemWriter;
import org.springframework.batch.item.database.builder.JdbcBatchItemWriterBuilder;
import org.springframework.batch.item.file.FlatFileParseException;
import org.springframework.batch.item.file.builder.FlatFileItemReaderBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;

import com.vsi.jobs.itemsubstitutionforoutofstock.config.AppConfig;
import com.vsi.jobs.itemsubstitutionforoutofstock.constants.ItemSubstitutionForOutOfStockConstants;
import com.vsi.jobs.itemsubstitutionforoutofstock.model.oracle.VSOGOutOfStockSkuData;
import com.vsi.jobs.itemsubstitutionforoutofstock.model.oracle.VSOGOutOfStockSkuDataForBatchJob;
import javax.sql.DataSource;
import static com.vsi.jobs.itemsubstitutionforoutofstock.config.LoggerConfig.logInfo;
import java.sql.Date;
import java.text.SimpleDateFormat;
import static com.vsi.jobs.itemsubstitutionforoutofstock.config.LoggerConfig.logError;

@Configuration
@Lazy
public class BatchStepConfig {
    private static final Logger log =
        LoggerFactory.getLogger(ItemSubstitutionForOutOfStockConstants.PROCESS_LOG);
    private final String className = getClass().getSimpleName();

    @Autowired
    private AppConfig appConfig;

    /**
     *  The below bean is used to insert data into the table -
VS_OG_OUT_OF_STOCK_SKU_DATA

     * @param ds
     * @return
     */

    @Bean
    public JdbcBatchItemWriter<VSOGOutOfStockSkuDataForBatchJob>
        jdbcWriter(DataSource ds) {
                logInfo(log, className +" : jdbcWriter : Starts");
                        return new
        JdbcBatchItemWriterBuilder<VSOGOutOfStockSkuDataForBatchJob>()
                        .dataSource(ds)
                        .sql("insert into
        VS_OG_OUT_OF_STOCK_SKU_DATA(id, profile_id, next_order_date, sku_id,frequency, quantity) values
        (OG_OUT_OF_STOCK_SKU_sequence.NEXTVAL, :merchantUserId, :placeDate, :sku, :fre
        quencyDays,:orderQuantity)")
                        .beanMapped()
                        .build();
    }

    /**
     * @Lazy annotation for ItemReader is used because of cyclic
dependency *exception
     * @param ir
     * @return
     */
    @Bean
    public ItemReader<VSOGOutOfStockSkuDataForBatchJob> fileReader(@Lazy
        ItemReader<VSOGOutOfStockSkuDataForBatchJob> ir) {
                logInfo(log, className +" : fileReader : Starts");
                logInfo(log, className + " : batchProcessingFile :
                        "+appConfig.getBatchProcessingFile());
                Resource resource = new
                    FileSystemResource(appConfig.getBatchProcessingFile());
                try {
                    return new
                        FlatFileItemReaderBuilder<VSOGOutOfStockSkuDataForBatchJob>()
                                            .name("file-reader")
                                            .resource(resource)
                                            .targetType(VSOGOutOfStockSkuDataForBatchJob.class)
                                            .linesToSkip(1)
                                            .delimited().delimiter(",").names(new String[]
                        {"Merchant User ID", "Email Address", "Place Date", "Discount Price", "Frequency Days", "In Stock", "Product Name", "SKU", "Order Quantity", "Total Subscriber Value"})
                                            .build();
                        }
                catch(FlatFileParseException ffpe) {
                    logError(log, className + " : FlatFileParseException occured
                             :"+ffpe);
                }
                return ir;
            }
        }

此外,我正在使用以下配置类来设置批处理配置步骤:

package com.vsi.jobs.itemsubstitutionforoutofstock.batch.steps;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.core.launch.support.SimpleJobLauncher;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean;
import org.springframework.batch.core.step.skip.SkipPolicy;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.support.transaction.ResourcelessTransactionManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.transaction.PlatformTransactionManager;
import com.vsi.jobs.itemsubstitutionforoutofstock.batch.skipper.FileVerificationSkipper;
import com.vsi.jobs.itemsubstitutionforoutofstock.config.AppConfig;
import com.vsi.jobs.itemsubstitutionforoutofstock.constants.ItemSubstitutionForOutOfStockConstants;
import com.vsi.jobs.itemsubstitutionforoutofstock.model.oracle.VSOGOutOfStockSkuDataForBatchJob;

import static com.vsi.jobs.itemsubstitutionforoutofstock.config.LoggerConfig.logInfo;

/**
*  This class has declaration of required beans required to run batch process
* without creating JOB Repository.Also we declare the chunk size and declare bean of class which
* validates the lines of data in the file
* @author Sanjay Naik
*/
@Configuration
@EnableBatchProcessing
@Lazy
public class BatchJobProcessConfig {

    private static final Logger log = LoggerFactory.getLogger(ItemSubstitutionForOutOfStockConstants.PROCESS_LOG
);
    private final String className = getClass().getSimpleName();

    @Autowired
    private AppConfig appConfig;

    /**
    * Below beans-transactionManager,jobRepository,jobLauncher is required to make spring batch work
    * without creation of Job Repository.In the below Bean ResourcelessTransactionManager is first created as it is required to disable creation of JobRepository.
    * We are then downcasting it to PlatformTransactionManager as ResourcelessTransactionManager was blocking insertion,truncate from repository
    * @return
    */
    @Bean
    public PlatformTransactionManager platFormTransactionManager() {
        return new ResourcelessTransactionManager();
    }

    @Bean
    public JobRepository jobRepository(PlatformTransactionManager transactionManager) throws Exception {
        MapJobRepositoryFactoryBean mapJobRepositoryFactoryBean = new MapJobRepositoryFactoryBean(transactionManager);

        mapJobRepositoryFactoryBean.setTransactionManager(transactionManager);
        return mapJobRepositoryFactoryBean.getObject();
    }

    @Bean
    public SimpleJobLauncher jobLauncher(JobRepository jobRepository) {
        SimpleJobLauncher simpleJobLauncher = new SimpleJobLauncher();
        simpleJobLauncher.setJobRepository(jobRepository);
        return simpleJobLauncher;
    }

    @Bean
    public SkipPolicy fileVerificationSkipper() {
        return new FileVerificationSkipper();
    }

    @Bean
    Job job(JobBuilderFactory jbf,
            StepBuilderFactory sbf,
            ItemReader<VSOGOutOfStockSkuDataForBatchJob> ir,
            BatchStepConfig step1) {
        logInfo(log, className + " : Inside Job Bean : ");
        Step s1 = sbf.get("file-db")
                .<VSOGOutOfStockSkuDataForBatchJob, VSOGOutOfStockSkuDataForBatchJob>chunk(appConfig.getBatchSizeOfOGFeedData())
                .reader(step1.fileReader(ir)).faultTolerant()
                .writer(step1.jdbcWriter(null))
                .build();
        return jbf.get("etl")
                .incrementer(new RunIdIncrementer())
                .start(s1)
                .build();

    }
}

此外,这是我用来从文件中读取数据的类:

package com.vsi.jobs.itemsubstitutionforoutofstock.model.oracle;

import java.sql.Date;

import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import org.hibernate.annotations.GenericGenerator;

public class VSOGOutOfStockSkuDataForBatchJob {
    @Id
    @GeneratedValue(generator = "UUID")
    @GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator")
    @Column(name = "ID")
    private String id;

    @Column(name="PROFILE_ID")
    private String merchantUserId;

    private String emailAddress;

    @Column(name="NEXT_ORDER_DATE")
    private Date placeDate;

    private double discountPrice;

    @Column(name="FREQUENCY")
    private int frequencyDays;

    private boolean inStock;

    private String productName;

    @Column(name="SKU_ID")

    private String sku;

    @Column(name="QUANTITY")
    private int orderQuantity;

    private double totalSubscriberValue;

    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getMerchantUserId() {
        return merchantUserId;
    }
    public void setMerchantUserId(String merchantUserId) {
        this.merchantUserId = merchantUserId;
    }
    public String getEmailAddress() {
        return emailAddress;
    }
    public void setEmailAddress(String emailAddress) {
        this.emailAddress = emailAddress;
    }
    public Date getPlaceDate() {
        return placeDate;
    }
    public void setPlaceDate(Date placeDate) {
        this.placeDate = placeDate;
    }
    public double getDiscountPrice() {
        return discountPrice;
    }
    public void setDiscountPrice(double discountPrice) {
        this.discountPrice = discountPrice;
    }
    public int getFrequencyDays() {
        return frequencyDays;
    }
    public void setFrequencyDays(int frequencyDays) {
        this.frequencyDays = frequencyDays;
    }
    public boolean isInStock() {
        return inStock;
    }
    public void setInStock(boolean inStock) {
        this.inStock = inStock;
    }
    public String getProductName() {
        return productName;
    }
    public void setProductName(String productName) {
        this.productName = productName;
    }
    public String getSku() {
        return sku;
    }
    public void setSku(String sku) {
        this.sku = sku;
    }
    public int getOrderQuantity() {
        return orderQuantity;
    }
    public void setOrderQuantity(int orderQuantity) {
        this.orderQuantity = orderQuantity;
    }
    public double getTotalSubscriberValue() {
        return totalSubscriberValue;
    }
    public void setTotalSubscriberValue(double totalSubscriberValue) {
        this.totalSubscriberValue = totalSubscriberValue;
    }
}

这是我用来将数据保存到数据库的实体:

package com.vsi.jobs.itemsubstitutionforoutofstock.model.oracle;

import java.sql.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.validation.Valid;

import org.hibernate.annotations.GenericGenerator;

@Entity
@Table(name = "VS_OG_OUT_OF_STOCK_SKU_DATA")
public class VSOGOutOfStockSkuData {

    @Id
    @GeneratedValue(generator = "UUID")
    @GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator")
    @Column(name = "ID")
    private String id;


    @Column(name="PROFILE_ID")
    private String profileId;

    @Column(name="NEXT_ORDER_DATE")
    private Date placeDate;

    @Column(name="SKU_ID")
    private String skuId;

    @Column(name="FREQUENCY")

    private int frequency;

    @Column(name="QUANTITY")
    private int quantity;

    public String getId() {
        return id;

    }
    public void setId(String id) {
        this.id = id;
    }
    public String getProfileId() {

        return profileId;
    }

    public void setProfileId(String profileId) {
        this.profileId = profileId;
    }
    public Date getPlaceDate() {
        return placeDate;
    }
    public void setPlaceDate(Date placeDate) {
        this.placeDate = placeDate;
    }
    public String getSkuId() {
        return skuId;
    }
    public void setSkuId(String skuId) {
        this.skuId = skuId;
    }
    public int getFrequency() {
        return frequency;
    }
    public void setFrequency(int frequency) {
        this.frequency = frequency;
    }
    public int getQuantity() {
        return quantity;
    }
    public void setQuantity(int quantity) {
        this.quantity = quantity;
    }
    @Override
    public String toString() {
        return "VSOGOutOfStockSkuData {" +
                "id=" + id +
                ", profileId=" + profileId +
                ", placeDate=" + placeDate +
                ", skuId=" + skuId +
                ", frequency=" + frequency +
                ", quantity=" + quantity +
                "}";
    }
}

在运行时,我在日志中收到以下消息:

2019-05-19 13:28:25,823 [main] INFO  processlog - OGOutOfStockSkuDAO : BatchProcessingFile : archive/Vitamin_Shoppe_TotalSubscriberValue_Report_05192019201.csv
2019-05-19 13:28:25,825 [main] INFO  processlog - OGOutOfStockSkuDAO : initiateBatchJobRun : Starts
2019-05-19 13:28:25,845 [main] INFO  processlog - BatchStepConfig$$EnhancerBySpringCGLIB$$81e89aa3 : fileReader : Starts
2019-05-19 13:28:25,847 [main] INFO  processlog - BatchStepConfig$$EnhancerBySpringCGLIB$$81e89aa3 : batchProcessingFile : archive/Vitamin_Shoppe_TotalSubscriberValue_Report_05192019201.csv
2019-05-19 13:28:25,894 [main] INFO  processlog - BatchJobProcessConfig$$EnhancerBySpringCGLIB$$f0468489 : Inside Job Bean :
2019-05-19 13:28:25,919 [main] INFO  processlog - BatchStepConfig$$EnhancerBySpringCGLIB$$81e89aa3 : jdbcWriter : Starts
2019-05-19 13:28:26,320 [main] INFO  o.s.b.c.l.support.SimpleJobLauncher - Job: [SimpleJob: [name=etl]] launched with the following parameters: [{}]
2019-05-19 13:28:26,356 [main] INFO  o.s.batch.core.job.SimpleStepHandler - Executing step: [file-db]
2019-05-19 13:28:26,419 [main] ERROR o.s.batch.core.step.AbstractStep - Encountered an error executing step file-db in job etl
org.springframework.batch.core.step.skip.NonSkippableReadException: Non-skippable exception during read
        at org.springframework.batch.core.step.item.FaultTolerantChunkProvider.read(FaultTolerantChunkProvider.java:105)
        at org.springframework.batch.core.step.item.SimpleChunkProvider$1.doInIteration(SimpleChunkProvider.java:119)
        at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:375)
        at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:215)
        at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:145)
        at org.springframework.batch.core.step.item.SimpleChunkProvider.provide(SimpleChunkProvider.java:113)
        at org.springframework.batch.core.step.item.ChunkOrientedTasklet.execute(ChunkOrientedTasklet.java:69)
        at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:407)
        at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:331)
        at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140)
        at org.springframework.batch.core.step.tasklet.TaskletStep$2.doInChunkContext(TaskletStep.java:273)
        at org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:82)
        at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:375)
        at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:215)
        at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:145)
        at org.springframework.batch.core.step.tasklet.TaskletStep.doExecute(TaskletStep.java:258)
        at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:203)
        at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:148)
        at org.springframework.batch.core.job.AbstractJob.handleStep(AbstractJob.java:399)
        at org.springframework.batch.core.job.SimpleJob.doExecute(SimpleJob.java:135)
        at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:313)
        at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:144)
        at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:50)
        at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:137)
        at com.vsi.jobs.itemsubstitutionforoutofstock.dao.OGOutOfStockSkuDAO.initiateBatchJobRun(OGOutOfStockSkuDAO.java:168)
        at com.vsi.jobs.itemsubstitutionforoutofstock.dao.OGOutOfStockSkuDAO.populateOGOutOfStockDataForSuccessfulOGFile(OGOutOfStockSkuDAO.java:140)
        at com.vsi.jobs.itemsubstitutionforoutofstock.service.impl.OGOutOfStockSkuServiceImpl.createOGOutOfStockSkuData(OGOutOfStockSkuServiceImpl.java:249)
        at com.vsi.jobs.itemsubstitutionforoutofstock.service.impl.OGOutOfStockSkuServiceImpl.processFile(OGOutOfStockSkuServiceImpl.java:119)
        at com.vsi.jobs.itemsubstitutionforoutofstock.runner.ItemSubstitutionForOutOfStockJob.loadOGOutOfStockSkuJOB(ItemSubstitutionForOutOfStockJob.java:78)
        at com.vsi.jobs.itemsubstitutionforoutofstock.runner.ItemSubstitutionForOutOfStockJob.run(ItemSubstitutionForOutOfStockJob.java:44)
        at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:788)
        at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:778)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:335)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1255)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1243)
        at com.vsi.jobs.itemsubstitutionforoutofstock.ItemSubstitutionForOutOfStockApplication.main(ItemSubstitutionForOutOfStockApplication.java:19)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
        at java.lang.reflect.Method.invoke(Unknown Source)
        at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:48)
        at org.springframework.boot.loader.Launcher.launch(Launcher.java:87)
        at org.springframework.boot.loader.Launcher.launch(Launcher.java:50)
        at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:51)
Caused by: org.springframework.batch.item.file.FlatFileParseException: Parsing error at line: 2 in resource=[file [D:\Item_Substitution_For_Out_Of_Stock\codebase\Item_Substitution_For_Out_Of_Stock\archive\Vitamin_Shoppe_TotalSubscriberValue_Report_05192019201.csv]], input=["merchant_user_1","user1@email.com","2019-05-14","15.99","30","1","product_1","sku_1","2","200.50"]
        at org.springframework.batch.item.file.FlatFileItemReader.doRead(FlatFileItemReader.java:184)
        at org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader.read(AbstractItemCountingItemStreamItemReader.java:89)
        at org.springframework.batch.core.step.item.SimpleChunkProvider.doRead(SimpleChunkProvider.java:94)
        at org.springframework.batch.core.step.item.FaultTolerantChunkProvider.read(FaultTolerantChunkProvider.java:87)
        ... 43 common frames omitted
Caused by: org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors
Field error in object 'target' on field 'placeDate': rejected value [2019-05-14]; codes [typeMismatch.target.placeDate,typeMismatch.placeDate,typeMismatch.java.sql.Date,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [target.placeDate,placeDate]; arguments []; default message [placeDate]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'java.sql.Date' for property 'placeDate'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'java.sql.Date' for property 'placeDate': no matching editors or conversion strategy found]
        at org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper.mapFieldSet(BeanWrapperFieldSetMapper.java:200)
        at org.springframework.batch.item.file.mapping.DefaultLineMapper.mapLine(DefaultLineMapper.java:43)
        at org.springframework.batch.item.file.FlatFileItemReader.doRead(FlatFileItemReader.java:180)
        ... 46 common frames omitted
2019-05-19 13:28:26,446 [main] INFO  o.s.b.c.l.support.SimpleJobLauncher - Job: [SimpleJob: [name=etl]] completed with the following parameters: [{}] and the following status: [FAILED]
2019-05-19 13:28:26,448 [main] INFO  processlog - OGOutOfStockSkuDAO : initiateBatchJobRun : Ends
2019-05-19 13:28:26,467 [main] DEBUG org.hibernate.SQL - select vsogoutofs0_.audit_id as audit_id1_1_0_, vsogoutofs0_.audit_entry_date as audit_entry_date2_1_0_, vsogoutofs0_.failure_code as failure_code3_1_0_, vsogoutofs0_.failure_reason as failure_reason4_1_0_, vsogoutofs0_.file_name as file_name5_1_0_, vsogoutofs0_.status as status6_1_0_ from p_stgatgcomm.vs_og_out_of_stock_sku_audit vsogoutofs0_ where vsogoutofs0_.audit_id=?
2019-05-19 13:28:26,500 [main] DEBUG org.hibernate.SQL - insert into p_stgatgcomm.vs_og_out_of_stock_sku_audit (audit_entry_date, failure_code, failure_reason, file_name, status, audit_id) values (?, ?, ?, ?, ?, ?)
2019-05-19 13:28:26,509 [main] INFO  processlog - OGOutOfStockSkuDAO : populateOGInvDataForSuccessfulOGFile : OG inventory population in DB is complete
2019-05-19 13:28:26,510 [main] INFO  processlog - ItemSubstitutionForOutOfStockJob : loadOGOutOfStockSkuJOB : JOB Finished
2019-05-19 13:28:26,516 [Thread-7] INFO  o.s.c.a.AnnotationConfigApplicationContext - Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@22a71081: startup date [Sun May 19 13:27:50 IST 2019]; root of context hierarchy
2019-05-19 13:28:26,520 [Thread-7] INFO  o.s.c.s.DefaultLifecycleProcessor - Stopping beans in phase 0
2019-05-19 13:28:26,527 [Thread-7] INFO  o.s.i.endpoint.EventDrivenConsumer - Removing {logging-channel-adapter:_org.springframework.integration.errorLogger} as a subscriber to the 'errorChannel' channel
2019-05-19 13:28:26,527 [Thread-7] INFO  o.s.i.c.PublishSubscribeChannel - Channel 'application.errorChannel' has 0 subscriber(s).
2019-05-19 13:28:26,528 [Thread-7] INFO  o.s.i.endpoint.EventDrivenConsumer - stopped _org.springframework.integration.errorLogger
2019-05-19 13:28:26,532 [Thread-7] INFO  o.s.s.c.ThreadPoolTaskScheduler - Shutting down ExecutorService 'taskScheduler'
2019-05-19 13:28:26,533 [Thread-7] INFO  o.s.j.e.a.AnnotationMBeanExporter - Unregistering JMX-exposed beans on shutdown
2019-05-19 13:28:26,537 [Thread-7] INFO  o.s.j.e.a.AnnotationMBeanExporter - Unregistering JMX-exposed beans
2019-05-19 13:28:26,542 [Thread-7] INFO  o.s.o.j.LocalContainerEntityManagerFactoryBean - Closing JPA EntityManagerFactory for persistence unit 'default'
2019-05-19 13:28:26,545 [Thread-7] INFO  com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown initiated...
2019-05-19 13:28:26,578 [Thread-7] INFO  com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown completed.

2 个答案:

答案 0 :(得分:0)

您在此处配置的项目阅读器不正确:

.names(new String[]{"Merchant User ID","Email Address","Place Date","Discount Price","Frequency Days","In Stock","Product Name","SKU","Order Quantity","Total Subscriber Value"})

names属性应设置为目标类型VSOGOutOfStockSkuDataForBatchJob中的字段名称,例如:

.names(new String[]{"merchantUserId", "emailAddress", "placeDate"}); // TODO add other fields

答案 1 :(得分:0)

使用FlatFileItemReaderBuilder时,默认情况下它将使用DefaultLineMapperBeanWrapperFieldSetMapper正确地将一行从CSV文件映射到Java对象。

此映射器将无法将String转换为Date字段,因此它将引发您注意到的异常。

BeanWrapperFieldSetMapper具有允许自定义转换的机制。这可以通过创建自己的PropertyEditor来完成。例如:

public class DatePropertyEditor extends PropertyEditorSupport {
    private static final DateFormat FORMAT = new SimpleDateFormat("yyyy-MM-dd");
    @Override
    public void setAsText(String text) throws IllegalArgumentException {
        try {
            setValue(FORMAT.parse(text));
        } catch (ParseException e) {
            throw new IllegalArgumentException("Could not parse date", e);
        }
    }

    @Override
    public String getAsText() {
        return FORMAT.format((Date) getValue());
    }
}

此类可以将String转换为java.util.Date

最后一步是在PropertyEditor中注册FlatFileItemReaderBuilder

return new FlatFileItemReaderBuilder<VSOGOutOfStockSkuDataForBatchJob>()
    .name("file-reader")
    .resource(resource)
    .targetType(VSOGOutOfStockSkuDataForBatchJob.class)
    .linesToSkip(1)
    .delimited()
    .delimiter(",")
    .names(new String[] {"Merchant User ID","Email Address","Place Date","Discount Price","Frequency Days","In Stock","Product Name","SKU","Order Quantity","Total Subscriber Value"})
    // You should add something like this
    .customEditors(Collections.singletonMap(Date.class, new DatePropertyEditor())
    .build();

此外,“名称”字段应包含与Bean属性名称匹配的字符串数组,并按它们在CSV中的显示顺序排列。 Mahmoud也提到了这一点。

您的情况应该变成:

return new FlatFileItemReaderBuilder<VSOGOutOfStockSkuDataForBatchJob>()
    .name("file-reader")
    .resource(resource)
    .targetType(VSOGOutOfStockSkuDataForBatchJob.class)
    .linesToSkip(1)
    .delimited()
    .delimiter(",")
    // Fix names to match bean property names
    .names(new String[] {"merchantUserId","emailAddress","placeDate","discuntPrice","frequencyDays","inStock","productName","sku","orderQuantity","totalSubscriberValue"})
    // You should add something like this
    .customEditors(Collections.singletonMap(Date.class, new DatePropertyEditor())
    .build();