广告
返回顶部
首页 > 资讯 > 精选 >Spring Cloud Feign使用对象参数的方法
  • 193
分享到

Spring Cloud Feign使用对象参数的方法

2023-06-29 06:06:25 193人浏览 薄情痞子
摘要

本文小编为大家详细介绍“spring Cloud Feign使用对象参数的方法”,内容详细,步骤清晰,细节处理妥当,希望这篇“Spring Cloud Feign使用对象参数的方法”文章能帮助大家解决

本文小编为大家详细介绍“spring Cloud Feign使用对象参数的方法”,内容详细,步骤清晰,细节处理妥当,希望这篇“Spring Cloud Feign使用对象参数的方法”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。

概述

spring cloud Feign 用于微服务的封装,通过接口代理的实现方式让微服务调用变得简单,让微服务的使用上如同本地服务。但是它在传参方面不是很完美。在使用 Feign 代理 GET 请求时,对于简单参数(基本类型、包装器、字符串)的使用上没有困难,但是在使用对象传参时却无法自动的将对象包含的字段解析出来。

如果你没耐心看完,直接跳到最后一个标题跟着操作就行了。

@RequestBody

对象传参是很常见的操作,虽然可以通过一个个参数传递来替代,但是那样就太麻烦了,所以必须解决这个问题。

我在网上看到有人用 @RequestBody 来注解对象参数,我在尝试后发现确实可用。这个方案实际使用 body 体装了参数(使用的是 GET 请求),但是这个方案有些问题:

  1. 注解需要在 consumer 和 provider 两边都有,这造成了麻烦

  2. 使用接口测试工具 Postman 无法跑通微服务,后来发现是因为 body 体的格式选择不正确,这个格式不是通常的表单或者路径拼接,而是 GraphQL。我没有研究过这种格式应该如何填写参数,但是 Postman 上并没有给出像表单那样方便的格式,这对于测试是很不利的。

@SpringQueryMap

于是我继续寻找答案,发现可以使用 @SpringQueryMap 仅添加在 consumer 的参数上就能自动对 Map 类型参数编码再拼接到 URL 上。而我用的高版本的 Feign,可以直接把对象编码。

可是正当我以为得到正解时,却发现还是有问题:

我明明在 Date 类型的字段上加上了 @DateTimeFORMat(pattern = "yyyy-MM-dd"),却没有生效,他用自己的方式进行了编码(或者说序列化),而且官方确实没有提供这种格式化方式。

又一番找寻后发现了一位大佬自己实现了一个注解转换替代 @SpringQueryMap,并实现了丰富的格式化功能 ORZ,只能说佩服佩服。但是我没有那样的技术,又不太想复制粘贴他那一大堆的代码,因为出了问题也不好改,所以我还是想坚持最大限度地使用框架,最小限度的给框架填坑。

QueryMapEncoder

终于功夫不费有心人,我发现了 Feign 预留的自定义编码器接口 QueryMapEncoder,框架提供了两个实现:

  • FieldQueryMapEncoder

  • BeanQueryMapEncoder

虽然这两个实现不能满足我的要求,但是只要稍加修改写一个自己的实现类就行了,于是我在 FieldQueryMapEncoder 的基础上修改,仅仅添加了一个方法,小改了一个方法就实现了功能。

原理:Feign 其实还是用 Map<String, Object> 进行的编码,编码方式也很简单,String 是 key,Object 是 value。最开始的方式就是用 Object 的 toString() 方法把参数编码,这也是为什么 Date 字段会变成一个默认的时间格式,因为 toString() 根本和 @DateTimeFormat 没有关系。而高版本使用编码器实现了对象传参,实际实际上是通过简单的反射获取对象的元数据,再放到 Map 中。

上面的原理都能从 @DateTimeFormat 的注释和编码器的源码中得到答案。

我们要做的就是自定义一个编码器,实现在元数据放入 Map 之前根据需要把字段变成我们想要的字符串。下面是我实现的代码,供参考:

