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

Spring Boot中构建深层嵌套JSON对应的POJO/DTO最佳实践

处理嵌套JSON的Spring Boot DTO设计方案

一、别用匿名类,避坑优先

匿名类看起来能把代码集中在一个文件,但实际问题一堆:Jackson序列化时会自动带上匿名类的后缀(比如$1),第三方API大概率不认;没法复用,每次构造请求都要重新写一遍嵌套逻辑;不能加参数校验注解(比如@NotBlank);调试时找不到具体的类结构,排查问题巨麻烦——完全得不偿失。

二、两种主流实用方案

方案1:静态内部类拆分(推荐,平衡简洁性与可维护性)

把所有嵌套结构都作为主DTO的静态内部类,既能把代码集中在一个文件里,又能保证类型安全、可复用,还能加校验注解。

示例代码:

import com.fasterxml.jackson.annotation.JsonProperty;
import jakarta.validation.constraints.NotBlank;

public class ThirdPartyRequestDto {

    @JsonProperty("profile")
    private Profile profile;

    // Getters & Setters(或用Lombok简化)

    public static class Profile {
        @NotBlank
        @JsonProperty("firstName")
        private String firstName;

        @JsonProperty("credentials")
        private Credentials credentials;

        // Getters & Setters
        public static class Credentials {
            @JsonProperty("password")
            private Password password;

            // Getters & Setters
            public static class Password {
                @JsonProperty("hook")
                private Hook hook;

                // Getters & Setters
                public static class Hook {
                    @NotBlank
                    @JsonProperty("type")
                    private String type;

                    // Getters & Setters
                }
            }
        }
    }

    // 新增静态构建方法,避免多层嵌套new的繁琐
    public static ThirdPartyRequestDto buildDefault(String firstName) {
        ThirdPartyRequestDto dto = new ThirdPartyRequestDto();
        Profile profile = new Profile();
        profile.setFirstName(firstName);
        
        Profile.Credentials credentials = new Profile.Credentials();
        Profile.Credentials.Password password = new Profile.Credentials.Password();
        Profile.Credentials.Password.Hook hook = new Profile.Credentials.Password.Hook();
        hook.setType("default");
        
        password.setHook(hook);
        credentials.setPassword(password);
        profile.setCredentials(credentials);
        dto.setProfile(profile);
        
        return dto;
    }
}

优势:

  • 所有结构集中在一个文件,不会散得满项目都是
  • 支持JSR-380校验注解,配合Spring的@Valid能提前拦截非法数据
  • Jackson序列化完全符合第三方API要求,无额外冗余字段
  • 静态内部类可被外部访问复用,比如其他地方需要单独构造Hook对象时直接调用new ThirdPartyRequestDto.Profile.Credentials.Password.Hook()

方案2:用Map/ObjectNode快速构建(适合临时/简单场景)

如果只是偶尔调用第三方API,不想写一堆类,可以直接用Jackson的ObjectNode或者HashMap构造JSON,跳过DTO定义。

示例代码:

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;

public class ThirdPartyClient {
    private final ObjectMapper objectMapper = new ObjectMapper();

    public String buildRequestJson(String firstName) {
        ObjectNode root = objectMapper.createObjectNode();
        
        ObjectNode profile = objectMapper.createObjectNode();
        profile.put("firstName", firstName);
        
        ObjectNode credentials = objectMapper.createObjectNode();
        ObjectNode password = objectMapper.createObjectNode();
        ObjectNode hook = objectMapper.createObjectNode();
        hook.put("type", "default");
        
        password.set("hook", hook);
        credentials.set("password", password);
        profile.set("credentials", credentials);
        root.set("profile", profile);
        
        try {
            return objectMapper.writeValueAsString(root);
        } catch (Exception e) {
            throw new RuntimeException("构建请求JSON失败", e);
        }
    }
}

优势:快速实现,不用定义DTO类;缺点:无类型安全,字段名拼写错误要到运行时才发现,没法做参数校验,API结构变更时需手动修改所有相关代码,仅适合临时场景或极简单的JSON结构。

三、用Lombok减少模板代码

如果觉得写getter/setter太繁琐,搭配Lombok的@Data、@NestedConfigurationProperty(Spring Boot支持嵌套属性绑定)能大幅精简代码:

import com.fasterxml.jackson.annotation.JsonProperty;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;

@Data
public class ThirdPartyRequestDto {
    @JsonProperty("profile")
    private Profile profile;

    @Data
    public static class Profile {
        @NotBlank
        @JsonProperty("firstName")
        private String firstName;

        @JsonProperty("credentials")
        private Credentials credentials;

        @Data
        public static class Credentials {
            @JsonProperty("password")
            private Password password;

            @Data
            public static class Password {
                @JsonProperty("hook")
                private Hook hook;

                @Data
                public static class Hook {
                    @NotBlank
                    @JsonProperty("type")
                    private String type;
                }
            }
        }
    }
}

@Data自动生成getter、setter、equals、hashCode、toString方法,代码瞬间清爽很多。

四、总结

  • 长期维护/复杂API:优先用静态内部类+Lombok,兼顾集中管理、类型安全与可维护性
  • 临时/简单API:用ObjectNode/HashMap快速实现,节省时间
  • 绝对避开匿名类:序列化问题多,维护成本高,完全不实用

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 01:45:38