Margrop
Articles158
Tags353
Categories21
1password AC AP API AppDaemon Aqara Cron Date Diagrams.net HA HADashboard HomeAssistant IP IPv4 Java LVM‑Thin Linux MacOS MySQL NAS PPPoE PostgreSQL ProcessOn Proxmox VE SSL Shell TTS TimeMachine UML Uptime Kuma Web Windows activate ad adb adblock agent aligenie aliyun alpine annotation aop authy autofs backup baidupan bash bitwarden boot brew browser caddy2 cdn centos cert certbot charles chat chrome classloader client clone closures cloudflare cmd command commit container crontab ctyun ddsm demo dependency deploy developer devtools dll dns docker domain download draw drawio dsm dump dylib edge exception export fail2ban feign firewall-cmd flow frp frpc frps fuckgfw function gcc gfw git github golang gperftools gridea grub gvt-g hacs havcs heap hello hexo hibernate hidpi hoisting homeassistant hosts html htmlparser https idea image img img2kvm import index install intel io ios ip iptables iptv ipv6 iso java javascript jetbrains jni jnilib jpa js json jsonb jupter jupyterlab jvm k8s kernel key kid kms kodi koolproxy koolproxyr kvm lan lastpass launchctl learning lede letsencrypt linux live low-code lvm lxc m3u8 mac macos mariadb markdown maven md5 microcode mirror modem modules monitor mount mstsc mysql n2n n5105 nas network nfs node node-red nodejs nohup notepad++ npm nssm ntp oop openfeign openssl os otp ovz packet capture pat pdf pem perf ping pip plugin png powerbutton print pro proxy pve pvekclean python qcow2 qemu qemu-guest-agent rar reboot reflog remote remote desktop renew repo resize retina root route router rule rules runtime safari sata scipy-notebook scoping scp server slmgr so socks source spk spring springboot springfox ssh ssl stash string supernode svg svn swagger sync synology systemctl tap tap-windows tapwindows telecom template terminal tls token totp tvbox txt ubuntu udisk ui undertow uninstall unlocker upgrade url v2ray vhd vim vlmcsd vm vmdk web websocket wechat windows with worker wow xiaoya xml yum zip 中国电信 云电脑 交换机 光猫 公网IP 内存 内网IP 升级 启动 夏令时 天猫精灵 天翼云 安装 容器 导入 小米 常用软件 广告屏蔽 序列号 应用市场 异常 抓包 描述文件 时区 显卡虚拟化 智能家居 智能音箱 梯子 模块 流程 流程图 浏览器 漫游 激活 火绒 电信 画图 直播源 续期 网关 网络风暴 群晖 腾讯 虚拟机 证书 路由 路由器 软件管家 软路由 运维监控 镜像 镜像源 门窗传感器 防火墙 阿里云 阿里源 集客

Hitokoto

Archive

feign 使用示例:@Body注解,http请求体

feign 使用示例:@Body注解,http请求体

出现接口使用http请求体来传递参数的情况,所以研究了一下feign,发现@Body注解大致可以实现。
虽然说是使用请求体来传递参数,但实质上请求体还是放了json格式的数据。当然,如果不想只局限于json格式,可以将其设置为通用的格式,详见文末。

  • maven依赖
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    <dependency><!-- 更容易的调用第三方接口 -->
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-slf4j</artifactId>
    <version>11.0</version>
    </dependency>
    <dependency><!-- 更容易的调用第三方接口 -->
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-okhttp</artifactId>
    <version>11.0</version>
    </dependency>
    <dependency><!-- 更容易的调用第三方接口 -->
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-gson</artifactId>
    <version>11.0</version>
    </dependency>
    OpenFeign 客户端初始化代码
    1
    2
    3
    4
    5
    6
    7
    Feign.builder()
    .client(new OkHttpClient())
    .encoder(new GsonEncoder())
    .decoder(new GsonDecoder())
    .logger(new Slf4jLogger())
    .logLevel(feign.Logger.Level.FULL)
    .target(ApplyV3Api.class, server);
    先来一个简单的例子

使用预定义模板方式的请求体

使用@Body注解,定义模板。客户端通过feign向服务端发送请求。
客户端的代码:

