使用FlatFileItemReader读取csv文件,遇到空列时引发异常

时间:2019-09-29 09:33:04

标签: java spring-boot csv spring-batch

使用FlatFileItemReader读取csv文件时,列映射类型为Int,但csv文件中此列为null(例如:6321517,Jack, 1,,。最后两列为空)。 解析文件时会抛出异常(java.lang.NumberFormatException: Unparseable number

csv

CUSTR_NBR,SUR_NAME,CHECK_FLAG,RESN_CODE
6321517,Jack,1,,

首先解析第一行数据(CUSTR_NBR,SUR_NAME,CHECK_FLAG,RESN_CODE),因此我设置了.SetLinesToSkip(1)。但是,如果解析了空值,则无法正常执行相应的“ CHECK_FLAG”和“ RESN_CODE”。我相信有一个相应的配置项。我查看了springbatch的文档,找不到任何相关的配置项。

csvItemReader

    @Bean
    @StepScope
    public FlatFileItemReader<InfoDTO> csvItemReader() {
        FlatFileItemReader<InfoDTO> csvItemReader = new FlatFileItemReader<>();
        csvItemReader.setResource(new ClassPathResource("data/charge-off.csv"));
        csvItemReader.setLinesToSkip(1);

        DelimitedLineTokenizer tokenizer=new DelimitedLineTokenizer();
        String[] tokens = new String[]{"CUSTR_NBR","SUR_NAME","CHECK_FLAG","RESN_CODE","EMPNO"};
        tokenizer.setNames(tokens);
        DefaultLineMapper<InfoDTO> lineMapper=new DefaultLineMapper<InfoDTO>();
        lineMapper.setLineTokenizer(tokenizer);
        lineMapper.setFieldSetMapper(new InfoFileMapper());
        lineMapper.afterPropertiesSet();
        csvItemReader.setLineMapper(lineMapper);

        return csvItemReader;
    }

映射器

    public class InfoFileMapper implements FieldSetMapper<ChargeOffBatchDTO> {
        @Override
        public InfoDTO mapFieldSet(FieldSet fieldSet) throws BindException {

            if(fieldSet == null){
                return null;
            }

            return new InfoDTO(
                fieldSet.readString("CUSTR_NBR"),
                fieldSet.readString("SUR_NAME"),
                fieldSet.readString("CHECK_FLAG"),
                fieldSet.readInt("RESN_CODE"),
                fieldSet.readInt("EMPNO")
            );
        }
    }

我需要将null列映射为0值。如何配置?

2 个答案:

答案 0 :(得分:0)

我没有使用Spring Batch,但是看着FieldSet Interface specification,似乎有一些实现您想要的方法的替代方法。

Spring Batch reference确实提到了一些容错能力,特别是在不存在值的情况下引发异常。要禁用此功能,您需要将strict设置为false

tokenizer.setStrict(false);

否则,您可以尝试一些旧的替代方法,例如,而不是尝试将值直接读取到int中,而是将其读取为String,然后在将该String转换为{{1 }}

int

如果该字段不为空且不是字符串,您仍可能会得到String empNo = fieldSet.readString("EMPNO"); if ((empNo == null) || (empNo.equals(""))) { empNo = "0"; } int i = Integer.valueOf(empNo); ,因此我个人将通过处理异常来解决问题:

java.lang.NumberFormatException

也许不是那么有说服力,但它可以工作并达到目的。

答案 1 :(得分:0)

您可以创建自己的行映射器实现,并检查子字符串为空的子字符串,然后将其替换为零,并将行向前传递。