Feign get请求通过对象传递url参数,且支持对象中的属性排序

2023-10-27

1.get请求参数比较多时候写param是很累的一种方式:

@GetMapping(value = "/fapi/v1/positionSide/dual")
PositionSideResponse getPositionSide(@RequestHeader(value = "X-MBX-APIKEY") String apikey, @SpringQueryMap BaseRequest request);

使用 @SpringQueryMap 可以自动将对象转换为get参数拼接在url上

2.当实体对象中的熟悉需要排序时怎么办呢? 比如sign的参数必须放参数末尾这种情况?

这个时候需要我们自定义实现 BeanQueryMapEncoder 代码如下

import feign.Param;
import feign.QueryMapEncoder;
import feign.codec.EncodeException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.annotation.Order;

import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
public class CustomerBeanQueryMapEncoder implements QueryMapEncoder {

    private final Map<Class<?>, CustomerBeanQueryMapEncoder.ObjectParamMetadata> classToMetadata =
            new HashMap<>();

    @Override
    public Map<String, Object> encode(Object object) throws EncodeException {
        try {
            CustomerBeanQueryMapEncoder.ObjectParamMetadata metadata = getMetadata(object.getClass());
            Map<String, Object> propertyNameToValue = new LinkedHashMap<>();
            for (PropertyDescriptor pd : metadata.objectProperties) {
                Method method = pd.getReadMethod();
                Object value = method.invoke(object);
                if (value != null && value != object) {
                    Param alias = method.getAnnotation(Param.class);
                    String name = alias != null ? alias.value() : pd.getName();
                    propertyNameToValue.put(name, value);
                }
            }
            return propertyNameToValue;
        } catch (IllegalAccessException | IntrospectionException | InvocationTargetException e) {
            throw new EncodeException("Failure encoding object into query map", e);
        }
    }

    private CustomerBeanQueryMapEncoder.ObjectParamMetadata getMetadata(Class<?> objectType) throws IntrospectionException {
        CustomerBeanQueryMapEncoder.ObjectParamMetadata metadata = classToMetadata.get(objectType);
        if (metadata == null) {
            metadata = CustomerBeanQueryMapEncoder.ObjectParamMetadata.parseObjectType(objectType);
            classToMetadata.put(objectType, metadata);
        }
        return metadata;
    }

    private static class ObjectParamMetadata {

        private final List<PropertyDescriptor> objectProperties;

        private ObjectParamMetadata(List<PropertyDescriptor> objectProperties) {
            this.objectProperties = Collections.unmodifiableList(objectProperties);
        }

        private static CustomerBeanQueryMapEncoder.ObjectParamMetadata parseObjectType(Class<?> type)
                throws IntrospectionException {
            List<PropertyDescriptor> properties = new ArrayList<PropertyDescriptor>();

            for (PropertyDescriptor pd : Introspector.getBeanInfo(type).getPropertyDescriptors()) {
                boolean isGetterMethod = pd.getReadMethod() != null && !"class".equals(pd.getName());
                if (isGetterMethod) {
                    properties.add(pd);
                }
            }

            /**
             * 实现排序
             */
            properties = properties.stream().sorted(Comparator.comparing(x -> {
                int orderValue = -1;
                try {
                    Field field = type.getDeclaredField(x.getName());
                    Order orderAnno = field.getAnnotation(Order.class);
                    if (orderAnno != null) {
                        orderValue = orderAnno.value();
                    }
                } catch (NoSuchFieldException e) {
                    log.error("NoSuchFieldException", e);
                }
                return orderValue;
            })).collect(Collectors.toList());

            return new CustomerBeanQueryMapEncoder.ObjectParamMetadata(properties);
        }
    }
}

然后对feign的queryMapEncoder赋值成我们的

import feign.Feign;
import feign.Retryer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FeignConfiguration {

    /**
     * @Description 替换解析queryMap的类为自定义map类
     */
    @Bean
    public Feign.Builder feignBuilder() {
        return Feign.builder()
                .queryMapEncoder(new CustomerBeanQueryMapEncoder())
                .retryer(Retryer.NEVER_RETRY);
    }

}

