最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring?Cloud?Feign?使用對象參數(shù)的操作

 更新時間:2022年02月22日 14:10:24   作者:呆煒  
這篇文章主要介紹了Spring?Cloud?Feign?如何使用對象參數(shù)的問題,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下

概述

Spring Cloud Feign 用于微服務(wù)的封裝,通過接口代理的實現(xiàn)方式讓微服務(wù)調(diào)用變得簡單,讓微服務(wù)的使用上如同本地服務(wù)。但是它在傳參方面不是很完美。在使用 Feign 代理 GET 請求時,對于簡單參數(shù)(基本類型、包裝器、字符串)的使用上沒有困難,但是在使用對象傳參時卻無法自動的將對象包含的字段解析出來。

如果你沒耐心看完,直接跳到最后一個標(biāo)題跟著操作就行了。

@RequestBody

對象傳參是很常見的操作,雖然可以通過一個個參數(shù)傳遞來替代,但是那樣就太麻煩了,所以必須解決這個問題。

我在網(wǎng)上看到有人用 @RequestBody 來注解對象參數(shù),我在嘗試后發(fā)現(xiàn)確實可用。這個方案實際使用 body 體裝了參數(shù)(使用的是 GET 請求),但是這個方案有些問題:

  1. 注解需要在 consumer 和 provider 兩邊都有,這造成了麻煩
  2. 使用接口測試工具 Postman 無法跑通微服務(wù),后來發(fā)現(xiàn)是因為 body 體的格式選擇不正確,這個格式不是通常的表單或者路徑拼接,而是 GraphQL。我沒有研究過這種格式應(yīng)該如何填寫參數(shù),但是 Postman 上并沒有給出像表單那樣方便的格式,這對于測試是很不利的。

@SpringQueryMap

于是我繼續(xù)尋找答案,發(fā)現(xiàn)可以使用 @SpringQueryMap 僅添加在 consumer 的參數(shù)上就能自動對 Map 類型參數(shù)編碼再拼接到 URL 上。而我用的高版本的 Feign,可以直接把對象編碼。

可是正當(dāng)我以為得到正解時,卻發(fā)現(xiàn)還是有問題:

我明明在 Date 類型的字段上加上了 @DateTimeFormat(pattern = "yyyy-MM-dd"),卻沒有生效,他用自己的方式進行了編碼(或者說序列化),而且官方確實沒有提供這種格式化方式。

又一番找尋后發(fā)現(xiàn)了一位大佬自己實現(xiàn)了一個注解轉(zhuǎn)換替代 @SpringQueryMap,并實現(xiàn)了豐富的格式化功能 ORZ(原文鏈接:Spring Cloud Feign實現(xiàn)自定義復(fù)雜對象傳參),只能說佩服佩服。但是我沒有那樣的技術(shù),又不太想復(fù)制粘貼他那一大堆的代碼,因為出了問題也不好改,所以我還是想堅持最大限度地使用框架,最小限度的給框架填坑。

QueryMapEncoder

終于功夫不費有心人,我發(fā)現(xiàn)了 Feign 預(yù)留的自定義編碼器接口 QueryMapEncoder,框架提供了兩個實現(xiàn):

  • FieldQueryMapEncoder
  • BeanQueryMapEncoder

雖然這兩個實現(xiàn)不能滿足我的要求,但是只要稍加修改寫一個自己的實現(xiàn)類就行了,于是我在 FieldQueryMapEncoder 的基礎(chǔ)上修改,僅僅添加了一個方法,小改了一個方法就實現(xiàn)了功能。

原理:Feign 其實還是用 Map<String, Object> 進行的編碼,編碼方式也很簡單,String 是 key,Object 是 value。最開始的方式就是用 Object 的 toString() 方法把參數(shù)編碼,這也是為什么 Date 字段會變成一個默認的時間格式,因為 toString() 根本和 @DateTimeFormat 沒有關(guān)系。而高版本使用編碼器實現(xiàn)了對象傳參,實際實際上是通過簡單的反射獲取對象的元數(shù)據(jù),再放到 Map 中。

上面的原理都能從 @DateTimeFormat 的注釋和編碼器的源碼中得到答案。

我們要做的就是自定義一個編碼器,實現(xiàn)在元數(shù)據(jù)放入 Map 之前根據(jù)需要把字段變成我們想要的字符串。下面是我實現(xiàn)的代碼,供參考:

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();
    // 可擴展為策略模式,支持更多的格式轉(zhuǎn)換
    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: 最好不要寫死時區(qū)
            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 方法的最后一行稍微修改了一下,引用了我加的方法,其他都是直接借鑒過來的(本來我想更偷懶,直接繼承一下子,但是它用了私有的內(nèi)部類導(dǎo)致我只能全部復(fù)制粘貼了)。

解決方案

1.不用引入其他的 Feign 依賴,保證有下面這個就行(看網(wǎng)上其他方法還要引入特定依賴,要對應(yīng)版本號,挺麻煩的)

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

