Feign 实现 GET 方法传递 POJO
Feign 实现 GET 方法传递 POJO
作者:Grey
原文地址:
需求#
Spring MVC 支持 GET 方法直接绑定 POJO 的,但是 Feign 目前无法做到,有几种解决方案
方案一:把 POJO 拆散成一个一个单独的属性放在方法参数里。
方案二:把方法参数变成Map传递。
方案三:使用 GET 传递 @RequestBody ,但此方式违反 Restful 规范。
方案四(最佳实践):通过实现 Feign 的 RequestInterceptor 中的 apply 方法来进行统一拦截转换处理 Feign 中的 GET 方法多参数传递的问题。
接下来介绍方案四,即最佳实践。
环境#
Java 版本:17
Spring Boot 版本:2.7.5
Spring Cloud 版本:2021.0.5
项目结构和说明#
- feign-usage:父项目名称
- register-server : 仅作注册中心,无其他业务方法
- src/
- pom.xml
- provider : 服务端端模块
- src/
- pom.xml
- consumer : 客户端模块
- src/
- pom.xml
- pom.xml:父项目 pom 配置
- register-server : 仅作注册中心,无其他业务方法
代码说明#
provider 项目中,定义了一个 Controller ,用于接收用户请求,有如下的一个方法。
@RestController
@RequestMapping("/user")
public class UserController {
@RequestMapping(value = "/add", method = RequestMethod.GET)
public String addUser(User user, HttpServletRequest request) {
String token = request.getHeader("oauthToken");
return "hello, add user : " + user.getName();
}
……
}
基于上述两个服务,客户端 consumer 定义了一个 feign 客户端用于请求服务端的服务
@FeignClient(name = "provider")
public interface UserFeignService {
@RequestMapping(value = "/user/add", method = RequestMethod.GET)
String addUser(User user);
……
}
用于 feign 使用 GET 无法直接传递 POJO,所以定义如下一个拦截器,在 apply 方法种处理请求并封装成 POJO 发送给服务端,本实例中,我们要封装的是 User 对象
public class User {
private Long id;
private String name;
private int age;
// 省略 Get / Set 方法
}
定义的拦截器代码如下
@Component
public class FeignRequestInterceptor implements RequestInterceptor {
private final ObjectMapper objectMapper;
public FeignRequestInterceptor(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
}
@Override
public void apply(RequestTemplate template) {
if (template.method().equals("GET") && template.body() != null) {
try {
JsonNode jsonNode = objectMapper.readTree(template.body());
template.body(null, StandardCharsets.UTF_8);
Map<String, Collection<String>> queries = new HashMap<>();
buildQuery(jsonNode, "", queries);
template.queries(queries);
} catch (IOException e) {
e.printStackTrace();
}
}
}
private void buildQuery(JsonNode jsonNode, String path, Map<String, Collection<String>> queries) {
if (!jsonNode.isContainerNode()) {
if (jsonNode.isNull()) {
return;
}
Collection<String> values = queries.computeIfAbsent(path, k -> new ArrayList<>());
values.add(jsonNode.asText());
return;
}
if (jsonNode.isArray()) { // 数组节点
Iterator<JsonNode> it = jsonNode.elements();
while (it.hasNext()) {
buildQuery(it.next(), path, queries);
}
} else {
Iterator<Map.Entry<String, JsonNode>> it = jsonNode.fields();
while (it.hasNext()) {
Map.Entry<String, JsonNode> entry = it.next();
if (StringUtils.hasText(path)) {
buildQuery(entry.getValue(), path + "." + entry.getKey(), queries);
} else { // 根节点
buildQuery(entry.getValue(), entry.getKey(), queries);
}
}
}
}
}
测试一下,分别启动 register-server,provider,consumer 三个项目,使用 Postman 做如下请求
返回成功结果。
完整代码见:feign-usage
参考资料#
作者:GreyZeng
出处:https://www.cnblogs.com/greyzeng/p/16890723.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
你可以在这里自定义其他内容
本文来自博客园,作者:Grey Zeng,转载请注明原文链接:https://www.cnblogs.com/greyzeng/p/16890723.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· Vue3状态管理终极指南:Pinia保姆级教程
2016-11-14 Github团队开发示例(二)