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

Spring Boot中如何用Jackson生成带层级编号的动态属性名

动态替换Spring Boot REST API层级结构的属性名(level1、level2...)

问题场景

构建Spring Boot REST API时,返回的层级结构响应中所有层级的嵌套属性名均为levels,需要将其动态替换为带编号的名称(如level1、level2),实现层级分明的JSON输出。

现有实体类

public class Root {
    private String id;
    private List<Level> levels;
    // 省略getter、setter及构造方法
}

public class Level {
    private String name;
    private List<Level> levels;
    // 省略getter、setter及构造方法
}

当前JSON输出

{
  "id" :"testid",
  "levels" : [
         {
          "name" :"test1",
          "levels" : [
              {
                 "name": "test3",
                 "levels" : []
              }
          ]
         }
      ]
}

期望JSON输出

{
  "id" :"testid",
  "level1" : [
         {
          "name" :"test1",
          "level2" : [
              {
                 "name": "test3",
                 "level3" : []
              }
          ]
         }
      ]
}

解决方案:自定义Jackson序列化器

利用Spring Boot默认的Jackson JSON处理框架,通过自定义序列化器跟踪层级深度,动态生成带编号的属性名。

1. 编写自定义层级序列化器

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;
import java.util.List;

public class LevelSerializer extends JsonSerializer<List<Level>> {
    // 用ThreadLocal存储当前层级,避免多线程请求间的干扰
    private static final ThreadLocal<Integer> CURRENT_LEVEL = ThreadLocal.withInitial(() -> 1);

    @Override
    public void serialize(List<Level> levels, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        int depth = CURRENT_LEVEL.get();
        // 写入带编号的属性名
        gen.writeFieldName("level" + depth);
        gen.writeStartArray();

        // 层级+1,用于子节点序列化
        CURRENT_LEVEL.set(depth + 1);
        for (Level level : levels) {
            serializers.defaultSerializeValue(level, gen);
        }
        // 恢复当前层级,不影响后续节点
        CURRENT_LEVEL.set(depth);

        gen.writeEndArray();
    }
}

2. 为实体类字段指定序列化器

在Root和Level类的levels字段上添加@JsonSerialize注解,指定使用自定义序列化器:

import com.fasterxml.jackson.databind.annotation.JsonSerialize;

public class Root {
    private String id;
    @JsonSerialize(using = LevelSerializer.class)
    private List<Level> levels;
    // 省略getter、setter及构造方法
}

public class Level {
    private String name;
    @JsonSerialize(using = LevelSerializer.class)
    private List<Level> levels;
    // 省略getter、setter及构造方法
}

3. (可选)全局注册序列化器

如果不想在实体类上添加注解,可以通过配置类全局注册序列化器,避免侵入实体类:

import com.fasterxml.jackson.core.type.TypeReference;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.fasterxml.jackson.databind.module.SimpleModule;

@Configuration
public class JacksonConfig {
    @Bean
    public SimpleModule levelSerializerModule() {
        SimpleModule module = new SimpleModule();
        // 精确指定针对List<Level>类型的序列化器
        module.addSerializer(new TypeReference<List<Level>>() {}, new LevelSerializer());
        return module;
    }
}

注意事项

  • ThreadLocal用于在多线程环境中独立跟踪每个请求的层级深度,Spring MVC的请求线程池会自动管理线程状态,无需手动清理。
  • 如果需要调整初始层级编号,修改ThreadLocal.withInitial(() -> 1)中的初始值即可。
  • 若存在其他类型的List需要序列化,使用TypeReference指定List<Level>类型可以避免影响其他序列化逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 14:45:37