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

如何在Jackson CsvMapper中将小数点替换为逗号?

问题

使用Spring Boot结合Jackson生成CSV文件时,Double类型字段默认以点(.)作为小数分隔符,需要替换为逗号(,)。尝试将Double字段改为String类型后,导出时字段会被自动添加双引号,不符合需求。期望生成的CSV中,数字字段无引号且使用逗号作为小数分隔符,格式如下:

field1;field2;field3;field4
"Value 1";"Value, 2";7,1;8,0
解决方案

以下两种方法可解决该问题,推荐优先使用Locale配置的方式,更符合Jackson原生设计:

方法一:通过Locale配置小数分隔符

Jackson的数字格式化逻辑依赖Locale,设置支持逗号作为小数分隔符的Locale(如德语区Locale),同时在CSV Schema中指定数字列类型,即可避免添加引号并替换小数分隔符。

修改CSV生成代码

替换原有的JsonNode转换逻辑,直接用CsvMapper处理实体类,并配置Locale和列类型:

CsvMapper csvMapper = new CsvMapper();
// 设置为对应Locale,例如德语区Locale(小数分隔符为逗号),可替换为你所在国家的Locale
csvMapper.setLocale(new Locale("de", "DE"));

// 构建CSV Schema,明确指定数字列类型
CsvSchema.Builder csvSchemaBuilder = CsvSchema.builder();
csvSchemaBuilder.addColumn("field1");
csvSchemaBuilder.addColumn("field2");
csvSchemaBuilder.addColumn("field3", CsvSchema.ColumnType.NUMBER);
csvSchemaBuilder.addColumn("field4", CsvSchema.ColumnType.NUMBER);

CsvSchema csvSchema = csvSchemaBuilder.build().withHeader().withColumnSeparator(';');

// 直接序列化实体类列表(responseObject应为List<ExampleQuestionClass>)
dataCsv = csvMapper.writerFor(List.class)
        .with(csvSchema)
        .writeValueAsBytes(responseObject);

说明

  • 配置Locale后,Jackson会自动按照该区域的数字格式输出,将小数点替换为逗号。
  • 指定ColumnType.NUMBER后,CSV生成时不会为数字字段添加双引号,符合期望格式。

方法二:自定义Double序列化器

如果需要更精细的格式控制(如固定小数位数),可自定义Jackson序列化器处理Double字段,直接输出带逗号分隔符的字符串,并通过Schema配置避免引号。

步骤1:创建自定义序列化器

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import java.io.IOException;
import java.text.DecimalFormat;

public class CustomDoubleSerializer extends StdSerializer<Double> {
    // 自定义格式,保留两位小数
    private static final DecimalFormat df = new DecimalFormat("#.##");

    public CustomDoubleSerializer() {
        this(null);
    }

    public CustomDoubleSerializer(Class<Double> t) {
        super(t);
    }

    @Override
    public void serialize(Double value, JsonGenerator gen, SerializerProvider provider) throws IOException {
        if (value != null) {
            // 将小数点替换为逗号
            String formattedValue = df.format(value).replace('.', ',');
            gen.writeString(formattedValue);
        }
    }
}

步骤2:在实体类字段上添加注解

@Data
@NoArgsConstructor
@AllArgsConstructor
@JsonPropertyOrder({"field1", "field2", "field3", "field4"})
public class ExampleQuestionClass {
    @JsonProperty("field1")
    private String field1;
    @JsonProperty("field2")
    private String field2;
    
    @JsonProperty("field3")
    @JsonSerialize(using = CustomDoubleSerializer.class)
    private Double field3;
    
    @JsonProperty("field4")
    @JsonSerialize(using = CustomDoubleSerializer.class)
    private Double field4;
}

步骤3:配置CSV Schema并序列化

CsvMapper csvMapper = new CsvMapper();
// 构建Schema时指定数字列类型,避免字符串引号
CsvSchema.Builder csvSchemaBuilder = CsvSchema.builder();
csvSchemaBuilder.addColumn("field1");
csvSchemaBuilder.addColumn("field2");
csvSchemaBuilder.addColumn("field3", CsvSchema.ColumnType.NUMBER);
csvSchemaBuilder.addColumn("field4", CsvSchema.ColumnType.NUMBER);

CsvSchema csvSchema = csvSchemaBuilder.build().withHeader().withColumnSeparator(';');

dataCsv = csvMapper.writerFor(List.class)
        .with(csvSchema)
        .writeValueAsBytes(responseObject);
注意事项
  • 避免先将实体类序列化为JsonNode再转CSV:此过程中Double会被转为带点的字符串,后续无法通过Locale或Schema修改格式。
  • 选择对应Locale时,需确保该区域的小数分隔符为逗号,可根据实际需求替换为Locale.FRANCE、Locale.ITALY等。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 18:24:50