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

SpringBoot在RequestBody中使用枚舉參數(shù)案例詳解

 更新時(shí)間:2021年09月03日 11:31:00   作者:沉潛飛動(dòng)  
這篇文章主要介紹了SpringBoot在RequestBody中使用枚舉參數(shù)案例詳解,本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下

前文說到 優(yōu)雅的使用枚舉參數(shù)實(shí)現(xiàn)原理,本文繼續(xù)說一下如何在 RequestBody 中優(yōu)雅使用枚舉。

本文先上實(shí)戰(zhàn),說一下如何實(shí)現(xiàn)。在 優(yōu)雅的使用枚舉參數(shù) 代碼的基礎(chǔ)上,我們繼續(xù)實(shí)現(xiàn)。

確認(rèn)需求

需求與前文類似,只不過這里需要是在 RequestBody 中使用。與前文不同的是,這種請(qǐng)求是通過 Http Body 的方式傳輸?shù)胶蠖?,通常?json 或 xml 格式,Spring 默認(rèn)借助 Jackson 反序列化為對(duì)象。

同樣的,我們需要在枚舉中定義 int 類型的 id、String 類型的 code,id 取值不限于序號(hào)(即從 0 開始的 orinal 數(shù)據(jù)),code 不限于 name。客戶端請(qǐng)求過程中,可以傳 id,可以傳 code,也可以傳 name。服務(wù)端只需要在對(duì)象中定義一個(gè)枚舉參數(shù),不需要額外的轉(zhuǎn)換,即可得到枚舉值。

好了,接下來我們定義一下枚舉對(duì)象。

定義枚舉和對(duì)象

先定義我們的枚舉類GenderIdCodeEnum,包含 id 和 code 兩個(gè)屬性:

public enum GenderIdCodeEnum implements IdCodeBaseEnum {
    MALE(1, "male"),
    FEMALE(2, "female");

    private final Integer id;
    private final String code;

    GenderIdCodeEnum(Integer id, String code) {
        this.id = id;
        this.code = code;
    }

    @Override
    public String getCode() {
        return code;
    }

    @Override
    public Integer getId() {
        return id;
    }
}

這個(gè)枚舉類的要求與前文一致,不清楚的可以再去看一下。

在定義一個(gè)包裝類GenderIdCodeRequestBody,用于接收 json 數(shù)據(jù)的請(qǐng)求體:

@Data
public class GenderIdCodeRequestBody {
    private String name;
    private GenderIdCodeEnum gender;
    private long timestamp;
}

除了GenderIdCodeEnum參數(shù)外,其他都是示例,所以隨便定義一下。

實(shí)現(xiàn)轉(zhuǎn)換邏輯

前奏鋪墊好,接下來入正題了。Jackson 提供了兩種方案:

  • 方案一:精準(zhǔn)攻擊,指定需要轉(zhuǎn)換的字段,不影響其他類對(duì)象中的字段
  • 方案二:全范圍攻擊,所有借助 Jackson 反序列化的枚舉字段,全部具備自動(dòng)轉(zhuǎn)換功能

方案一:精準(zhǔn)攻擊

這種方案中,我們首先需要實(shí)現(xiàn)JsonDeserialize抽象類:

public class IdCodeToEnumDeserializer extends JsonDeserializer<BaseEnum> {
    @Override
    public BaseEnum deserialize(JsonParser jsonParser, DeserializationContext deserializationContext)
            throws IOException {
        final String param = jsonParser.getText();// 1
        final JsonStreamContext parsingContext = jsonParser.getParsingContext();// 2
        final String currentName = parsingContext.getCurrentName();// 3
        final Object currentValue = parsingContext.getCurrentValue();// 4
        try {
            final Field declaredField = currentValue.getClass().getDeclaredField(currentName);// 5
            final Class<?> targetType = declaredField.getType();// 6
            final Method createMethod = targetType.getDeclaredMethod("create", Object.class);// 7
            return (BaseEnum) createMethod.invoke(null, param);// 8
        } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException | NoSuchFieldException e) {
            throw new CodeBaseException(ErrorResponseEnum.PARAMS_ENUM_NOT_MATCH, new Object[] {param}, "", e);
        }
    }
}

然后在指定枚舉字段上定義@JsonDeserialize注解,比如:

@JsonDeserialize(using = IdCodeToEnumDeserializer.class)
private GenderIdCodeEnum gender;