此时在实体对象的属性上标注Order即可实现Encode后字符串的排序

    private Long recvWindow;

    /**
     * 下单时间戳
     */
    private Long timestamp = System.currentTimeMillis();

    /**
     * 签名值
     */
    @Order(value = Integer.MAX_VALUE)
    private String signature;

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Feign get请求通过对象传递url参数,且支持对象中的属性排序 的相关文章

  • 如何将画廊意图中的“打开”更改为“完成”?

    我使用以下意图打开画廊来选择多个图像和视频 Intent intent new Intent intent setType image video intent putExtra Intent EXTRA ALLOW MULTIPLE tr
  • @RestController 没有 @ResponseBody 方法工作不正确

    我有以下控制器 RestController RequestMapping value base url public class MyController RequestMapping value child url method Req
  • 通过SOCKS代理连接Kafka

    我有一个在 AWS 上运行的 Kafka 集群 我想用标准连接到集群卡夫卡控制台消费者从我的应用程序服务器 应用程序服务器可以通过 SOCKS 代理访问互联网 无需身份验证 如何告诉 Kafka 客户端通过代理进行连接 我尝试了很多事情 包
  • Spring RestTemplate 使用 cookie 遵循重定向

    最近我遇到了一个问题 我需要做一个GET请求远程服务 我假设使用一个简单的 servlet 并且 RestTemplate 返回Too many redirects 经过一番调查 似乎对指定远程服务发出的第一个请求实际上只是一个 302 重
  • 身份验证在 Spring Boot 1.5.2 和 Oauth2 中不起作用

    我正在使用带有 spring boot 1 5 2 RELEASE 的 Oauth2 当我尝试重写 ResourceServerConfigurerAdapter 类的配置方法时 它给了我一个编译错误 但这在 Spring boot 1 2
  • 通往楼梯顶部的可能路径

    这是一个非常经典的问题 我听说谷歌在他们的面试中使用过这个问题 问题 制定一个递归方法 打印从楼梯底部到楼梯顶部的所有可能的独特路径 有 n 个楼梯 您一次只能走 1 步或 2 步 示例输出 如果它是一个有 3 级楼梯的楼梯 1 1 1 2
  • 大数据使用什么数据结构

    我有一个包含一百万行的 Excel 工作表 每行有 100 列 每行代表一个具有 100 个属性的类的实例 列值是这些属性的值 哪种数据结构最适合在这里使用来存储数百万个数据实例 Thanks 这实际上取决于您需要如何访问这些数据以及您想要
  • Spring Security SAML2 使用 G Suite 作为 Idp

    我正在尝试使用 Spring Security 5 3 3 RELEASE 来处理 Spring Boot 应用程序中的 SAML2 身份验证 Spring Boot 应用程序将成为 SP G Suite 将成为 IDP 在我的 Maven
  • 需要使用 joda 进行灵活的日期时间转换

    我想使用 joda 解析电子邮件中的日期时间字符串 不幸的是我得到了各种不同的格式 例如 Wed 19 Jan 2011 12 52 31 0600 Wed 19 Jan 2011 10 15 34 0800 PST Wed 19 Jan
  • Jackson XML ArrayList 输出具有两个包装器元素

    我在 Jackson 生成的 XML 输出中得到了两个包装器元素 我只想拥有一个 我有一个 Java bean Entity Table name CITIES JacksonXmlRootElement localName City pu
  • Java Swing For mac 中的 DJ Native Swing 浏览器

    我有一个用 Swing 制作的 Java 应用程序 并且使用了一个 DJ Native Swing 浏览器 当我尝试在 OS X 上使用它时 它抛出了一个NoClassDefFoundError尽管我添加了 swt jar 但始终如此 有人
  • GWT 2.3 开发模式 - 托管模式 JSP 编译似乎不使用 java 1.5 兼容性

    无法编译 JSP 类 生成的 servlet 错误 DefaultMessage 上次更新 0 日期 中 0 时间 HH mm ss z 语法 错误 注释仅在源级别为 1 5 时可用 在尝试以开发模式在 Web 浏览器中打开我的 gwt 模
  • 使用 Mockito 模拟某些方法,但不模拟其他方法

    有没有办法使用 Mockito 模拟类中的某些方法 而不模拟其他方法 例如 在这个 诚然是人为的 Stock我想嘲笑的班级getPrice and getQuantity 返回值 如下面的测试片段所示 但我想要getValue 执行乘法 如
  • java库维护数据库结构

    我的应用程序一直在开发 所以偶尔 当版本升级时 需要创建 更改 删除一些表 修改一些数据等 通常需要执行一些sql代码 是否有一个 Java 库可用于使我的数据库结构保持最新 通过分析类似 db structure version 信息并执
  • 是否可以使用 Java Guava 将函数应用于集合?

    我想使用 Guava 将函数应用于集合 地图等 基本上 我需要调整 a 的行和列的大小Table分别使所有行和列的大小相同 执行如下操作 Table
  • Java Swing:需要一个高质量的带有复选框的开发 JTree

    我一直在寻找一个 Tree 实现 其中包含复选框 其中 当您选择一个节点时 树中的所有后继节点都会被自动选择 当您取消选择一个节点时 树中其所有后继节点都会自动取消选择 当已经选择了父节点 并且从其后继之一中删除了选择时 节点颜色将发生变化
  • Java中HashMap和ArrayList的区别?

    在爪哇 ArrayList and HashMap被用作集合 但我不明白我们应该在哪些情况下使用ArrayList以及使用时间HashMap 他们两者之间的主要区别是什么 您具体询问的是 ArrayList 和 HashMap 但我认为要完
  • org.apache.commons.net.io.CopyStreamException:复制时捕获 IOException

    我正在尝试使用以下方法中的代码将在我的服务器中创建的一些文件复制到 FTP 但奇怪的是我随机地低于错误 我无法弄清楚发生了什么 Exception org apache commons net io CopyStreamException
  • 泛型、数组和 ClassCastException

    我想这里一定发生了一些我不知道的微妙事情 考虑以下 public class Foo
  • 洪水填充优化:尝试使用队列

    我正在尝试创建一种填充方法 该方法采用用户指定的初始坐标 检查字符 然后根据需要更改它 这样做之后 它会检查相邻的方块并重复该过程 经过一番研究 我遇到了洪水填充算法并尝试了该算法 它可以工作 但无法满足我对 250 x 250 个字符的数

