1. 引言
在本文中,我们将学习如何使用 Jackson 库在 Java 中将 JSON 数据转换为 CSV 格式,以及反过来操作。
虽然也有其他工具可以实现类似功能(比如 org.json 提供的 CDL 类),但本文我们专注于使用 Jackson。
我们将结合 ObjectMapper
和 CsvMapper
来完成 JSON 与 CSV 的转换,目标是提供一套简单粗暴的转换方案,避免踩坑。
2. 依赖配置
首先,我们需要在项目中添加 Jackson 的 CSV 支持模块:
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-csv</artifactId>
<version>2.13.0</version>
</dependency>
另外,还需要 Jackson 的核心模块:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.0</version>
</dependency>
这两个依赖都可在 Maven Central 上找到最新版本。
3. 数据结构说明
在进行 JSON 到 CSV 转换前,我们需要理解两种格式之间的数据映射关系:
- ✅ JSON 支持复杂结构,如嵌套对象、数组等
- ✅ CSV 更适合表示“列表型”数据,每一行对应一个对象
因此,JSON 中的数组对象是最适合转换为 CSV 的结构。
我们以下面这个订单项列表为例:
[ {
"item" : "No. 9 Sprockets",
"quantity" : 12,
"unitPrice" : 1.23
}, {
"item" : "Widget (10mm)",
"quantity" : 4,
"unitPrice" : 3.45
} ]
转换后的 CSV 格式如下:
item,quantity,unitPrice
"No. 9 Sprockets",12,1.23
"Widget (10mm)",4,3.45
4. JSON 转 CSV
4.1 步骤概览
- 使用
ObjectMapper
将 JSON 文件解析为JsonNode
树 - 构建
CsvSchema
,基于 JSON 字段名设置列头 - 使用
CsvMapper
将JsonNode
写入 CSV 文件
4.2 示例代码
JsonNode jsonTree = new ObjectMapper().readTree(new File("src/main/resources/orderLines.json"));
Builder csvSchemaBuilder = CsvSchema.builder();
JsonNode firstObject = jsonTree.elements().next();
firstObject.fieldNames().forEachRemaining(fieldName -> {
csvSchemaBuilder.addColumn(fieldName);
});
CsvSchema csvSchema = csvSchemaBuilder.build().withHeader();
CsvMapper csvMapper = new CsvMapper();
csvMapper.writerFor(JsonNode.class)
.with(csvSchema)
.writeValue(new File("src/main/resources/orderLines.csv"), jsonTree);
运行后即可得到预期的 CSV 文件。
5. CSV 转 JSON
5.1 步骤概览
- 定义 POJO 类
OrderLine
用于映射 CSV 数据 - 使用
CsvMapper
读取 CSV 文件为OrderLine
对象列表 - 使用
ObjectMapper
将对象列表写回 JSON 文件
5.2 示例代码
定义 OrderLine
类:
public class OrderLine {
private String item;
private int quantity;
private BigDecimal unitPrice;
// Constructors, Getters, Setters and toString
}
读取 CSV 并转换为 JSON:
CsvSchema orderLineSchema = CsvSchema.emptySchema().withHeader();
CsvMapper csvMapper = new CsvMapper();
MappingIterator<OrderLine> orderLines = csvMapper.readerFor(OrderLine.class)
.with(orderLineSchema)
.readValues(new File("src/main/resources/orderLines.csv"));
new ObjectMapper()
.configure(SerializationFeature.INDENT_OUTPUT, true)
.writeValue(new File("src/main/resources/orderLinesFromCsv.json"), orderLines.readAll());
运行后即可得到结构清晰的 JSON 文件。
6. 自定义 CSV 格式
有时候我们希望控制输出 CSV 的列名、顺序或隐藏某些字段。这时可以使用 Jackson 提供的注解。
6.1 需求示例
我们希望输出的 CSV 格式如下:
count,name
12,"No. 9 Sprockets"
4,"Widget (10mm)"
即:
- ✅ 将
item
映射为name
- ✅ 将
quantity
映射为count
- ❌ 忽略
unitPrice
- ✅
count
列排在最前
6.2 实现方式
定义一个抽象类用于格式配置:
@JsonPropertyOrder({ "count", "name" })
public abstract class OrderLineForCsv {
@JsonProperty("name")
private String item;
@JsonProperty("count")
private int quantity;
@JsonIgnore
private BigDecimal unitPrice;
}
使用该类生成 CsvSchema
并注册为 Mixin:
CsvMapper csvMapper = new CsvMapper();
CsvSchema csvSchema = csvMapper
.schemaFor(OrderLineForCsv.class)
.withHeader();
csvMapper.addMixIn(OrderLine.class, OrderLineForCsv.class);
最后进行转换:
OrderLine[] orderLines = new ObjectMapper()
.readValue(new File("src/main/resources/orderLines.json"), OrderLine[].class);
csvMapper.writerFor(OrderLine[].class)
.with(csvSchema)
.writeValue(new File("src/main/resources/orderLinesReformated.csv"), orderLines);
运行后即可得到符合预期的 CSV 文件。
7. 小结
本文我们介绍了如何使用 Jackson 的 CsvMapper
和 ObjectMapper
实现 JSON 与 CSV 的双向转换,并演示了如何通过注解灵活控制输出格式。
整个过程简单粗暴,适合需要快速实现数据格式转换的场景。
完整代码可在 GitHub 上找到:https://github.com/eugenp/tutorials(路径:jackson-modules/jackson-conversions-2
)