Spring Boot中WebClient调用外部API后DTO转换值为null问题排查
问题原因及解决方案
核心问题1:响应结构不匹配
外部API返回的是包含results数组的顶层对象,而你直接尝试将整个响应转换为AddressResponse类,两者结构完全不匹配,导致Jackson无法找到对应字段,最终所有值为null。
核心问题2:DTO字段与API响应字段不匹配
你的AddressResponse中的street、line1、line2、postcode字段,在API返回的响应里没有对应的键名(API返回的是name、country、state等),就算结构匹配,这些字段也无法被赋值。
核心问题3:DTO缺少序列化支持
你的AddressResponse类只有私有字段,没有提供无参构造函数和getter/setter方法,Jackson默认需要这些来完成对象反序列化,无法直接为私有字段赋值。
具体修复步骤
1. 创建匹配API响应结构的DTO
先定义顶层响应类和结果项类,完全匹配API返回的JSON结构:
// 顶层响应类,对应API返回的整个JSON public class ApiAddressResponse { private List<AddressResult> results; // 无参构造函数(必须) public ApiAddressResponse() {} // Getter和Setter public List<AddressResult> getResults() { return results; } public void setResults(List<AddressResult> results) { this.results = results; } } // 结果项类,对应results数组中的单个对象 public class AddressResult { private String name; private String country; private String country_code; private String state; private String county; private String city; // 如果需要datasource信息,可以再定义对应的Datasource类并添加字段 // 无参构造函数(必须) public AddressResult() {} // Getter和Setter public String getName() { return name; } public void setName(String name) { this.name = name; } public String getCountry() { return country; } public void setCountry(String country) { this.country = country; } // 其他字段的Getter/Setter同理 }
2. 修改WebClient调用逻辑
先将响应转换为顶层的ApiAddressResponse,再从results数组中提取数据,映射到你的AddressResponse:
public AddressResponse resolveAddress(AddressRequest addressRequest) { ApiAddressResponse apiResponse = webClient.get() .uri(uriBuilder -> uriBuilder .queryParam("text", addressRequest.getSearchTerm()) .queryParam("apiKey", apiKey) .build()) .retrieve() .bodyToMono(ApiAddressResponse.class) .block(); // 处理空响应或空结果的情况 if (apiResponse == null || apiResponse.getResults().isEmpty()) { return null; // 或者抛出自定义异常 } AddressResult firstResult = apiResponse.getResults().get(0); AddressResponse addressResponse = new AddressResponse(); // 根据业务需求映射字段,比如将name赋值给street addressResponse.setStreet(firstResult.getName()); addressResponse.setCountry(firstResult.getCountry()); // line1、line2、postcode如果API没有返回对应数据,只能保持null,或者确认API是否有其他字段可用 return addressResponse; }
3. 完善你的AddressResponse类
添加无参构造函数和Getter/Setter,或者使用Lombok的@Data注解简化代码:
// 使用Lombok的方式(需要引入Lombok依赖) @Data public class AddressResponse { private String street; private String line1; private String line2; private String postcode; private String country; } // 不使用Lombok的方式 public class AddressResponse { private String street; private String line1; private String line2; private String postcode; private String country; public AddressResponse() {} // 所有字段的Getter和Setter public String getStreet() { return street; } public void setStreet(String street) { this.street = street; } public String getLine1() { return line1; } public void setLine1(String line1) { this.line1 = line1; } // 其他字段的Getter/Setter同理 }
内容的提问来源于stack exchange,提问作者kidulf
相关产品推荐
相关产品推荐