随机推荐

  • java去重复元素并打印_Java打印数组中重复元素

    Java打印数组中重复元素 1 说明 在此程序中 我们需要打印数组中存在的重复元素 这可以通过两个循环来完成 第一个循环将选择一个元素 第二个循环将通过将所选元素与其他元素进行比较来遍历整个数组 如果找到匹配项 则打印重复的元素 在上面的数
  • 仙道服务器维护,【正式服】2月14日例行更新维护公告

    为了给您提供更优质的游戏体验 诛仙手游 正式服 将于2月14日7 00 9 00进行例行维护 如遇特殊情况 开机时间将会顺延 本次更新后 等级 30级的玩家将通过邮件收到200绑定元宝更新补偿奖励 情人节特别活动 1 执子之手 与子同秀 活
  • 【面试】面试官:src和href的区别

    1 请求资源类型不同 1 href是Hypertext Reference的缩写 表示超文本引用 用来建立当前元素和文档之问的链接 常用的有 link a 2 在请求 src 资源时会将其指向的资源下载并应用到文档中 常用的有script
  • C++STL容器(上)string/vector/deque/stack/queue/list

    数据结构 研究节点和节点之间的关系 STL 算法 容器 迭代器 实现了数据结构和算法的有效分离 用来管理元素 算法和迭代器可以进行无缝连接 count v begin v end 3 统计元素3的个数 容器除了可以放基础数据类型 也可以放元
  • 字符数组、字符串数组转换成字符串【JAVA基础】

    一 字符数组to字符串 直接声明 char c a b c String s new String c 二 字符串数组to字符串 string是不可变类 利用StringBuffer String str abc dfe hij Strin
  • l130 华大低功耗mcu_HC32L110C6PA HC32L110C6UA 华大超低功耗 Cortex-M0+ 32位MCU

    HC32L110C6PA HC32L110C4UAHC32L110C6UA 华大超低功耗 Cortex M0 32位MCU HC32L110C6PA HC32L110C4UA 华大超低功耗 Cortex M0 32位MCU 超低功耗 MCU
  • BLE基础理论/Android BLE开发示例/蓝牙扫描列表数量扫描包/扫描响应包设置等

    参考 https blog csdn net qq 36075612 article details 127739150 spm 1001 2014 3001 5502 参考 https blog csdn net qq 36075612
  • 蓝桥杯:李白打酒加强版

    话说大诗人李白 一生好饮 幸好他从不开车 一天 他提着酒壶 从家里出来 酒壶中有酒 22 斗 他边走边唱 无事街上走 提壶去打酒 逢店加一倍 遇花喝一斗 这一路上 他一共遇到店 NN 次 遇到花 MM 次 已知最后一次遇到的是花 他正好把酒
  • Java变量的分类(根据作用域)

    按照作用域的不同 变量可分为 成员变量和局部变量 成员变量有两种 静态变量和实例变量 成员变量 在类中声明 作用域是整个类 局部变量 在一个方法的内部声明 作用域是整个方法 静态变量 被static关键字修饰 在内存中只有一个 被类的所有实
  • Jenkins配置定时任务

    1 点击任务后 点击配置 2 选择 构建触发器 下面的 定时构建 并设定定时规则 设置完成后 构建任务就会按照我们设置的时间定时执行了 3 设定规则 此处定时任务的格式遵循 cron 的语法 可以与 cron 的语法有轻微的差异 具体格式
  • App版本更新接口的设计

    工作这几年碰到的版本检测升级的接口也算是五花八门 啥样的都有 但肯定有的功能是有个apk的下载链接 能间接或直接提示你是强制还是非强制更新 间接是指提供你后台最新版本号 让你自己与本地版本号通过比较得出是否升级 直接就是后台接口直接返回个B
  • redhat6.9安装docker

    1 离线安装说明 内网环境需要在redhat6 9上安装docker以及docker compose 内网不能连接互联网 所以只能采用手工下载离线安装包的方式做 2 需要操作系统版本 docker支持的版本有 redhat7 redhat6
  • java类的加载顺序

    一 程序 package yy class Parent static int a 4 static System out println Parent class Chlid extends Parent static int a 5 s
  • tensorflow笔记(二十七)——重要tensor操作函数

    1 合并 多个tensor的合并主要包括2个函数 tf concat和tf stack 他们的输出参数都是list of tensor 区别是 tf concat是沿某一维度拼接shape相同的张量 拼接生成的新张量维度不会增加 tf st
  • OpenCV将多幅BMP压缩成AVI文件

    最近需要同时采集多个摄像头的视频 一般的屏幕录制软件使用不了 只能自己把一幅幅图片保存下来 再转成AVI视频 OpenCV正好提供了这类函数 所以自己做了一个简单的转换工具 主要利用的函数 CvVideoWriter cvCreateVid
  • python 笔记16--Flask-BasicAuth 使用与重构

    python 笔记16 Flask BasicAuth 使用与重构 1 介绍 2 方案 2 1 BasicAuth 使用与原理 2 2 BasicAuth 优化重构 3 注意事项 4 说明 1 介绍 Flask BasicAuth 是一种F
  • 【C/C++面试必备】面向对象与面向过程的区别

    这篇文章来说下面向对象编程 那什么是面向对象编程呢 介绍面向对象之前 那必须先说一下面向过程 什么是面向过程呢 面向过程 Procedure Oriented Programming 简称POP 是一种编程模型 由一系列要执行的计算步骤组成
  • https网络编程——openssl中后缀名文件说明以及常用的证书协议

    参考 openssl中后缀名文件说明 地址 https qingmu blog csdn net article details 108215177 spm 1001 2014 3001 5502 参考 Openssl常用的证书协议有哪些
  • 源码编译安装Nginx并设置开机自启动

    切换目录 cd usr local src 下载Nginx wget http nginx org download nginx 1 16 0 tar gz 解压源码 tar zxvf nginx 1 16 0 tar gz 配置源码 cd
  • Feign get请求通过对象传递url参数,且支持对象中的属性排序

    1 get请求参数比较多时候写param是很累的一种方式 GetMapping value fapi v1 positionSide dual PositionSideResponse getPositionSide RequestHead