Reading CSV file with Spring batch and map to Domain objects based on the the first field then inserting in DB tables

北城以北 提交于 2020-01-06 06:18:45

问题


I can read and insert in the DB if the csv file has only lines starting with ORD but if the file is showing as below, mixed with different rows, I can do the mapping but the problem is what I'm using with the type of object for the chunk, as it takes one type of class.

I want to map each row and then accordingly insert into the DB based on the first three characters, if the row starts with ORD then insert in Order table if starts with DET then insert in Detail table, my coding below show where I have reached so far, is there any help that you can further provide me please

Note that file structure is always showing orders then items related to this order.

Here is the csv file format:

ORD,02013872,12345,,P,,,HYD800,,,,,
DET,1.0,100,5.0,,31Jan2017,,,,,
DET,2.0,120001,10.0,,25Jan2017,,,,,
ORD,02013872,12345,,P,,,HYD800,,,,,
DET,1.0,100,5.0,,31Jan2017,,,,,
DET,2.0,120001,10.0,,25Jan2017,,,,,
ORD,02013872,12345,,P,,,HYD800,,,,,
DET,1.0,100,5.0,,31Jan2017,,,,,
DET,2.0,120001,10.0,,25Jan2017,,,,,

Here is the code that I have so far:

@Entity
public class OrderDetail {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String branchCode;
private String ord;
private String eiclientNumber;
private String clientOrderNumber;
private String consigneeP;
private String paymentTerms;
private String earliestShipDate;
private String latestShipDate;
private String consigneeCode;
private String billToCode;
private String thirdPartyBillToCustomerNo;
private String preferredCarrier;
private String usd1;
private String usd2;

@ManyToMany(mappedBy = "orderDetails")
private Set<ItemDetail>  itemDetails = new HashSet<>();
}

@Entity
public class ItemDetail {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String branchCode;
private String ordNo;
private String detail;
private String lineNumber;
private String skuNumber;
private String qty;
private String lotNo;
private String receiptPo;
private String usd1;
private String usd2;
private String usd3;
private String usd4;


@ManyToMany
@JoinTable(name = "order_item", joinColumns = @JoinColumn(name = "item_id"), 
inverseJoinColumns = @JoinColumn(name = "order_id"))
private Set<OrderDetail> orderDetails = new HashSet<>();
}

@Configuration
@EnableBatchProcessing
public class BatchConfig {

@Autowired
private JobBuilderFactory jobBuilderFactory;
@Autowired
private StepBuilderFactory stepBuilderFactory;

@Bean
public Step sampleStep(JdbcBatchItemWriter<OrderDetail> writer) throws Exception {

    return stepBuilderFactory.get("sampleStep")
            .<OrderDetail,OrderDetail>chunk(5)
            .reader(reader(null))
            .writer(writer)
            .build();
}

@Bean
public Job importUserJob(JobCompletionNotificationListener listener, Step sampleStep) {
    return jobBuilderFactory.get("orderJob")
            .incrementer(new RunIdIncrementer())
            .listener(listener)
            .flow(sampleStep)
            .end()
            .build();
}

@Bean
@StepScope
public JdbcBatchItemWriter<OrderDetail> writer(DataSource dataSource,@Value("#{jobParameters[file_path]}") String filePath) {

    final FileSystemResource fileResource = new FileSystemResource(filePath);

    System.out.println("Branch code is : " + fileResource.getFilename().substring(5,8)); //getting the branch code from the path to insert it in table order details
    String branchCode = fileResource.getFilename().substring(5,8);

    return new JdbcBatchItemWriterBuilder<OrderDetail>()
             .itemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<>())
            .sql("INSERT INTO order_detail (ord, branch_code, eiclient_number, client_order_number, consigneep, payment_terms, earliest_ship_date, latest_ship_date, consignee_code, bill_to_code, third_party_bill_to_customer_no, preferred_carrier, usd1, usd2) " +
                    "VALUES (:ord, '"+branchCode+"', :eiclientNumber, :clientOrderNumber, :consigneeP, :paymentTerms, :earliestShipDate, :latestShipDate, :consigneeCode, :billToCode, :thirdPartyBillToCustomerNo, :preferredCarrier, :usd1, :usd2)")
           /* .sql("INSERT INTO item_detail (ord_no, branch_code, detail, line_number, sku_number, qty, lot_no, receipt_po, usd1, usd2, usd3, usd4) " +
                    "VALUES (:ordNo, '"+branchCode+"', :detail, :lineNumber, :skuNumber, :qty, :lotNo, :receiptPo, :usd1, :usd2, :usd3, :usd4)")
*/
            .dataSource(dataSource)
            .build();

}

@Bean
@StepScope
public FlatFileItemReader reader(@Value("#{jobParameters[file_path]}") String filePath) throws Exception {

    final FileSystemResource fileResource = new FileSystemResource(filePath);
    return new FlatFileItemReaderBuilder()
            .name("ordersItemReader")
            .resource(fileResource)
            .lineMapper(orderLineMapper())
            /*.delimited()
            .names(new String[]{"ord", "branchCode", "eiclientNumber", "clientOrderNumber", "consigneeP", "paymentTerms", "earliestShipDate", "latestShipDate", "consigneeCode", "billToCode", "thirdPartyBillToCustomerNo"})
            .fieldSetMapper(new BeanWrapperFieldSetMapper<OrderDetail>() {{
                setTargetType(OrderDetail.class);
            }})*/
            .build();
}


@Bean
public LineMapper orderLineMapper() throws Exception {

    PatternMatchingCompositeLineMapper mapper = new PatternMatchingCompositeLineMapper();

    Map<String, LineTokenizer> tokenizers = new HashMap<String, LineTokenizer>();
    tokenizers.put("ORD*",orderTokenizer() );
    tokenizers.put("DET*",orderItemTokenizer());
    mapper.setTokenizers(tokenizers);

    Map<String, FieldSetMapper> mappers = new HashMap<String, FieldSetMapper>();
    mappers.put("ORD*", orderFieldSetMapper());
    mappers.put("DET*", orderLineFieldSetMapper());

    mapper.setFieldSetMappers(mappers);

    return mapper;

}


@Bean
public LineTokenizer orderTokenizer() {
    DelimitedLineTokenizer tokenizer = new DelimitedLineTokenizer(",");
    tokenizer.setNames(new String[] { "ord", "eiclientNumber", "clientOrderNumber", "consigneeP", "paymentTerms", "earliestShipDate", "latestShipDate", "consigneeCode", "billToCode", "thirdPartyBillToCustomerNo", "preferredCarrier", "usd1","usd2"});
    return tokenizer;
}

@Bean
public LineTokenizer orderItemTokenizer() {
    DelimitedLineTokenizer tokenizer = new DelimitedLineTokenizer(",");
    tokenizer.setNames(new String[] { "ordNo", "detail", "lineNumber", "skuNumber", "qty", "lotNo", "receiptPo", "usd1", "usd2", "usd3", "usd4"});
    return tokenizer;
}

@Bean
public FieldSetMapper<OrderDetail> orderFieldSetMapper() throws Exception {
    BeanWrapperFieldSetMapper<OrderDetail> mapper =
            new BeanWrapperFieldSetMapper<OrderDetail>();

    mapper.setPrototypeBeanName("orderDetail");
    mapper.afterPropertiesSet();
    return mapper;
}


@Bean
@Scope("prototype")
public OrderDetail orderDetail() {
    return new OrderDetail();
}

}

来源:https://stackoverflow.com/questions/57557032/reading-csv-file-with-spring-batch-and-map-to-domain-objects-based-on-the-the-fi

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!