Spring cloud Feign不支持对象传参解决办法[完美解决]
spring cloud 使用 Feign 进行服务调用时,不支持对象参数。
通常解决方法是,要么把对象每一个参数平行展开,并使用 @RequestParam 标识出每一个参数,要么用 @RequestBody 将请求改为 body 传参,虽然这样解决了问题,但是这样限制了传参方式,并且使代码变得很繁重。
以下为完美解决 Feign 对象传参问题的办法。
- 引入如下依赖(可以在maven仓库中搜索 strongfeign)
复制代码
1
2
3 com.moonciki.strongfeign
4 feign-httpclient
5 10.2.3
6
复制代码
该源码修改自 https://github.com/OpenFeign/feign,提交过pr,但是项目原作者并没有采纳,pr地址如下:https://github.com/OpenFeign/feign/pull/949
之后为了同步到了maven 仓库,做了相应删减及pom的变更,具体改动可参考github。地址:https://github.com/cdmamata/strong-feign
注意:不要使用 10.3.x版本,该版本有问题。如果jar包无法下载请使用 maven 中央仓库。
-
创建如下三个类
开始时,打算把以下三个类加进仓库中,但由于如下三个类内容不多,并且有很多定制化的可能,因此单独实现。 2.1 ParamModel.java
复制代码
1 package com.moonciki.strongfeign.model.annotation;
2
3 import java.lang.annotation.*;
4
5 @Target({ElementType.PARAMETER})
6 @Retention(RetentionPolicy.RUNTIME)
7 @Documented
8 public @interface ParamModel {
9 String value() default "";
10 }
复制代码
2.2 ModelExpander.java
复制代码
1 package com.moonciki.strongfeign.model.expander;
2
3 import com.alibaba.fastjson.JSON;
4 import feign.Param;
5 import lombok.extern.slf4j.Slf4j;
6
7 import java.util.Map;
8
9 @Slf4j
10 public class ModelExpander implements Param.Expander {
11
12 public String expand(Object value) {
13 String objectJson = JSON.toJSONString(value);
14 return objectJson;
15 }
16
17 @Override
18 public String expandWithName(Object value, String name) {
19 String valueExpand = null;
20
21 if(value != null){
22 if(name != null) {
23 try {
24 Map jsonMap = (Map)JSON.toJSON(value);
25
26 Object getValue = jsonMap.get(name);
27 if(getValue != null){
28 valueExpand = getValue.toString();
29 }
30 } catch (Exception e) {
31 log.error("GET VALUE ERROR:", e);
32 }
33 }else {
34 valueExpand = value.toString();
35 }
36 }
37
38 return valueExpand;
39 }
40 }
复制代码
注:该类需依赖 fastjson,也可根据个人需要修改该方法。
2.3 ParamModelParameterProcessor.java
复制代码
1 package com.moonciki.strongfeign.model.processor;
2
3 import com.moonciki.strongfeign.model.annotation.ParamModel;
4 import com.moonciki.strongfeign.model.expander.ModelExpander;
5 import feign.MethodMetadata;
6 import org.springframework.cloud.openfeign.AnnotatedParameterProcessor;
7
8 import java.lang.annotation.Annotation;
9 import java.lang.reflect.Field;
10 import java.lang.reflect.Method;
11 import java.util.Collection;
12
13
14 public class ParamModelParameterProcessor implements AnnotatedParameterProcessor {
15
16 private static final Class ANNOTATION = ParamModel.class;
17
18 public Class<? extends Annotation> getAnnotationType() {
19 return ANNOTATION;
20 }
21
22 @Override
23 public boolean processArgument(AnnotatedParameterContext context, Annotation annotation, Method method) {
24
25 int parameterIndex = context.getParameterIndex();
26 Class parameterType = method.getParameterTypes()[parameterIndex];
27 MethodMetadata data = context.getMethodMetadata();
28
29 Field[] fields = parameterType.getDeclaredFields();
30
31 for(Field field: fields) {
32 String name = field.getName();
33 context.setParameterName(name);
34
35 Collection query = context.setTemplateParameter(name, (Collection)data.template().queries().get(name));
36 data.template().query(name, query);
37 }
38 data.indexToExpander().put(context.getParameterIndex(), new ModelExpander());
39
40 return true;
41 }
42 }
复制代码
- 使用注解配置 feign Contract 对象
复制代码
1 @Bean
2 public Contract feignContract(){
3 List processors = new ArrayList<>();
4 processors.add(new ParamModelParameterProcessor());
5 processors.add(new PathVariableParameterProcessor());
6 processors.add(new RequestHeaderParameterProcessor());
7 processors.add(new RequestParamParameterProcessor());
8 return new SpringMvcContract(processors);
9 }
复制代码
- 使用方法示例
复制代码
1 @Primary
2 @FeignClient(value = "/user", fallback = UserClientFallback.class)
3 public interface UserClient {
4
5 /**
6 * demo post
7 * @return
8 */
9 @PostMapping("/demoPost")
10 Result demoPost(@ParamModel UserAccount userAccount);
11
12 /**
13 * demo get
14 * @return
15 */
16 @GetMapping("/demoGet")
17 Result demoPost(@ParamModel UserAccount userAccount);
18
19
20 }
复制代码
使用时,只需要在对象前加 @ParamModel 注解即可
需要同时传递对象及基本类型参数时, @ParamModel 可以与 @RequestParam("jobName") 同时使用在不同参数上。
原文地址https://www.cnblogs.com/moonciki/p/11320548.html