出现问题的原因
较早springboot2.1.x版本中,feign是不原生支持get形式的pojo的方式传参的,但是查询的时候,我们遵循restfull Api的开发规范,此时传递的参数,就会接收不到(为null).
解决方案一
升级springboot版本到2.1.x.使用Spring Cloud OpenFeign提供@SpringQueryMap注解,用于将POJO或Map参数注释为查询参数映射。
1.定义一个pojo类
@Setter
@Getter
public class Params {
private String param1;
private String param2;
}
2.以下feign客户端使用注释使用Params该类@SpringQueryMap:
@FeignClient(“demo”)
公共 类 DemoTemplate {
@GetMapping(path =“/ demo”)
String demoEndpoint( @SpringQueryMap Params params);
}
此时会出现一个异常: Method xxx not annotated with HTTP method type (ex. GET, POST),这个是由于 @RequestLine is a core Feign annotation, but you are using the Spring Cloud @FeignClientwhich uses Spring MVC annotations.研究源码发现:在Contract接口中:
protected MethodMetadata parseAndValidateMetadata(Class<?> targetType, Method method) {
MethodMetadata data = new MethodMetadata();
data.returnType(Types.resolve(targetType, targetType, method.getGenericReturnType()));
data.configKey(Feign.configKey(targetType, method));
if (targetType.getInterfaces().length == 1) {
processAnnotationOnClass(data, targetType.getInterfaces()[0]);
}
processAnnotationOnClass(data, targetType);
for (Annotation methodAnnotation : method.getAnnotations()) {
processAnnotationOnMethod(data, methodAnnotation, method);
}
checkState(data.template().method() != null,
"Method %s not annotated with HTTP method type (ex. GET, POST)",
method.getName());
Class<?>[] parameterTypes = method.getParameterTypes();
Type[] genericParameterTypes = method.getGenericParameterTypes();
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
意思就是feign 默认使用的是spring mvc 注解(就是RequestMapping 之类的), 所以需要配置自定义的:Contract
@Bean
public Contract customerContract(){
return new feign.Contract.Default();
}
解决方案二
@Component
@Slf4j
public class FeignCustomRequestInteceptor implements RequestInterceptor {
@Autowired
private ObjectMapper objectMapper;
@Override
public void apply(RequestTemplate template) {
if (HttpMethod.GET.toString() == template.method() && template.body() != null) {
//feign 不支持GET方法传输POJO 转换成json,再换成query
try {
Map<String, Collection<String>> map = objectMapper.readValue(template.bodyTemplate(), new TypeReference<Map<String, Collection<String>>>() {
});
template.body(null);
template.queries(map);
} catch (IOException e) {
log.error("cause exception", e);
}
}
}
总结
feign调用会有很多的坑坑洼洼,大家多看下文档,或许你的收益会不一样。