Spring WebClient如何优雅映射JSON对象列表响应
问题原因
直接使用bodyToMono(SportResponse.class)映射失败,是因为接口返回的JSON存在外层包裹结构,实际返回格式为外层对象携带sports数组字段,数组内的元素才是SportResponse对应的实体。
你当前编写的手动转换逻辑虽然能运行,但存在明显冗余:每次调用都新建ObjectMapper实例浪费性能,手动做类型强转、流处理的逻辑完全可以交给序列化框架自动完成,不需要手写。
简洁实现方案
第一步,定义和接口返回结构完全对齐的响应包装类,不需要额外写转换逻辑:
如果项目使用Java 16+,直接用record定义即可:
public record SportApiWrapper(List<SportResponse> sports) {}
如果是低版本Java,用普通JavaBean定义即可,可配合Lombok简化代码:
@Data public class SportApiWrapper { private List<SportResponse> sports; }
第二步,删除原有冗余的mapResponse私有方法,修改WebClient接收逻辑,直接让框架完成序列化:
@Service public class SportService { private final WebClient sportWebClient; private final ApplicationConfiguration applicationConfiguration; public SportService(WebClient webClient, ApplicationConfiguration applicationConfiguration) { this.sportWebClient = webClient; this.applicationConfiguration = applicationConfiguration; } public List<SportResponse> getAllSports() { return sportWebClient .get() .uri("api/v1/json/2/all_sports.php") .retrieve() // 直接映射到包装类,Jackson会自动完成字段绑定 .bodyToMono(SportApiWrapper.class) // 直接取出内部的体育项目列表即可 .map(SportApiWrapper::getSports) .block(); } }
可选优化项
- 不建议在业务方法中手动new
ObjectMapper实例,该对象线程安全,重复创建会带来不必要的性能开销,Spring环境下默认已经注册了全局单例的ObjectMapper,直接注入使用即可,上述方案中完全不需要手动操作ObjectMapper。 - 如果不想单独定义包装类,也可以使用
ParameterizedTypeReference直接映射嵌套结构,但是可读性比定义包装类差,写法如下:.bodyToMono(new ParameterizedTypeReference<Map<String, List<SportResponse>>>() {}) .map(resp -> resp.get("sports")) - 如果后续要完成全异步改造,不要在业务层直接调用
block()阻塞响应式线程,直接返回Mono<List<SportResponse>>交给上层Web框架处理即可。
内容的提问来源于stack exchange,提问作者cubila
相关产品推荐
相关产品推荐