1
2
3
4
5
6
7
8
9
10
interface FeignClientAPI {
@RequestLine("POST /jsonBody")
@Headers("Content-Type: application/json")
//因为'{}'在模板中有特殊作用(占位符),所以json的首尾中括号需要转义。'{'=>'%7B','}'=>'%7D'
@Body("%7B\"id\": \"{id}\", \"name\": \"{name}\"%7D")
String jsonBody(@Param("id") String id, @Param("name") String name);
}
```java
//客户端调用
feignClient.jsonBody("xxId", "xxName");

服务端的代码:

1
2
3
4
5
6
@RequestMapping("/jsonBody")
@ResponseBody
public Object jsonBody(@RequestBody JSONObject body){
System.out.println(body);
return "success";
}

看了上面一个例子,你会感觉很鸡肋,这json还要预定义,这怎么玩嘛。

使用参数模板方式的请求体

使用String作为方法参数

上面例子我们知道,@Body注解支持”{}”形式的占位符,会将方法中的参数填充到模板中,嘿嘿嘿,我们直接将参数当做模板如何,见下
客户端的代码:

1
2
3
4
5
6
interface FeignClientAPI {
@RequestLine("POST /jsonBody")
@Headers("Content-Type: application/json")
@Body("{body}")
String jsonBody(@Param("body") String body);
}

发现区别了吗,我们直接给@Body注解定义了一个”{body}”。
那么客户端调用时,相应的传参就不是一个个字段了,而是一整个json。

1
2
3
4
5
//客户端调用
JSONObject body = new JSONObject();
body.put("id", "xxId");
body.put("name", "xxName");
feignClient.jsonBody(body.toJSONString());

服务端的代码不需要变化。

使用Bean作为方法参数(toString)

feign方法参数使用String类型总感觉诸多不便,通过翻阅代码(详见feign.template.Expressions.SimpleExpression#expand(java.lang.Object, boolean)),发现可以直接使用对象参数,不过使用的对象需要重写toString方法,因为内部实现是调用对象的toString转成字符串处理。

客户端的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
interface FeignClientAPI {
@RequestLine("POST /jsonBody")
@Headers("Content-Type: application/json")
@Body("{body}")
String jsonBody(@Param("body") InitBean bean);
}

@lombok.Data
public class InitBean {
private String id;
private String name;

public String toString(){
return com.alibaba.fastjson.JSON.toJSONString(this);
}
}```
客户端调用时,直接传Bean。
```java
//客户端调用
InitBean bean = new InitBean ().setId("xxId").setName("xxName");
feignClient.jsonBody(bean);

服务端的代码不需要变化。

再进一步,将请求体与其他形式的参数配合使用

下面有三段扩展示例,每个示例包括客户端代码和服务端代码,客户端调用的代码你懂的吧,省略了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/***************** 扩展一:请求体 + Restful风格URL ******************/
//客户端代码
@RequestLine("POST /jsonBody/{path}")
@Headers("Content-Type: application/json")
@Body("{body}")
String jsonBodyAndPath(@Param("body") String body, @Param(value="path") String path);
//服务端代码
@RequestMapping("/jsonBody/{path}")
@ResponseBody
public Object jsonBodyAndPath(@RequestBody JSONObject body, @PathVariable String path){
System.out.println(body);
System.out.println(path);
return "success";
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/***************** 扩展二:请求体 + 请求参数 ******************/
//客户端代码
@RequestLine("POST /jsonBodyWithParam")
@Headers("Content-Type: application/json")
@Body("{body}")
String jsonBodyWithParam(@Param("body") String body, @QueryMap Map map);

//服务端代码
@RequestMapping("/jsonBodyWithParam")
@ResponseBody
public Object jsonBodyWithParam(@RequestBody JSONObject body, @RequestParam String param){
System.out.println(body);
System.out.println(param);
return "success";
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/***************** 扩展三:请求体 + Restful风格URL + 请求参数 ******************/
//客户端代码
@RequestLine("POST /jsonBodyAndPathWithParam/{path}")
@Headers("Content-Type: application/json")
@Body("{body}")
String jsonBodyAndPathWithParam(@Param("body") String body, @Param(value="path") String path, @QueryMap Map map);

//服务端代码
@RequestMapping("/jsonBodyAndPathWithParam/{path}")
@ResponseBody
public Object jsonBodyAndPathWithParam(@RequestBody JSONObject body, @PathVariable String path, @RequestParam String param){
System.out.println(body);
System.out.println(path);
System.out.println(param);
return "success";
}

希望上面代码的排版不会把你搞蒙(写一起会比较紧凑吧/捂脸)

扩展一下,非json格式的请求体

上面的示例都是以请求体为json格式数据为大前提,那么,遇到不是json格式的请求体,比如是xml格式的呢??
这里我是直接将客户端的代码的请求头改为了 @Headers(“Content-Type: text/plain;”),表示这个请求体为普通文本类型。如下

1
2
3
4
5
@RequestLine("POST /stringBody")
//将请求内容设置为简单文本类型
@Headers("Content-Type: text/plain;")
@Body("{body}")
String stringBody(@Param("body") String body);

相应的,服务端代码使用String做接收参数,来接收请求体的内容。服务端接收到string后,转化为相应的类型

1
2
3
4
5
6
7
8
9
10
11
@RequestMapping("/stringBody")
@ResponseBody
public Object stringBody(@RequestBody String body) throws DocumentException {
System.out.println(body);
//string 转 json
JSONObject jsonObject = com.alibaba.fastjson.JSONObject.parseObject(body);
//或者 string 转 xml
Document document = org.dom4j.DocumentHelper.parseText(body);
//或其他...
return "success";
}

基本是上述思路,还没有发掘其他方式实现,如果更好的实现方式,感谢分享,一起探讨。

参考文章

https://blog.csdn.net/qq_31772441/article/details/100176834
https://blog.csdn.net/sinat_36553913/article/details/104469418
https://blog.csdn.net/sinat_36553913/article/details/104527072
https://www.jianshu.com/p/0834508b7a6d

Author:Margrop
Link:http://blog.margrop.com/post/feign-demo/
版权声明:本文采用 CC BY-NC-SA 3.0 CN 协议进行许可