2.編寫上面那樣的類,你可以直接復(fù)制過去改個包名就行,如果還需要除了 Date 以外的格式化,請看注釋和文章分析。其中我對日期的格式化,直接使用了 @DateTimeFormat 提供的模式,和 Spring 保持了一致。

3.編寫一個 Feign 配置類,將剛自定義的編碼器注冊進去。細節(jié)我就不多說了:

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;
@Configuration
public class FeignConfig {
    @Bean
    public Feign.Builder feignBuilder() {
        return Feign.builder()
                .queryMapEncoder(new PowerfulQueryMapEncoder())
                .retryer(Retryer.NEVER_RETRY);
    }
}

4.Feign 代理接口中聲明使用這個配置類,細節(jié)不談

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);
}

到此這篇關(guān)于Spring Cloud Feign 如何使用對象參數(shù)的文章就介紹到這了,更多相關(guān)Spring Cloud Feign對象參數(shù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java String 和 new String()的比較與區(qū)別

    Java String 和 new String()的比較與區(qū)別

    這篇文章主要介紹了Java String 和 new String()的區(qū)別的相關(guān)資料,需要的朋友可以參考下
    2017-04-04
  • Java深入學(xué)習(xí)圖形用戶界面GUI之事件處理

    Java深入學(xué)習(xí)圖形用戶界面GUI之事件處理

    這篇文章主要介紹了基于Java GUI 事件處理方式,一個圖形界面制作完成了,在程序開發(fā)中只是完成了起步的工作。要想讓一個組件都發(fā)揮自己的作用.就必須對所有的組件進行事件處理
    2022-05-05
  • 線程池調(diào)用kafka發(fā)送消息產(chǎn)生的內(nèi)存泄漏問題排查解決

    線程池調(diào)用kafka發(fā)送消息產(chǎn)生的內(nèi)存泄漏問題排查解決

    這篇文章主要為大家介紹了線程池調(diào)用kafka發(fā)送消息產(chǎn)生的內(nèi)存泄漏問題排查解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-08-08
  • JavaWeb簡單用戶登錄注冊實例代碼(有驗證碼)

    JavaWeb簡單用戶登錄注冊實例代碼(有驗證碼)

    這篇文章主要介紹了JavaWeb簡單用戶登錄注冊實例代碼,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-02-02
  • Java操作mongodb增刪改查的基本操作實戰(zhàn)指南

    Java操作mongodb增刪改查的基本操作實戰(zhàn)指南

    MongoDB是一個基于分布式文件存儲的數(shù)據(jù)庫,由c++語言編寫,旨在為WEB應(yīng)用提供可擴展的高性能數(shù)據(jù)存儲解決方案,下面這篇文章主要給大家介紹了關(guān)于Java操作mongodb增刪改查的基本操作實戰(zhàn)指南,需要的朋友可以參考下
    2023-05-05
  • SpringBoot 快速實現(xiàn) api 加密的方法

    SpringBoot 快速實現(xiàn) api 加密的方法

    在項目中,為了保證數(shù)據(jù)的安全,我們常常會對傳遞的數(shù)據(jù)進行加密,常用的加密算法包括對稱加密(AES)和非對稱加密(RSA),本文給大家介紹SpringBoot 快速實現(xiàn) api 加密,感興趣的朋友一起看看吧
    2023-10-10
  • Java使用JSqlParser解析SQL語句應(yīng)用場景

    Java使用JSqlParser解析SQL語句應(yīng)用場景

    JSqlParser是一個功能全面的Java庫,用于解析SQL語句,支持多種SQL方言,它可以輕松集成到Java項目中,并提供靈活的操作方式,本文介紹Java使用JSqlParser解析SQL語句總結(jié),感興趣的朋友一起看看吧
    2024-09-09
  • Java編寫擲骰子游戲

    Java編寫擲骰子游戲

    這篇文章主要介紹了Java編寫擲骰子游戲,需要的朋友可以參考下
    2015-11-11
  • IDEA離線安裝maven helper插件的圖文教程

    IDEA離線安裝maven helper插件的圖文教程

    本文通過圖文并茂的形式給大家介紹IDEA離線安裝maven helper插件,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2021-08-08
  • MyBatis Log Free插件IDE下載與使用方式

    MyBatis Log Free插件IDE下載與使用方式

    這篇文章主要介紹了MyBatis Log Free插件IDE下載與使用方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-07-07

最新評論

万源市| 林甸县| 湖州市| 富阳市| 汤原县| 乡宁县| 察哈| 阿克陶县| 灯塔市| 宁夏| 梧州市| 凭祥市| 广丰县| 耒阳市| 平南县| 开鲁县| 同仁县| 南召县| 双桥区| 嫩江县| 卢氏县| 鄂托克前旗| 洛扎县| 繁峙县| 彭州市| 乐清市| 三门县| 琼海市| 会东县| 酒泉市| 荆门市| 化德县| 定襄县| 永川市| 开封县| 兰溪市| 绍兴县| 左云县| 扎赉特旗| 鹤岗市| 额尔古纳市|