在平时使用过程中,GET请求是可以直接使用实体参数的,但是当使用feign调用时,会报错。这时了解到使用feign调用时,如果是实体对象,会将参数写入body,而GET请求是不使用body的。这种情况应该怎么处理呢,我有三种办法:
1. 修改服务者。
既然get请求在使用feign的时候无法使用实体,那就修改为post/PUT请求,这样就能使用实体了。但是此种方法时,如果服务提供方使用的restful风格,只是查询数据,居然修改为post请求,这就不合理了。并且如果是跨部门的合作,去要求服务提供者修改,这就更加不现实了。
2. 修改传参格式。
既然服务提供方无法去强制要求,那我们消费端只能修改传参条件。我们可以直接使用Map来传参,只需要加上注解就可以了。
@RequestParam Map param,简单实用。
3. 仍然传入实体对象。
对于第二种方法,传入map可谓是一了百了,但是在实际过程中,应该很多公司都杜绝使用此种方式,map虽然写的简单,但是别人不能一目了然的了解这个map里有什么,换个人来看,就只知道各种map在传递,但是里面具体有什么值,会导致什么后果都无法进行判断,对比接口时也发现,feign的请求和服务提供者的请求不一致。因此,这样也是很多具有代码洁癖,追求代码优雅的人无法忍受的。那么,应该怎么传入实体呢。
在上一篇https://blog.csdn.net/woyyazj/article/details/106283333使用springcloud feign时 token认证 其实已经提到了,我们可以使用增加拦截器的方式,来先处理我们的请求。既然实体对象不能传入body,那么我们能不能直接从body里获取出来,然后在放到参数里去呢?答案当然是肯定的。我们可以先查看RequestTemplate的源码,发现里面存在2个属性,对于我们来说比较重要
private final Map<String, QueryTemplate> queries = new LinkedHashMap<>();
private Request.Body body = Request.Body.empty();
我们要处理的也就是这2个参数,我们可以先从body里把我们的实体对象获取出来,然后再将参数存入queries,再清空body,这不就完成我们的目的了吗?
public Request.Body requestBody() {
return this.body;
}
public RequestTemplate query(String name, String... values) {
if (values == null) {
return query(name, Collections.emptyList());
}
return query(name, Arrays.asList(values));
}
上面2个方法,就是分别取出body,和给queries加入参数的方法。然后找了一圈,未找到清理body的方法,怎么办.,反射啊,反射去修改不要太简单,很轻松就完成了,达到我们的目的。代码如下
import com.alibaba.fastjson.JSON;
import feign.Request;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.apache.commons.lang.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class FeignConfig implements RequestInterceptor {
@Override
public void apply(RequestTemplate requestTemplate) {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
//添加token
requestTemplate.header("Authorization", request.getHeader("Authorization"));
//将body的数据写入参数
if("GET".equals(requestTemplate.method())){
try{
//获取body内容
String json = requestTemplate.requestBody().asString();
if (StringUtils.isEmpty(json)) {
return ;
}
Map<String, Object> map= JSON.parseObject(json);
Set<String> set = map.keySet();
Iterator<String> it = set.iterator();
while (it.hasNext()) {
String key = (String) it.next();
Object values = map.get(key);
if (values!=null && !"".equals(values) && !"null".equals(values)) {
//将body的参数写入queries
requestTemplate.query(key,values.toString());
}
}
Class requestClass=requestTemplate.getClass();
Field field = requestClass.getDeclaredField("body");
field.setAccessible(true);
//修改body为空。
field.set(requestTemplate, Request.Body.empty());
}catch (Exception e){
}
}
}
}
以上三种方法都介绍了,至于怎么选择,依据自身情况吧