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

使用Spring RestTemplate如何将结构不同的REST JSON响应转为自定义模型对象

方案合理性说明

你当前使用Jackson JsonNode 手动提取字段的方案是完全合理的,适配你不需要全量响应字段、需统一业务模型做跨接口数据校验的场景,灵活度很高。

当前方案优化点

你现有实现可以做几个小调整提升稳定性和性能:

  • 不要每次调用都新建ObjectMapper实例,Spring Boot已经自动配置了单例的ObjectMapper,直接注入复用即可,避免重复创建的性能开销
  • 提取字段时优先用path()代替get(),遇到不存在的字段不会抛出空指针,同时使用asText()、asInt()等方法代替toString(),避免取出的字符串自带多余引号
  • 你的响应体是JSON对象不是数组,不需要调用get(0)获取首元素,直接读取根节点字段即可

优化后的代码示例:

@Autowired
private ObjectMapper objectMapper;

@Override
public NotaryDistrictDetails getNotaryDistrictDetails(String districtId) throws URISyntaxException {
    String completeURL =  this.wpPortalGetNotaryDistrictPostDetailsURL.replace("{districtId}", districtId);
    URI uri = new URI(completeURL);
    NotaryDistrictDetails myModelObj = new NotaryDistrictDetails();
    try {
        HttpHeaders basicAuthHeader =  this.getWpBasicAuthenticationHeader();
        HttpEntity<String> request = new HttpEntity<>(basicAuthHeader);
        ResponseEntity<String> response = restTemplate.exchange(uri, HttpMethod.GET, request, String.class);
        if (response.getStatusCode().is2xxSuccessful() && response.getBody() != null) {
            JsonNode rootNode = objectMapper.readTree(response.getBody());
            // 提取根节点id
            myModelObj.setId(rootNode.path("id").asText());
            // 提取嵌套的title字段
            myModelObj.setTitle(rootNode.path("title").path("rendered").asText());
            // 提取深层嵌套的公证人ID
            myModelObj.setNotaryId(rootNode.path("toolset-meta")
                .path("gruppo-scheda-notary")
                .path("idnotary")
                .path("raw").asText());
            // 其余字段赋值逻辑
        }
    } catch(Exception e) {
        e.printStackTrace();
    }
    return myModelObj;
}
更优实现方案

根据你的场景可以选择以下两种更优方案:

方案1:JsonPath简化嵌套字段提取

如果响应嵌套层级深、需要提取的字段较多,推荐使用JsonPath库直接通过路径表达式提取字段,无需逐层调用get()方法,代码更简洁。
使用示例:

  1. Spring Boot默认已集成JsonPath,无需额外引入依赖
  2. 代码实现:
DocumentContext context = JsonPath.parse(response.getBody());
// 直接通过路径表达式提取任意层级字段
String notaryId = context.read("$.toolset-meta.gruppo-scheda-notary.idnotary.raw", String.class);
String title = context.read("$.title.rendered", String.class);
Integer id = context.read("$.id", Integer.class);
// 赋值给业务模型
myModelObj.setId(String.valueOf(id));
myModelObj.setTitle(title);
myModelObj.setNotaryId(notaryId);

方案2:静态内部类做中间反序列化层(推荐固定映射场景)

如果字段映射逻辑固定,想要获得编译期类型校验能力,避免运行期字段名写错的问题,可以在你的业务模型类内部定义静态的临时反序列化类,不需要单独维护一套外部响应模型,兼顾类型安全和代码整洁。
示例代码:

@Data
public class NotaryDistrictDetails {
    // 你的业务模型原有字段
    private String id;
    private String title;
    private String notaryId;

    // 内部静态反序列化中间类,仅当前类使用,无需对外暴露
    @JsonIgnoreProperties(ignoreUnknown = true)
    @Data
    private static class WpApiResponse {
        private Integer id;
        private WpRenderField title;
        @JsonProperty("toolset-meta")
        private WpToolsetMeta toolsetMeta;
    }

    @JsonIgnoreProperties(ignoreUnknown = true)
    @Data
    private static class WpRenderField {
        private String rendered;
        private String raw;
    }

    @JsonIgnoreProperties(ignoreUnknown = true)
    @Data
    private static class WpToolsetMeta {
        @JsonProperty("gruppo-scheda-notary")
        private WpNotaryGroup notaryGroup;
    }

    @JsonIgnoreProperties(ignoreUnknown = true)
    @Data
    private static class WpNotaryGroup {
        @JsonProperty("idnotary")
        private WpRenderField idNotary;
    }

    // 统一转换方法
    public static NotaryDistrictDetails convertFrom(WpApiResponse response) {
        NotaryDistrictDetails details = new NotaryDistrictDetails();
        details.setId(String.valueOf(response.getId()));
        details.setTitle(response.getTitle().getRendered());
        details.setNotaryId(response.getToolsetMeta().getNotaryGroup().getIdNotary().getRaw());
        return details;
    }
}

调用时直接让RestTemplate反序列化为中间类即可:

ResponseEntity<NotaryDistrictDetails.WpApiResponse> response = restTemplate.exchange(uri, HttpMethod.GET, request, NotaryDistrictDetails.WpApiResponse.class);
NotaryDistrictDetails details = NotaryDistrictDetails.convertFrom(response.getBody());
方案选型建议
  • 字段少、映射逻辑不常变更:用优化后的JsonNode方案即可,足够轻量
  • 嵌套层级深、字段多:用JsonPath方案,代码更简洁
  • 映射逻辑固定、需要类型安全校验:用内部静态类中间层方案,性能最优、稳定性最高

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 15:45:01