A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

本帖最后由 小蜀哥哥 于 2019-8-8 17:26 编辑

    spring cloud 使用 Feign 进行服务调用时,不支持对象参数。
    通常解决方法是,要么把对象每一个参数平行展开,并使用 @RequestParam 标识出每一个参数,要么用 @RequestBody 将请求改为 body 传参,虽然这样解决了问题,但是这样限制了传参方式,并且使代码变得很繁重。
    以下为完美解决 Feign 对象传参问题的办法
1. 引入如下依赖(可以在maven仓库中搜索 strongfeign)
[AppleScript] 纯文本查看 复制代码
<dependency>
    <groupId>com.moonciki.strongfeign</groupId>
    <artifactId>feign-httpclient</artifactId>
    <version>10.2.3</version>
</dependency>
注意:不要使用 10.3.x版本,该版本有问题。如果jar包无法下载请使用 maven 中央仓库。
2. 创建如下三个类
    开始时,打算把以下三个类加进仓库中,但由于如下三个类内容不多,并且有很多定制化的可能,因此单独实现。
    2.1 ParamModel.java
[AppleScript] 纯文本查看 复制代码
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
[AppleScript] 纯文本查看 复制代码
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
[AppleScript] 纯文本查看 复制代码
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 对象
[AppleScript] 纯文本查看 复制代码
@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. 使用方法示例
[AppleScript] 纯文本查看 复制代码
@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")  同时使用在不同参数上。

0 个回复

您需要登录后才可以回帖 登录 | 加入黑马