package com.example.billmanagerfront.config.encoder;import java.lang.reflect.Field;import java.text.DateFormat;import java.text.SimpleDateFormat;import java.util.ArrayList;import java.util.Collections;import java.util.List;import java.util.Map;import java.util.Optional;import java.util.TimeZone;import java.util.concurrent.ConcurrentHashMap;import java.util.stream.Collectors;import org.springframework.format.annotation.DateTimeFormat;import feign.Param;import feign.QueryMapEncoder;import feign.codec.EncodeException;public class PowerfulQueryMapEncoder implements QueryMapEncoder {    private final Map<Class<?>, ObjectParamMetadata> classToMetadata = new ConcurrentHashMap<>();    @Override    public Map<String, Object> encode(Object object) throws EncodeException {        ObjectParamMetadata metadata = classToMetadata.computeIfAbsent(object.getClass(),                ObjectParamMetadata::parseObjectType);        return metadata.objectFields.stream()                .map(field -> this.FieldValuePair(object, field))                .filter(fieldObjectPair -> fieldObjectPair.right.isPresent())                .collect(Collectors.toMap(this::fieldName, this::fieldObject));    }    private String fieldName(Pair<Field, Optional<Object>> pair) {        Param alias = pair.left.getAnnotation(Param.class);        return alias != null ? alias.value() : pair.left.getName();    // 可扩展为策略模式,支持更多的格式转换    private Object fieldObject(Pair<Field, Optional<Object>> pair) {        Object fieldObject = pair.right.get();        DateTimeFormat dateTimeFormat = pair.left.getAnnotation(DateTimeFormat.class);        if (dateTimeFormat != null) {            DateFormat format = new SimpleDateFormat(dateTimeFormat.pattern());            format.setTimeZone(TimeZone.getTimeZone("GMT+8")); // TODO: 最好不要写死时区            fieldObject = format.format(fieldObject);        } else {        }        return fieldObject;    private Pair<Field, Optional<Object>> FieldValuePair(Object object, Field field) {        try {            return Pair.pair(field, Optional.ofNullable(field.get(object)));        } catch (IllegalAccessException e) {            throw new EncodeException("Failure encoding object into query map", e);    private static class ObjectParamMetadata {        private final List<Field> objectFields;        private ObjectParamMetadata(List<Field> objectFields) {            this.objectFields = Collections.unmodifiableList(objectFields);        private static ObjectParamMetadata parseObjectType(Class<?> type) {            List<Field> allFields = new ArrayList<Field>();            for (Class<?> currentClass = type; currentClass != null; currentClass = currentClass.getSuperclass()) {                Collections.addAll(allFields, currentClass.getDeclaredFields());            }            return new ObjectParamMetadata(allFields.stream()                    .filter(field -> !field.isSynthetic())                    .peek(field -> field.setAccessible(true))                    .collect(Collectors.toList()));    private static class Pair<T, U> {        private Pair(T left, U right) {            this.right = right;            this.left = left;        public final T left;        public final U right;        public static <T, U> Pair<T, U> pair(T left, U right) {            return new Pair<>(left, right);}

加注释的方法,就是我后添加进去的。encode 方法的最后一行稍微修改了一下,引用了我加的方法,其他都是直接借鉴过来的(本来我想更偷懒,直接继承一下子,但是它用了私有的内部类导致我只能全部复制粘贴了)。

解决方案

不用引入其他的 Feign 依赖,保证有下面这个就行(看网上其他方法还要引入特定依赖,要对应版本号,挺麻烦的)

<dependency>    <groupId>org.springframework.cloud</groupId>    <artifactId>spring-cloud-starter-openfeign</artifactId></dependency>

编写上面那样的类,你可以直接复制过去改个包名就行,如果还需要除了 Date 以外的格式化,请看注释和文章分析。其中我对日期的格式化,直接使用了 @DateTimeFormat 提供的模式,和 Spring 保持了一致。

编写一个 Feign 配置类,将刚自定义的编码器注册进去。细节我就不多说了:

package com.example.billmanagerfront.config;import com.example.billmanagerfront.config.encoder.PowerfulQueryMapEncoder;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import feign.Feign;import feign.Retryer;@Configurationpublic class FeignConfig {    @Bean    public Feign.Builder feignBuilder() {        return Feign.builder()                .queryMapEncoder(new PowerfulQueryMapEncoder())                .retryer(Retryer.NEVER_RETRY);    }}

Feign 代理接口中声明使用这个配置类,细节不谈

package com.example.billmanagerfront.client;import java.util.List;import com.example.billmanagerfront.config.FeignConfig;import com.example.billmanagerfront.pojo.Bill;import com.example.billmanagerfront.pojo.BillType;import org.springframework.cloud.openfeign.FeignClient;import org.springframework.cloud.openfeign.SpringQueryMap;import org.springframework.WEB.bind.annotation.DeleteMapping;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.PathVariable;@FeignClient(name = "BILL-MANAGER", path = "bill", configuration = FeignConfig.class)public interface BillClient {    @GetMapping("list")    List<Bill> list(@SpringQueryMap(true) Bill b);    @GetMapping("type")    List<BillType> type();    @DeleteMapping("delete/{id}")    public String delete(@PathVariable("id") Long id);}

读到这里,这篇“Spring Cloud Feign使用对象参数的方法”文章已经介绍完毕,想要掌握这篇文章的知识点还需要大家自己动手实践使用过才能领会,如果想了解更多相关内容的文章,欢迎关注编程网精选频道。

--结束END--

本文标题: Spring Cloud Feign使用对象参数的方法

本文链接: https://www.lsjlt.com/news/323160.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Spring Cloud Feign使用对象参数的方法
    本文小编为大家详细介绍“Spring Cloud Feign使用对象参数的方法”,内容详细,步骤清晰,细节处理妥当,希望这篇“Spring Cloud Feign使用对象参数的方法”文章能帮助大家解决...
    99+
    2023-06-29
  • Spring Cloud Feign 使用对象参数的操作
    目录概述@RequestBody@SpringQueryMapQueryMapEncoder解决方案概述 Spring Cloud Feign 用于微服务的封装,通过接口代理的实现方...
    99+
    2022-11-13
  • Spring Cloud中使用Feign,@RequestBody无法继承的解决方案
    目录使用Feign,@RequestBody无法继承的问题原因分析解决方案使用feign遇到的问题1、示例2、首次访问超时问题3、FeignClient接口中使用Feign,@Req...
    99+
    2022-11-12
  • Spring Cloud中声明式服务调用Feign的方法
    这篇文章主要介绍“Spring Cloud中声明式服务调用Feign的方法”,在日常操作中,相信很多人在Spring Cloud中声明式服务调用Feign的方法问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”S...
    99+
    2023-06-19
  • feign post参数对象不加@RequestBody的使用说明
    目录feign post参数对象不加@RequestBody解决办法这里对比一下feign和原接口的参数使用@RequestParam、@RequestBody 的正确姿势背景详细情...
    99+
    2022-11-12
  • Spring Cloud-Feign服务调用的问题及处理方法
    概述: • Feign 是一个声明式的 REST 客户端,它用了基于接口的注解方式,很方便实现客户端配置。 • Feign 最初由 Netflix 公司提供...
    99+
    2022-11-12
  • 基于Feign传输对象无法接收参数的问题
    目录Feign传输对象无法接收参数Feign参数传递问题记录API层接口层Feign传输对象无法接收参数 今天碰到问题,当我们使用对象作为参数传输时,无法获得其参数值。  @Requ...
    99+
    2022-11-13
  • 使用spring MVC怎么传递对象参数
    本篇文章为大家展示了使用spring MVC怎么传递对象参数,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。采用@ModelAttribute注解的方式,接收方式如下:@RequestMapping(...
    99+
    2023-05-31
    springmvc
  • Feign远程调用传递对象参数并返回自定义分页数据的方法
    这篇文章主要介绍“Feign远程调用传递对象参数并返回自定义分页数据的方法”,在日常操作中,相信很多人在Feign远程调用传递对象参数并返回自定义分页数据的方法问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”F...
    99+
    2023-06-29
  • 解决SpringCloud Feign传对象参数调用失败的问题
    SpringCloud Feign传对象参数调用失败 不支持GET请求方式 使用Apache HttpClient替换Feign原生httpclient @...
    99+
    2022-11-12
  • Spring Cloud微服务使用webSocket的方法
    webSocket webSocket长连接是一种在单个tcp连接上进行全双工通信的协议,允许双向数据推送。一般微服务提供的restful API只是对前端请求做出相应。使用web...
    99+
    2022-11-12
  • Postman传递对象参数的方法是什么
    这篇文章主要介绍“Postman传递对象参数的方法是什么”,在日常操作中,相信很多人在Postman传递对象参数的方法是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Postman传递对象参数的方法是什么...
    99+
    2023-06-26
  • 使用spring通过aop获取方法参数和参数值
    目录spring通过aop获取方法参数和参数值自定义注解切面aop切面 注解、参数获取1、定义需要切面的注解2、在需要进行切面的方法标注注解3、定义切面spring通过aop获取方法...
    99+
    2022-11-12
  • MyBatis传入参数为List对象的实现方法
    这篇文章主要介绍MyBatis传入参数为List对象的实现方法,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!SSM框架是JavaWeb必学的框架,虽说基本的增删改查很简单,但是当面临一些特殊情况时,有时还是会显得手足...
    99+
    2023-06-07
  • Spring Cloud Alibaba整合Nacos使用的方法是什么
    今天小编给大家分享一下Spring Cloud Alibaba整合Nacos使用的方法是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有...
    99+
    2023-07-05
  • Vue子组件内的props对象参数配置方法
    目录一、简单数据类型1、布尔类型 Boolean正确写法 :2、数字类型 Number正确写法 :3、字符串类型 String正确写法 :二、复杂数据类型1、数组 Array错误写法...
    99+
    2022-11-13
  • Spring AOP 对象内部方法间的嵌套调用方式
    目录Spring AOP 对象内部方法间的嵌套调用我们先定义一个接口以及此接口的一个实现类增加AOP处理同一对象内的嵌套方法调用AOP失效原因分析举一个同一对象内的嵌套方法调用拦截失...
    99+
    2022-11-12
  • Feign远程调用传递对象参数并返回自定义分页数据的过程解析
    目录Feign介绍Feign测试1.在yml文件里面增加了配置信息2.在客户端pom.xml文件中引入的依赖(消费者端)3.服务调用端接口为4.服务调用端Service代码5.服务调...
    99+
    2022-11-13
  • python Workbook对象的使用方法
    这篇文章主要讲解了“python Workbook对象的使用方法”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“python Workbook对象的使用方法”吧!说明要创建新的Excel文档,...
    99+
    2023-06-20
  • 使用@RequestBody传对象参数时碰到的坑
    目录@RequestBody传对象参数时碰到的坑我的真实代码是这样的:也就是下面的区别:@RequestBody 的正确使用@RequestBody接收的是一个Json对象@Requ...
    99+
    2022-11-12
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作