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


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

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

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

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

    1 
    2 <dependency>
    3     <groupId>com.moonciki.strongfeign</groupId>
    4     <artifactId>feign-httpclient</artifactId>
    5     <version>10.2.3</version>
    6 </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

     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<String, Object> jsonMap = (Map<String, Object>)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<ParamModel> 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 }

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

    1     @Bean
    2     public Contract feignContract(){
    3         List<AnnotatedParameterProcessor> 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     }

    4. 使用方法示例

     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")  同时使用在不同参数上。

  • 相关阅读:
    可配置智联爬虫
    python 交错列表合并
    猫途鹰简单爬虫正则巩固
    urllib.error.URLError: urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:777) 解决办法
    与MongoDB有关的面试题
    go tcp socket
    postgresql摘要
    go+postgresql服务器
    go map slice array channel 传参
    postgresql 数据库学习
  • 原文地址:https://www.cnblogs.com/moonciki/p/11320548.html
Copyright © 2020-2023  润新知