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
相关产品推荐
相关产品推荐

