feign 使用示例:@Body注解,http请求体
出现接口使用http请求体来传递参数的情况,所以研究了一下feign,发现@Body注解大致可以实现。
虽然说是使用请求体来传递参数,但实质上请求体还是放了json格式的数据。当然,如果不想只局限于json格式,可以将其设置为通用的格式,详见文末。
- maven依赖
<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 客户端初始化代码
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向服务端发送请求。
客户端的代码:
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");
服务端的代码:
@RequestMapping("/jsonBody")
@ResponseBody
public Object jsonBody(@RequestBody JSONObject body){
System.out.println(body);
return "success";
}
看了上面一个例子,你会感觉很鸡肋,这json还要预定义,这怎么玩嘛。
使用参数模板方式的请求体
使用String作为方法参数
上面例子我们知道,@Body注解支持"{}"形式的占位符,会将方法中的参数填充到模板中,嘿嘿嘿,我们直接将参数当做模板如何,见下
客户端的代码:
interface FeignClientAPI {
@RequestLine("POST /jsonBody")
@Headers("Content-Type: application/json")
@Body("{body}")
String jsonBody(@Param("body") String body);
}
发现区别了吗,我们直接给@Body注解定义了一个"{body}"。
那么客户端调用时,相应的传参就不是一个个字段了,而是一整个json。
//客户端调用
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转成字符串处理。
客户端的代码:
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);
服务端的代码不需要变化。
再进一步,将请求体与其他形式的参数配合使用
下面有三段扩展示例,每个示例包括客户端代码和服务端代码,客户端调用的代码你懂的吧,省略了。
/***************** 扩展一:请求体 + 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";
}
/***************** 扩展二:请求体 + 请求参数 ******************/
//客户端代码
@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";
}
/***************** 扩展三:请求体 + 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;”),表示这个请求体为普通文本类型。如下
@RequestLine("POST /stringBody")
//将请求内容设置为简单文本类型
@Headers("Content-Type: text/plain;")
@Body("{body}")
String stringBody(@Param("body") String body);
相应的,服务端代码使用String做接收参数,来接收请求体的内容。服务端接收到string后,转化为相应的类型
@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