具體說一下每行的作用:

  1. 獲取參數(shù)值。根據(jù)需要,此處可能是 id、code 或 name,也就是源值,需要將其轉(zhuǎn)換為枚舉;
  2. 獲取轉(zhuǎn)換上線文,這個(gè)是為 3、4 步做準(zhǔn)備的;
  3. 獲取標(biāo)記@JsonDeserialize注解的字段,此時(shí)currentName的值是gender;
  4. 獲取包裝對(duì)象,也就是GenderIdCodeRequestBody對(duì)象;
  5. 根據(jù)包裝對(duì)象的Class對(duì)象,以及字段名gender獲取Field對(duì)象,為第 5 步做準(zhǔn)備;
  6. 獲取gender字段對(duì)應(yīng)的枚舉類型,也即是GenderIdCodeEnum。之所以這樣做,是要實(shí)現(xiàn)一個(gè)通用的反序列化類;
  7. 這里是寫死的一種實(shí)現(xiàn),就是在枚舉類中,需要定義一個(gè)靜態(tài)方法,方法名是create,請(qǐng)求參數(shù)是Object
  8. 通過反射調(diào)用create方法,將第一步獲取的請(qǐng)求參數(shù)傳入。

我們來看一下枚舉類中定義的create方法:

public static GenderIdCodeEnum create(Object code) {
    final String stringCode = code.toString();
    final Integer intCode = BaseEnum.adapter(stringCode);
    for (GenderIdCodeEnum item : values()) {
        if (Objects.equals(stringCode, item.name())) {
            return item;
        }
        if (Objects.equals(item.getCode(), stringCode)) {
            return item;
        }
        if (Objects.equals(item.getId(), intCode)) {
            return item;
        }
    }
    return null;
}

為了性能考慮,我們可以提前定義三組 map,分別以 id、code、name 為 key,以枚舉值為 value,這樣就可以通過 O(1) 的時(shí)間復(fù)雜度返回了??梢詤⒖记拔牡?code>Converter類的實(shí)現(xiàn)邏輯。

這樣,我們就可以實(shí)現(xiàn)精準(zhǔn)轉(zhuǎn)換了。

方案二:全范圍攻擊

這種方案是全范圍攻擊了,只要是 Jackson 參與的反序列化,只要其中有目標(biāo)枚舉參數(shù),就會(huì)受到這種進(jìn)入這種方案的邏輯中。這種方案是在枚舉類中定義一個(gè)靜態(tài)轉(zhuǎn)換方法,通過@JsonCreator注解注釋,Jackson 就會(huì)自動(dòng)轉(zhuǎn)換了。

這個(gè)方法的定義與方案一中的create方法完全一致,所以只需要在create方法上加上注解即可:

@JsonCreator(mode = Mode.DELEGATING)
public static GenderIdCodeEnum create(Object code) {
    final String stringCode = code.toString();
    final Integer intCode = BaseEnum.adapter(stringCode);
    for (GenderIdCodeEnum item : values()) {
        if (Objects.equals(stringCode, item.name())) {
            return item;
        }
        if (Objects.equals(item.getCode(), stringCode)) {
            return item;
        }
        if (Objects.equals(item.getId(), intCode)) {
            return item;
        }
    }
    return null;
}

其中Mode類有四個(gè)值:DEFAULT、DELEGATING、PROPERTIES、DISABLED,這四種的差別會(huì)在原理篇中說明。還是那句話,對(duì)于應(yīng)用類技術(shù),我們可以先知其然,再知其所以然,也一定要知其所以然。

測(cè)試

先定義一個(gè) controller 方法:

@PostMapping("gender-id-code-request-body")
public GenderIdCodeRequestBody bodyGenderIdCode(@RequestBody GenderIdCodeRequestBody genderRequest) {
    genderRequest.setTimestamp(System.currentTimeMillis());
    return genderRequest;
}

然后定義測(cè)試用例,還是借助 JUnit5:

@ParameterizedTest
@ValueSource(strings = {"\"MALE\"", "\"male\"", "\"1\"", "1"})
void postGenderIdCode(String gender) throws Exception {
    final String result = mockMvc.perform(
            MockMvcRequestBuilders.post("/echo/gender-id-code-request-body")
                    .contentType(MediaType.APPLICATION_JSON_UTF8)
                    .accept(MediaType.APPLICATION_JSON_UTF8)
                    .content("{\"gender\": " + gender + ", \"name\": \"看山\"}")
    )
            .andExpect(MockMvcResultMatchers.status().isOk())
            .andDo(MockMvcResultHandlers.print())
            .andReturn()
            .getResponse()
            .getContentAsString();

    ObjectMapper objectMapper = new ObjectMapper();
    final GenderIdCodeRequestBody genderRequest = objectMapper.readValue(result, GenderIdCodeRequestBody.class);
    Assertions.assertEquals(GenderIdCodeEnum.MALE, genderRequest.getGender());
    Assertions.assertEquals("看山", genderRequest.getName());
    Assertions.assertTrue(genderRequest.getTimestamp() > 0);
}

文末總結(jié)

本文主要說明了如何在 RequestBody 中優(yōu)雅的使用枚舉參數(shù),借助了 Jackson 的反序列化擴(kuò)展,可以定制類型轉(zhuǎn)換邏輯。礙于文章篇幅,沒有羅列大段代碼。關(guān)注公號(hào)「看山的小屋」回復(fù) spring 可以獲取源碼。關(guān)注我,下一篇我們進(jìn)入原理篇。

