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

Spring Boot Restful API动态生成JSON:无需双对象的字段移除方案

如何在不创建父子对象的情况下修改Restful API的JSON输出?

问题描述

我正在开发Restful API服务,需要修改输出JSON,移除部分字段:

当前输出JSON

{
    "id": "10001",
    "name": "math",
    "family": "mac",
    "code": "1",
    "subNotes": [
        {
            "id": null,
            "name": "john",
            "family": null,
            "code": "1-1",
            "subNotes": null
        },
        {
            "id": null,
            "name": "cris",
            "family": null,
            "code": "1-2",
            "subNotes": null
        },
        {
            "id": null,
            "name": "eli",
            "family": null,
            "code": "1-3",
            "subNotes": null
        }
    ]
}

目标输出JSON

{
    "id": "10001",
    "name": "math",
    "family": "mac",
    "code": "1",
    "subNotes": [
        {
            "name": "john",
            "code": "1-1"
        },
        {
            "name": "cris",
            "code": "1-2"
        },
        {
            "name": "eli",
            "code": "1-3"
        }
    ]
}

请问能否无需创建父、子两个对象实现该修改?最优解决方案是什么?


解决方案

完全可以不用创建新的父子对象,以下是几种实用方案,按场景推荐:

1. 序列化注解(静态过滤,适合固定需求)

如果你的API用Jackson作为JSON序列化工具(Spring Boot默认),直接在实体类的目标字段上添加注解即可:

  • @JsonIgnore:直接标记要移除的字段(比如子对象的id、family、subNotes),序列化时会自动忽略这些字段。

    public class SubNote {
        @JsonIgnore
        private String id;
        private String name;
        @JsonIgnore
        private String family;
        private String code;
        @JsonIgnore
        private List<SubNote> subNotes;
        // getter/setter
    }
    

    优点:实现简单,无额外代码;缺点:如果该实体类被其他接口复用,会影响其他接口的输出。

  • @JsonView:定义视图接口,给需要输出的字段标记视图,接口方法上指定使用的视图,实现按需输出。

    // 定义视图接口
    public interface ApiView {
        interface Basic {}
        interface Detailed extends Basic {}
    }
    
    // 父实体类
    public class ParentNote {
        @JsonView(ApiView.Basic.class)
        private String id;
        @JsonView(ApiView.Basic.class)
        private String name;
        @JsonView(ApiView.Basic.class)
        private String family;
        @JsonView(ApiView.Basic.class)
        private String code;
        @JsonView(ApiView.Basic.class)
        private List<SubNote> subNotes;
        // getter/setter
    }
    
    // 子实体类
    public class SubNote {
        // 不标记视图,默认不输出
        private String id;
        @JsonView(ApiView.Basic.class)
        private String name;
        // 不标记视图,默认不输出
        private String family;
        @JsonView(ApiView.Basic.class)
        private String code;
        // 不标记视图,默认不输出
        private List<SubNote> subNotes;
        // getter/setter
    }
    
    // 接口方法
    @GetMapping("/notes")
    @JsonView(ApiView.Basic.class)
    public ParentNote getNotes() {
        // 返回数据逻辑
    }
    

    优点:灵活控制不同接口的输出字段,不影响实体类复用;缺点:需要定义视图接口,稍显繁琐。

2. 动态字段过滤(灵活适配多场景)

如果需要在运行时动态决定过滤哪些字段,可以用Jackson的FilterProvider:

@GetMapping("/notes")
public String getNotes() throws JsonProcessingException {
    ParentNote note = getNoteData(); // 获取原始数据
    ObjectMapper mapper = new ObjectMapper();
    
    // 定义过滤器,排除子对象的id、family、subNotes字段
    SimpleBeanPropertyFilter subNoteFilter = SimpleBeanPropertyFilter.serializeAllExcept("id", "family", "subNotes");
    FilterProvider filters = new SimpleFilterProvider()
            .addFilter("subNoteFilter", subNoteFilter);
    
    // 注意:需要给子实体类添加@JsonFilter("subNoteFilter")注解
    return mapper.writer(filters).writeValueAsString(note);
}

优点:无需修改实体类的全局注解,运行时动态调整;缺点:需要编写少量过滤逻辑代码。

3. 直接操作JSON节点(无需修改实体类)

如果不想修改任何实体类,可以先将对象转成JsonNode,手动移除不需要的字段后再转成JSON:

@GetMapping("/notes")
public String getNotes() throws JsonProcessingException {
    ParentNote note = getNoteData();
    ObjectMapper mapper = new ObjectMapper();
    JsonNode rootNode = mapper.valueToTree(note);
    
    // 遍历subNotes数组,移除每个子节点的指定字段
    if (rootNode.has("subNotes") && rootNode.get("subNotes").isArray()) {
        ArrayNode subNotesArray = (ArrayNode) rootNode.get("subNotes");
        for (JsonNode subNode : subNotesArray) {
            ((ObjectNode) subNode).remove("id");
            ((ObjectNode) subNode).remove("family");
            ((ObjectNode) subNode).remove("subNotes");
        }
    }
    
    return mapper.writeValueAsString(rootNode);
}

优点:完全不依赖实体类,适合临时需求或实体类无法修改的场景;缺点:需要手动处理JSON节点,嵌套复杂时代码量会增加。


最优方案选择

  • 如果是固定单一场景,优先用@JsonIgnore,实现成本最低;
  • 如果实体类需要多接口复用,用@JsonView更合适,兼顾灵活性和可维护性;
  • 如果需要动态调整过滤规则(比如根据请求参数决定输出字段),选择动态过滤或JSON节点操作方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 01:35:25