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

使用CsvToBean解析CSV时值为null但行数正确问题求解

问题描述

导入CSV文件获取全量数据时,读取到的记录行数和文件实际行数一致,但所有字段值均为null,涉及代码如下:

@RequestMapping(value = "/upload", method = RequestMethod.POST)
    public String uploadFile(@RequestParam(value = "file") MultipartFile file){
    CsvToBean<Person> csvToBean = new CsvToBeanBuilder(reader)
                                        .withType(Person.class)
                                        .withIgnoreLeadingWhiteSpace(true)
                                        .build();
                                List<Person> records = csvToBean.parse();
                                
                                System.out.println(records.size());
                            if(records.size() ==0) {
                                model.addAttribute("message_file", "Aucune donnée trouvée dans le fichier importé");
                                model.addAttribute("code_file", "000");
                            }
                            for(int i = 0; i<records.size(); i++){
                               System.out.println(records.get(i).getid());
                               
                             }
.....
}


Person class :

@Entity
@Table(name = "Person", schema = "MXP")
public class Person implements Serializable{

    private static final long serialVersionUID = 1L;

    @Id
    @Column(name = "person_id")
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "XPerson")

    private Long id;

    @Column(name = "PERSON_NAME")
    private String name;

    //..getters and setters
故障原因

行数匹配说明CSV行解析逻辑正常,字段全为null是映射环节失败导致,常见触发原因有4个:

  • 未给实体类字段加OpenCSV的映射注解:OpenCSV不会自动识别JPA的@Column注解做列名匹配,没有配置绑定规则的字段不会被赋值。
  • getter/setter不符合JavaBean命名规范:代码中调用的getid()方法名属性首字母未大写,OpenCSV通过反射扫描属性方法时无法匹配到对应字段。
  • 未正确初始化Reader对象:代码中直接传入未定义/未初始化的reader,没有从MultipartFile中获取文件输入流构造读取器。
  • CSV分隔符配置不匹配:如果CSV文件使用分号等非逗号分隔符,未指定分隔符会导致单行列解析错位,也可能出现字段为空的情况。
修复方案

按以下步骤调整代码即可正常读取数据:

  1. 引入OpenCSV的绑定注解,根据CSV格式选择映射规则
    • 如果CSV带表头,用@CsvBindByName指定和表头一致的列名
    • 如果CSV无表头按列位置排序,用@CsvBindByPosition指定列序号(从0开始计数)
  2. 修正所有字段的getter/setter命名,严格遵循JavaBean规范,属性名对应方法的第二个单词首字母大写,比如id字段的getter必须为getId()、setter为setId(Long id)。
  3. 从MultipartFile中获取输入流,正确构造Reader对象,建议显式指定字符集避免乱码。
  4. 根据CSV实际格式配置分隔符、忽略空行等解析参数。

修复后参考代码

Controller层上传逻辑:

@RequestMapping(value = "/upload", method = RequestMethod.POST)
public String uploadFile(@RequestParam(value = "file") MultipartFile file, Model model){
    // 用try-with-resources自动关闭流,避免资源泄漏
    try (Reader reader = new InputStreamReader(file.getInputStream(), StandardCharsets.UTF_8)) {
        CsvToBean<Person> csvToBean = new CsvToBeanBuilder<Person>(reader)
                .withType(Person.class)
                .withIgnoreLeadingWhiteSpace(true)
                // 分号分隔的CSV打开下方配置
                // .withSeparator(';')
                .build();
        List<Person> records = csvToBean.parse();
        System.out.println(records.size());
        if(records.size() == 0) {
            model.addAttribute("message_file", "Aucune donnée trouvée dans le fichier importé");
            model.addAttribute("code_file", "000");
        }
        for (Person record : records) {
            // 调用修正后的getId()方法
            System.out.println(record.getId());
        }
        // 其余业务逻辑
    } catch (Exception e) {
        e.printStackTrace();
        model.addAttribute("message_file", "文件解析失败:" + e.getMessage());
        model.addAttribute("code_file", "001");
    }
    return "对应视图路径";
}

Person实体类修正:

import com.opencsv.bean.CsvBindByName;
import java.io.Serializable;

@Entity
@Table(name = "Person", schema = "MXP")
public class Person implements Serializable{

    private static final long serialVersionUID = 1L;

    @Id
    @Column(name = "person_id")
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "XPerson")
    // 列名和CSV表头保持完全一致,区分大小写
    @CsvBindByName(column = "id")
    // 如果是无表头按位置映射,替换为下方注解
    // @CsvBindByPosition(position = 0)
    private Long id;

    @Column(name = "PERSON_NAME")
    @CsvBindByName(column = "name")
    // @CsvBindByPosition(position = 1)
    private String name;

    // 符合规范的getter/setter
    public Long getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

提示:如果表头和实体类字段名完全一致,@CsvBindByName可以不指定column属性,会自动按字段名匹配表头。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 13:45:34