Feign 实现 GET 方法传递 POJO

作者:Grey

原文地址:

博客园:Feign 实现 GET 方法传递 POJO

CSDN:Feign 实现 GET 方法传递 POJO

需求

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 配置

代码说明

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

参考资料

重新定义 Spring Cloud 实战

Feign 实现 GET 方法传递 POJO的更多相关文章

  1. Spring Boot 和 Spring Cloud Feign调用服务及传递参数踩坑记录

    背景 :在Spring Cloud Netflix栈中,各个微服务都是以HTTP接口的形式暴露自身服务的,因此在调用远程服务时就必须使用HTTP客户端.我们可以使用JDK原生的URLConnectio ...

  2. 【问题】Asp.net MVC 的cshtml页面中调用JS方法传递字符串变量参数

    [问题]Asp.net MVC 的cshtml页面中调用JS方法传递字符串变量参数. [解决]直接对变量加引号,如: <button onclick="deleteProduct('@ ...

  3. 如何解决Response.Redirect方法传递汉字丢失或乱码问题?

    为了确保传递的汉字被正确地接收,可以在传值之前使用Server对象的UrlEncode方法对所传递的汉字进行URL编码.代码如下: String name = Server.UrlEncode(&qu ...

  4. Jquery Ajax方法传递json到action

    ajax向后台传入json需要设置option,如下 contentType:'application/json' data:Json.Stringify(jsObj) 后台处理复杂json对象(不知 ...

  5. 给方法传递参数:ref参数和out参数

    /*--------------------------------------------------- 给方法传递参数:ref参数和out参数 (P106) ------------------- ...

  6. javascript重定向页面并用post方法传递消息

    javascript中重定向页面得方法很多,同时能传递消息的也不少:但可用post方法传递的我只找到两种: 第一种方法:用document.write在 JavaScript函数中,用document ...

  7. Vue把父组件的方法传递给子组件调用(评论列表例子)

    Vue把父组件的方法传递给子组件调用(评论列表例子) 效果展示: 相关Html: <!DOCTYPE html> <html lang="en"> < ...

  8. HTML的GET方法传递参数样式。

    #HTML的GET方法传递参数样式.http://127.0.0.1:8080/web1/urlinfo/getobject.html?UserId=1&UserName=ad

  9. mybatis由浅入深day01_ 7输入映射(7.1传递pojo的包装对象_7.2#{}与${}_7.3传递简单类型_7.4传递pojo对象_7.5传递hashmap)

    7 输入映射 通过parameterType指定输入参数的类型,类型可以是简单类型.hashmap.pojo的包装类型. 7.1 传递pojo的包装对象 7.1.1 需求 完成用户信息的综合查询,需要 ...

  10. tornado框架的get方法传递参数

    tornado框架的get方法传递参数,代码: # encoding: utf-8 """ @version: ?? @author: andu99 @contact: ...

随机推荐

  1. Docker实用篇

    Docker实用篇 0.学习目标 1.初识Docker 1.1.什么是Docker 微服务虽然具备各种各样的优势,但服务的拆分通用给部署带来了很大的麻烦. 分布式系统中,依赖的组件非常多,不同组件之间 ...

  2. helm安装metrics-server-3.8.2

    Application version 0.6.1 Chart version 3.8.2 获取chart包 helm repo add metrics-server https://kubernet ...

  3. Mac_mysql_密码重置

    1 通过Mac 的设置 stop mysql 2 跳过权限认证 // 进入数据库指令文件 cd /usr/local/mysql/bin // 跳过权限认证 sudo ./mysqld_safe -- ...

  4. 手把手教你君正X2000开发板的OpenHarmony环境搭建

    摘要:本文主要介绍基于君正X2000开发板的OpenHarmony环境搭建以及简单介绍网络配置情况 本文分享自华为云社区<君正X2000开发板的OpenHarmony环境搭建>,作者: 星 ...

  5. VSCODE 配置远程调试环境

    以下内容为本人的著作,如需要转载,请声明原文链接微信公众号「englyf」https://www.cnblogs.com/englyf/p/16691460.html 我的需求是,在Windows桌面 ...

  6. Centos7下安装postgresql(tar包形式安装)

    Centos7下安装postgresql(tar包形式安装) 1.官网下载地址: https://www.postgresql.org/ftp/source/ 2.将下载来tar包上传到linux服务 ...

  7. 输入法词库解析(四)百度分类词库.bdict(.bcd)

    前言 .bdict 是百度的分类词库格式,可以在 https://shurufa.baidu.com/dict 下载. 手机百度的分类词库格式 .bcd 是一样的,可以在 https://mime.b ...

  8. es证书生成方式

    ./bin/elasticsearch-certutil ca --pem # 生成一个名字叫做elastic-stack-ca.zip的文件 unzip elastic-stack-ca.zip A ...

  9. k8s安装常用软件的yaml文件

    参考网址:https://www.bejson.com (网站文件部分有坑,需要擦亮眼睛) nginx k8s版本:v1.20 apiVersion: apps/v1 kind: Deployment ...

  10. 使用Fluentd进行简单流处理

    在某些日志采集场景中,我们需要对数据流进行一些转换.比如,我们可能需要从日志记录中提取某些字段以进行错误告警,或向日志记录中插入新的字段用以后续的分析. 本文简单介绍一下使用Fluentd进行数据操作 ...