我正在使用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.
答案 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
时,默认情况下它将使用DefaultLineMapper
和BeanWrapperFieldSetMapper
正确地将一行从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();