You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Batch使用FlatFileItemWriter导出CSV列异常求助

Spring Batch FlatFileItemWriter导出CSV数据全在同一列的解决方法

问题排查与修复步骤

1. 检查属性名称与Test类的匹配性

BeanWrapperFieldExtractor的setNames方法传入的属性名必须与Test类的实际属性名(或getter方法对应的属性名)完全一致。Java中通常属性名采用小驼峰命名(比如id而非Id),如果你的Test类属性是:

public class Test {
    private Long id;
    private String typeTest1;
    private String typeTest2;

    // 对应的getter方法:getId(), getTypeTest1(), getTypeTest2()
}

那setNames应该改为:

beanWrapperFieldExtractor.setNames(new String[] {"id", "typeTest1", "typeTest2"});

(注意首字母小写,BeanWrapper会自动匹配对应的getter方法)

2. 添加表头配置(解决表头也在同一列的问题)

如果需要导出表头,需要给FlatFileItemWriter设置HeaderCallback,用同样的分隔符生成表头行:

flatFileItemWriter.setHeaderCallback(writer -> {
    DelimitedLineAggregator<String> headerAggregator = new DelimitedLineAggregator<>();
    headerAggregator.setDelimiter(",");
    headerAggregator.setFieldExtractor(items -> items);
    writer.write(headerAggregator.aggregate(new String[] {"ID", "TypeTest1", "TypeTest2"}));
});

3. 完善FlatFileItemWriter的初始化(可选但推荐)

使用FlatFileItemWriterBuilder可以让配置更清晰,避免手动调用open/write/close时的潜在问题:

public FlatFileItemWriter<Test> writeFile(List<Test> tests) throws Exception {
    FlatFileItemWriter<Test> flatFileItemWriter = new FlatFileItemWriterBuilder<Test>()
            .resource(new FileSystemResource("/data/outputData.csv"))
            .lineAggregator(getDelimitedLineAggregator())
            .headerCallback(writer -> {
                DelimitedLineAggregator<String> headerAggregator = new DelimitedLineAggregator<>();
                headerAggregator.setDelimiter(",");
                headerAggregator.setFieldExtractor(items -> items);
                writer.write(headerAggregator.aggregate(new String[] {"ID", "TypeTest1", "TypeTest2"}));
            })
            .append(false) // 覆盖原有文件,若需要追加设为true
            .build();

    flatFileItemWriter.open(new ExecutionContext());
    flatFileItemWriter.write(tests);
    flatFileItemWriter.close();

    return flatFileItemWriter;
}

4. 验证分隔符是否生效

确保没有其他代码修改了分隔符,比如如果CSV查看工具(比如Excel)默认的分隔符不是逗号,可能会显示在同一列。可以用文本编辑器打开导出的CSV文件,确认每行数据是否用逗号分隔开:

ID,TypeTest1,TypeTest2
1,value1,value2
2,value3,value4

如果文本里是正确分隔的,那只是查看工具的设置问题,调整工具的分隔符即可。


完整修正后的代码示例

import org.springframework.batch.item.file.FlatFileItemWriter;
import org.springframework.batch.item.file.builder.FlatFileItemWriterBuilder;
import org.springframework.batch.item.file.transform.BeanWrapperFieldExtractor;
import org.springframework.batch.item.file.transform.DelimitedLineAggregator;
import org.springframework.core.io.FileSystemResource;
import org.springframework.batch.item.ExecutionContext;

import java.util.List;

public class CsvExporter {

    public FlatFileItemWriter<Test> writeFile(List<Test> tests) throws Exception {
        FlatFileItemWriter<Test> flatFileItemWriter = new FlatFileItemWriterBuilder<Test>()
                .resource(new FileSystemResource("/data/outputData.csv"))
                .lineAggregator(getDelimitedLineAggregator())
                .headerCallback(writer -> {
                    DelimitedLineAggregator<String> headerAggregator = new DelimitedLineAggregator<>();
                    headerAggregator.setDelimiter(",");
                    headerAggregator.setFieldExtractor(items -> items);
                    writer.write(headerAggregator.aggregate(new String[] {"ID", "TypeTest1", "TypeTest2"}));
                })
                .append(false)
                .build();

        flatFileItemWriter.open(new ExecutionContext());
        flatFileItemWriter.write(tests);
        flatFileItemWriter.close();

        return flatFileItemWriter;
    }

    private DelimitedLineAggregator<Test> getDelimitedLineAggregator() {
        BeanWrapperFieldExtractor<Test> beanWrapperFieldExtractor = new BeanWrapperFieldExtractor<>();
        // 确保这里的属性名与Test类的属性完全匹配
        beanWrapperFieldExtractor.setNames(new String[] {"id", "typeTest1", "typeTest2"});
        // 可选:如果属性可能为null,设置默认值
        // beanWrapperFieldExtractor.setNullValue("");

        DelimitedLineAggregator<Test> aggregator = new DelimitedLineAggregator<>();
        aggregator.setDelimiter(",");
        aggregator.setFieldExtractor(beanWrapperFieldExtractor);
        return aggregator;
    }

    // 示例Test类
    public static class Test {
        private Long id;
        private String typeTest1;
        private String typeTest2;

        public Test(Long id, String typeTest1, String typeTest2) {
            this.id = id;
            this.typeTest1 = typeTest1;
            this.typeTest2 = typeTest2;
        }

        // 必须提供对应的getter方法
        public Long getId() {
            return id;
        }

        public String getTypeTest1() {
            return typeTest1;
        }

        public String getTypeTest2() {
            return typeTest2;
        }
    }
}

内容的提问来源于stack exchange,提问作者testyahoo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 10:57:06