如何用Univocity CSV Parser解析CSV并封装多字段为POJO单属性?
使用Univocity CSV Parser实现动态列映射与剩余列JSON封装
完全可以实现这个需求,核心是通过自定义RowProcessor来灵活处理每一行数据,结合Jackson将剩余列转为JSON对象。以下是具体实现步骤和代码示例:
1. 定义目标POJO
首先创建需要映射的POJO类,其中propertyC可以用Jackson的JsonNode或者Map<String, String>来存储剩余列的JSON数据:
import com.fasterxml.jackson.databind.JsonNode; public class TargetPojo { private String propertyA; private String propertyB; private JsonNode propertyC; // 构造器、Getter和Setter方法 public TargetPojo(String propertyA, String propertyB, JsonNode propertyC) { this.propertyA = propertyA; this.propertyB = propertyB; this.propertyC = propertyC; } // 省略Getter、Setter }
2. 创建自定义RowProcessor
自定义处理器需要接收选中列的配置(比如列名),在处理每一行时完成列提取和剩余列的JSON转换:
import com.fasterxml.jackson.databind.ObjectMapper; import com.univocity.parsers.common.processor.RowProcessor; import com.univocity.parsers.csv.CsvParser; import com.univocity.parsers.csv.CsvParserSettings; import java.util.*; public class DynamicColumnProcessor implements RowProcessor { private final String columnA; private final String columnB; private final ObjectMapper objectMapper; private List<String> headers; private final List<TargetPojo> resultList = new ArrayList<>(); public DynamicColumnProcessor(String columnA, String columnB) { this.columnA = columnA; this.columnB = columnB; this.objectMapper = new ObjectMapper(); } @Override public void processStarted(CsvParser parser) { // 获取CSV的表头信息 this.headers = Arrays.asList(parser.getContext().headers()); } @Override public void processRow(String[] row) { Map<String, String> remainingColumns = new HashMap<>(); String propA = null; String propB = null; for (int i = 0; i < headers.size(); i++) { String header = headers.get(i); String value = row[i]; if (header.equals(columnA)) { propA = value; } else if (header.equals(columnB)) { propB = value; } else { remainingColumns.put(header, value); } } // 将剩余列转为JsonNode try { JsonNode jsonNode = objectMapper.valueToTree(remainingColumns); resultList.add(new TargetPojo(propA, propB, jsonNode)); } catch (Exception e) { throw new RuntimeException("转换剩余列为JSON失败", e); } } @Override public void processEnded(CsvParser parser) { // 解析结束后的清理操作(可选) } public List<TargetPojo> getResultList() { return resultList; } }
3. Spring REST接口实现
编写Controller方法,接收上传的CSV文件和选中列的JSON参数,完成解析:
首先定义接收选中列信息的DTO:
public class ColumnSelection { private String columnA; private String columnB; // Getter和Setter }
然后是Controller:
import com.univocity.parsers.csv.CsvParser; import com.univocity.parsers.csv.CsvParserSettings; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestPart; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import java.io.InputStream; import java.util.List; @RestController public class CsvUploadController { @PostMapping("/upload-csv") public ResponseEntity<List<TargetPojo>> uploadCsv( @RequestPart("file") MultipartFile file, @RequestPart("selection") ColumnSelection selection) throws Exception { // 初始化CSV解析器设置 CsvParserSettings settings = new CsvParserSettings(); settings.setHeaderExtractionEnabled(true); // 自动提取表头 // 实例化自定义处理器 DynamicColumnProcessor processor = new DynamicColumnProcessor(selection.getColumnA(), selection.getColumnB()); settings.setProcessor(processor); // 解析CSV文件 try (InputStream inputStream = file.getInputStream()) { CsvParser parser = new CsvParser(settings); parser.parse(inputStream); } return ResponseEntity.ok(processor.getResultList()); } }
关键说明
- 如果用户上传的选中列信息是列索引而非列名,只需修改
DynamicColumnProcessor的逻辑,直接通过索引提取propA和propB,剩余列按表头-值的方式收集即可。 - 若不需要
JsonNode,可以直接用Map<String, String>作为propertyC的类型,省去Jackson转换步骤,更轻量化。 - 可以根据需求添加异常处理、数据校验(比如检查选中列是否存在于CSV表头中)等逻辑。
内容的提问来源于stack exchange,提问作者scharrua
相关产品推荐
相关产品推荐