推薦閱讀

到此這篇關(guān)于SpringBoot在RequestBody中使用枚舉參數(shù)案例詳解的文章就介紹到這了,更多相關(guān)SpringBoot在RequestBody中使用枚舉參數(shù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • spring boot開發(fā)遇到坑之spring-boot-starter-web配置文件使用教程

    spring boot開發(fā)遇到坑之spring-boot-starter-web配置文件使用教程

    Spring Boot支持容器的自動(dòng)配置,默認(rèn)是Tomcat,當(dāng)然我們也是可以進(jìn)行修改的。這篇文章給大家介紹了spring boot開發(fā)遇到坑之spring-boot-starter-web配置文件使用教程,需要的朋友參考下吧
    2018-01-01
  • JetBrains推出全新IDE之Fleet詳解

    JetBrains推出全新IDE之Fleet詳解

    當(dāng)您第一次啟動(dòng) Fleet 時(shí),它會(huì)作為一個(gè)功能齊全的編輯器啟動(dòng),具有語法高亮顯示、簡單的代碼補(bǔ)全以及您對(duì)一個(gè)編輯器期待的所有功能,本文學(xué)習(xí)下JetBrains推出全新IDE之Fleet相關(guān)知識(shí),感興趣的朋友跟隨小編一起看看吧
    2021-12-12
  • springboot @ConfigurationProperties和@PropertySource的區(qū)別

    springboot @ConfigurationProperties和@PropertySource的區(qū)別

    這篇文章主要介紹了springboot @ConfigurationProperties和@PropertySource的區(qū)別,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • 詳解JAVA 強(qiáng)引用

    詳解JAVA 強(qiáng)引用

    這篇文章主要介紹了JAVA 強(qiáng)引用的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-08-08
  • 如何解決SpringBoot2.6及之后版本取消了循環(huán)依賴的支持問題

    如何解決SpringBoot2.6及之后版本取消了循環(huán)依賴的支持問題

    循環(huán)依賴指的是兩個(gè)或者多個(gè)bean之間相互依賴,形成一個(gè)閉環(huán),SpringBoot從2.6.0開始默認(rèn)不允許出現(xiàn)Bean循環(huán)引用,解決方案包括在全局配置文件設(shè)置允許循環(huán)引用存在、在SpringApplicationBuilder添加設(shè)置允許循環(huán)引用、構(gòu)造器注入
    2024-10-10
  • jdbc和mybatis的流式查詢使用方法

    jdbc和mybatis的流式查詢使用方法

    有些時(shí)候我們所需要查詢的數(shù)據(jù)量比較大,但是jvm內(nèi)存又是有限制的,數(shù)據(jù)量過大會(huì)導(dǎo)致內(nèi)存溢出。這個(gè)時(shí)候就可以使用流式查詢,本文就主要介紹了jdbc和mybatis的流式查詢,感興趣的可以了解一下
    2021-11-11
  • 詳細(xì)介紹idea如何設(shè)置類頭注釋和方法注釋(圖文)

    詳細(xì)介紹idea如何設(shè)置類頭注釋和方法注釋(圖文)

    本篇文章主要介紹了idea如何設(shè)置類頭注釋和方法注釋(圖文),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-12-12
  • MyBatis異常-Property ''configLocation'' not specified, using default MyBatis Configuration

    MyBatis異常-Property ''configLocation'' not specified, using d

    今天小編就為大家分享一篇關(guān)于MyBatis異常-Property 'configLocation' not specified, using default MyBatis Configuration,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2019-03-03
  • 下一代Eclipse 步入云端

    下一代Eclipse 步入云端

    代號(hào)Che的下一代Eclipse IDE將運(yùn)行在云端,可以在任何機(jī)器上打開瀏覽器寫代碼。項(xiàng)目的建立、編輯、debug、部署可以都在一個(gè)倉庫中進(jìn)行,需要的朋友可以參考下
    2015-12-12
  • 在Mybatis中使用自定義緩存ehcache的方法

    在Mybatis中使用自定義緩存ehcache的方法

    這篇文章主要介紹了在Mybatis中使用自定義緩存ehcache的方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-01-01

最新評(píng)論

罗江县| 北宁市| 屏东县| 古浪县| 马关县| 乐亭县| 莆田市| 绥阳县| 和政县| 唐山市| 固始县| 石台县| 蕉岭县| 忻城县| 平武县| 达拉特旗| 长兴县| 从化市| 正安县| 巢湖市| 莒南县| 定兴县| 民乐县| 洞头县| 平定县| 什邡市| 屯留县| 砀山县| 石首市| 吴旗县| 缙云县| 呼伦贝尔市| 文昌市| 电白县| 罗源县| 津南区| 长兴县| 栖霞市| 大邑县| 偃师市| 翼城县|