您的位置:首页 > 编程语言 > Java开发

Spring cloud Feign不支持对象传参解决办法[完美解决]

2019-08-08 13:11 4591 查看

    spring cloud 使用 Feign 进行服务调用时,不支持对象参数。

    通常解决方法是,要么把对象每一个参数平行展开,并使用 @RequestParam 标识出每一个参数,要么用 @RequestBody 将请求改为 body 传参,虽然这样解决了问题,但是这样限制了传参方式,并且使代码变得很繁重。

    以下为完美解决 Feign 对象传参问题的办法。

1. 引入如下依赖(可以在maven仓库中搜索 strongfeign)

<dependency>
<groupId>com.moonciki.strongfeign</groupId>
<artifactId>feign-httpclient</artifactId>
<version>10.2.3</version>
</dependency>

该源码修改自 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. 创建如下三个类

    开始时,打算把以下三个类加进仓库中,但由于如下三个类内容不多,并且有很多定制化的可能,因此单独实现。

    2.1 ParamModel.java

package com.moonciki.strongfeign.model.annotation;

import java.lang.annotation.*;

@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ParamModel {
String value() default "";
}

    2.2 ModelExpander.java

package com.moonciki.strongfeign.model.expander;

import com.alibaba.fastjson.JSON;
import feign.Param;
import lombok.extern.slf4j.Slf4j;

import java.util.Map;

@Slf4j
public class ModelExpander implements Param.Expander {

public String expand(Object value) {
String objectJson = JSON.toJSONString(value);
return objectJson;
}

@Override
public String expandWithName(Object value, String name) {
String valueExpand = null;

if(value != null){
if(name != null) {
try {
Map<String, Object> jsonMap = (Map<String, Object>)JSON.toJSON(value);

Object getValue = jsonMap.get(name);
if(getValue != null){
valueExpand = getValue.toString();
}
} catch (Exception e) {
log.error("GET VALUE ERROR:", e);
}
}else {
valueExpand = value.toString();
}
}

return valueExpand;
}
}

注:该类需依赖 fastjson,也可根据个人需要修改该方法。

    2.3 ParamModelParameterProcessor.java

package com.moonciki.strongfeign.model.processor;

import com.moonciki.strongfeign.model.annotation.ParamModel;
import com.moonciki.strongfeign.model.expander.ModelExpander;
import feign.MethodMetadata;
import org.springframework.cloud.openfeign.AnnotatedParameterProcessor;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collection;

public class ParamModelParameterProcessor implements AnnotatedParameterProcessor {

private static final Class<ParamModel> ANNOTATION = ParamModel.class;

public Class<? extends Annotation> getAnnotationType() {
return ANNOTATION;
}

@Override
public boolean processArgument(AnnotatedParameterContext context, Annotation annotation, Method method) {

int parameterIndex = context.getParameterIndex();
Class parameterType = method.getParameterTypes()[parameterIndex];
MethodMetadata data = context.getMethodMetadata();

Field[] fields = parameterType.getDeclaredFields();

for(Field field: fields) {
String name = field.getName();
context.setParameterName(name);

Collection query = context.setTemplateParameter(name, (Collection)data.template().queries().get(name));
data.template().query(name, query);
}
data.indexToExpander().put(context.getParameterIndex(), new ModelExpander());

return true;
}
}

 

3. 使用注解配置 feign Contract 对象

@Bean
public Contract feignContract(){
List<AnnotatedParameterProcessor> processors = new ArrayList<>();
processors.add(new ParamModelParameterProcessor());
processors.add(new PathVariableParameterProcessor());
processors.add(new RequestHeaderParameterProcessor());
processors.add(new RequestParamParameterProcessor());
return new SpringMvcContract(processors);
}

 

4. 使用方法示例

@Primary
@FeignClient(value = "/user", fallback = UserClientFallback.class)
public interface UserClient {

/**
* demo post
* @return
*/
@PostMapping("/demoPost")
Result demoPost(@ParamModel UserAccount userAccount);

/**
* demo get
* @return
*/
@GetMapping("/demoGet")
Result demoPost(@ParamModel UserAccount userAccount);

}

使用时,只需要在对象前加 @ParamModel  注解即可

需要同时传递对象及基本类型参数时, @ParamModel 可以与 @RequestParam("jobName")  同时使用在不同参数上。

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: