欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

spring中前端明明傳了值后端卻接收不到問(wèn)題解決辦法

 更新時(shí)間:2024年05月15日 09:44:20   作者:AI?CODE  
在學(xué)習(xí)Spring的時(shí)候遇到了一個(gè)問(wèn)題,后臺(tái)一直接收不到前臺(tái)傳遞過(guò)來(lái)的參數(shù),耽誤了好長(zhǎng)時(shí)間終于找到了原因,這篇文章主要給大家介紹了關(guān)于spring中前端明明傳了值后端卻接收不到問(wèn)題的解決辦法,需要的朋友可以參考下

問(wèn)題場(chǎng)景

在進(jìn)行前后端的聯(lián)調(diào)時(shí),有時(shí)候會(huì)出現(xiàn),前端明明傳了值,后端接口卻接收不到的情況,這種情況常常讓人很苦惱,然后就會(huì)去仔細(xì)對(duì)比前后端的參數(shù)單詞是不是對(duì)應(yīng)上了,也會(huì)去檢查是不是前端的請(qǐng)求參數(shù)格式有問(wèn)題,又或者是后端接口接收的參數(shù)格式有問(wèn)題,一通檢查對(duì)比下來(lái),發(fā)現(xiàn)都沒(méi)問(wèn)題。那究竟是為什么呢?那就繼續(xù)往下看吧。

問(wèn)題重現(xiàn)

控制層代碼:

    @PostMapping(value = "/test")
    public void test(@RequestBody UserVO userVO) {

        System.out.println("用戶代碼:" + userVO.getUCode());
        System.out.println("用戶名稱:" + userVO.getUName());
    }

參數(shù)實(shí)體類:UserVO

@Data
public class UserVO {
    /**
     * 用戶代碼
     */
    private Long uCode;

    /**
     * 用戶名稱
     */
    private String uName;
}

用postman模擬前端調(diào)用:

控制臺(tái)預(yù)期打印結(jié)果:

用戶代碼:12345
用戶名稱:小明

控制臺(tái)實(shí)際打印結(jié)果:

解決方式

在實(shí)體類的屬性上方加@JsonProperty注解,如下圖:

然后測(cè)試控制臺(tái)打印結(jié)果:

原因分析

首先我們先把實(shí)體類復(fù)原,并且加上一個(gè)新的屬性loginType

@Data
public class UserVO {

    /**
     * 用戶代碼
     */
    private Long uCode;

    /**
     * 用戶名稱
     */
    private String uName;

    /**
     * 登錄類型
     */
    private String loginType;

}

眼尖的同學(xué)可能會(huì)發(fā)現(xiàn)了,我新加的屬性loginType長(zhǎng)得是不是跟原來(lái)兩個(gè)屬性u(píng)Code和uName不太一樣,不一樣的點(diǎn)在于uCode和uName都是首字母小寫(xiě),第二個(gè)字母大寫(xiě)的單詞,而loginType則不然。但是它們?nèi)挤像劮迕ǖ囊?guī)范,對(duì)吧。這時(shí)候可以猜測(cè),難道是這個(gè)原因?qū)е碌模?/p>

在這里我們先來(lái)簡(jiǎn)單驗(yàn)證下uCode、uName、loginType的情況

通過(guò)斷點(diǎn)發(fā)現(xiàn),uCode、uName是空的,loginType卻不是空的

然后我們將uCode、uName分別改為userCode、userName后再進(jìn)行測(cè)試

@Data
public class UserVO {
    /**
     * 用戶代碼
     */
    private Long userCode;
    /**
     * 用戶名稱
     */
    private String userName;
    /**
     * 登錄類型
     */
    private String loginType;
}

這個(gè)時(shí)候我們就可以得出結(jié)論,原因就是首字母小寫(xiě),第二個(gè)字母大寫(xiě)的單詞的屬性是有問(wèn)題的。

但是我們不禁要問(wèn),為啥呢?它這也符合駝峰命名法的規(guī)范啊。為什么它就有問(wèn)題呢?感興趣的同學(xué)可以接著往下看。

原理分析

首先我們要知道,在Spring中,前后端之間數(shù)據(jù)傳輸會(huì)涉及到數(shù)據(jù)的序列化和反序列化的操作,并且SpringBoot默認(rèn)是使用Jackson作為JSON數(shù)據(jù)格式處理的類庫(kù)。

序列化:按照指定的格式、順序等將實(shí)體類對(duì)象轉(zhuǎn)換為JSON對(duì)象;
反序列化:將JSON對(duì)象中的字符串、數(shù)字等,將其轉(zhuǎn)換為實(shí)體對(duì)象;

那么現(xiàn)在咱們就來(lái)斷點(diǎn)調(diào)試Jackson的源碼來(lái)看看原因。為方便展示,我將實(shí)體類留下uName、loginType兩個(gè)屬性

@Data
public class UserVO {
    /**
     * 用戶名稱
     */
    private String uName;
    /**
     * 登錄類型
     */
    private String loginType;
}

開(kāi)始調(diào)試:

Jackon主要是通過(guò)抽象類AbstractJackson2HttpMessageConverterreadJavaType方法將 HTTP 請(qǐng)求中的消息體轉(zhuǎn)換為對(duì)象,所以我們找到這部分代碼,對(duì)他進(jìn)行斷點(diǎn)調(diào)試:

然后逐步斷點(diǎn),在上圖的第192行和第195行,它會(huì)調(diào)用ObjectMapper.readValue,然后斷點(diǎn)推進(jìn)到調(diào)用方法的核心地方ObjectMapper_readMapAndClose方法

this._findRootDeserializer(ctxt, valueType);的大概意思就是根據(jù)類型找到反序列化器,注意在這邊是先從緩存中取,取到了的話就直接返回了。如果沒(méi)到下一步斷點(diǎn),在這邊你可以清除一下緩存。

然后斷點(diǎn)繼續(xù)推進(jìn)到創(chuàng)建反序列化器的地方DeserializerCache._createDeserializer

如果你清除緩存或者重啟項(xiàng)目在調(diào)用時(shí)會(huì)直接進(jìn)入到這個(gè)創(chuàng)建反序列化器的地方,你直接在這個(gè)方法上打斷點(diǎn)就好了

找到上圖中第164行的代碼,BeanDescription是類的描述的意思,所有的屬性都在這里被解析,然后我們斷點(diǎn)進(jìn)去看看。會(huì)進(jìn)入到POJOPropertiesCollector.collectAll方法,就是字面意思,收集所有。方法邏輯詳見(jiàn)下圖:

執(zhí)行完this._addFields(props);props加入了uNameloginType

執(zhí)行完this._addMethods(props);后發(fā)現(xiàn)props竟然多了一個(gè)uname

在這里我們點(diǎn)開(kāi)屬性詳細(xì)去看,會(huì)發(fā)現(xiàn)uName的get和set為空,但是loginType的是正常的,并且uname這個(gè)不知道哪里跑出來(lái)的屬性的get和set也是不為空的。

再接著執(zhí)行this._removeUnwantedProperties(props);移除不想要的屬性之后,會(huì)發(fā)現(xiàn)就剩下loginTypeuname了,因?yàn)?code>uName沒(méi)有g(shù)et和set。為什么

然后props中目前存儲(chǔ)的就是loginTypeuname

現(xiàn)在我們就要弄明白為什么有g(shù)et/set的是uname而不是uName

首先,在這個(gè)例子中我使用的是@Data注解,也就是使用的 Lombok,也就是說(shuō) getter 和 setter 是由 Lombok 生成的。使用注解的話會(huì)將get/set方法隱藏起來(lái),然后我們可以通過(guò)IDEA的Structure來(lái)看,見(jiàn)下圖:

那么Jackson 到底是如何解析的,使得解析出來(lái)的是uname,而不是uName。它解析的具體代碼在com.fasterxml.jackson.databind.util.BeanUtil類中的legacyManglePropertyName方法中

從上圖為我們可以很明顯的看到,通過(guò)這個(gè)方法之后getLoginType被解析成loginType了。那我們?cè)賮?lái)看看uName,見(jiàn)下圖:

從上圖斷點(diǎn)我們可以清晰的看見(jiàn)getUName被解析成uname了,按照我們正常的思維邏輯的話,loginType和uName都符合駝峰命名法的規(guī)范,那么uName對(duì)應(yīng)的get方法解析出來(lái)應(yīng)該是uName啊,為什么變成了uname呢?原因就在于這個(gè)

legacyManglePropertyName方法的處理邏輯,它的邏輯大概是:

1.根據(jù)入?yún)ffset去除get或者get,然后就剩下UName或者LoginType了
2.然后從第一個(gè)字母開(kāi)始解析,如果第一個(gè)字母是大寫(xiě)的,于是就將它轉(zhuǎn)成小寫(xiě),然后找下一個(gè),如果還是大寫(xiě),就繼續(xù)轉(zhuǎn)成小寫(xiě),直到找到一個(gè)小寫(xiě)字母后,就把之后的字母(不管大小寫(xiě))一起拼接進(jìn)來(lái)。

這樣就能解釋了:

去除get之后的LoginType找到第一個(gè)字母是大寫(xiě),轉(zhuǎn)為小寫(xiě)的l,下一個(gè)字母是小寫(xiě)的了,就直接把后面的全拼接進(jìn)來(lái),最終形成了loginType

去除get之后的UName找到第一個(gè)字母是大寫(xiě),轉(zhuǎn)為小寫(xiě)的u,下一個(gè)字母又是大寫(xiě),轉(zhuǎn)為小寫(xiě)的n,在下一個(gè)字母是小寫(xiě)的了,就直接把后面的全拼接進(jìn)來(lái),最終形成了uname

如果說(shuō)這邊的getUName換成getuName,那么解析出來(lái)的就是正確的uName了。

結(jié)論

到這里,我們就可以得出結(jié)論了

因?yàn)?Lombok 生成 get、set 方法的語(yǔ)義規(guī)范與和Jackson 處理 get、set 方法之間的不一致,導(dǎo)致屬性名無(wú)法匹配上,最終也就導(dǎo)致了前端明明傳了參數(shù),后端卻接收不到的問(wèn)題。

擴(kuò)展

我后面去github的 lombok社區(qū) 了解了相關(guān)內(nèi)容,lombook社區(qū)是這樣描述的:

用網(wǎng)頁(yè)翻譯給他翻譯成中文,翻譯有些不對(duì),但是能看明白大概意思就行

lombok的大概意思就是:我就是這樣的規(guī)范,即使其他的工具框架都改了,我也不改,但是建議你們不要使用首字母小寫(xiě)第二個(gè)字母大寫(xiě)的屬性名,避免出現(xiàn)問(wèn)題,可能知名度比較高的框架都比較傲嬌吧哈哈。

但是lombok還是給出了一個(gè)解決方案,加上這個(gè)配置項(xiàng)

lombok.accessors.capitalization = [basic | beanspec] (default: basic)

其中basic代表遵循lombok的規(guī)范(getUName);beanspec代表遵循Spring、Jackson 的規(guī)范(getuName)。默認(rèn)是basic。

看到這里,我就來(lái)總結(jié)一下能解決這個(gè)問(wèn)題的三種方案吧

1. 加@JsonProperty注解強(qiáng)行指定屬性名

@Data
public class UserVO {
    /**
     * 用戶名稱
     */
    @JsonProperty(value = "uName")
    private String uName;
    /**
     * 登錄類型
     */
    private String loginType;
}

2.不使用lombok,使用IDEA默認(rèn)生成get/set方法

3.加上lombok配置項(xiàng)

lombok.accessors.capitalization = [basic | beanspec] (default: basic)

最后,博主的建議是,盡量不要用這種命名方式,如果非要用,那就加上@JsonProperty注解強(qiáng)行指定屬性名,這樣比較方便。

總結(jié)

到此這篇關(guān)于spring中前端明明傳了值后端卻接收不到問(wèn)題解決辦法的文章就介紹到這了,更多相關(guān)spring前端傳值后端接收不到內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java中使用同步回調(diào)和異步回調(diào)的示例詳解

    Java中使用同步回調(diào)和異步回調(diào)的示例詳解

    這篇文章主要介紹了Java中使用同步回調(diào)和異步回調(diào)的相關(guān)資料,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-04-04
  • java計(jì)算π的多種方法

    java計(jì)算π的多種方法

    這篇文章主要介紹了使用java計(jì)算π的多種方法,代碼詳細(xì),邏輯清晰,對(duì)于算法思路可能有所幫助,需要的朋友可以參考下
    2021-04-04
  • spring boot實(shí)戰(zhàn)教程之shiro session過(guò)期時(shí)間詳解

    spring boot實(shí)戰(zhàn)教程之shiro session過(guò)期時(shí)間詳解

    這篇文章主要給大家介紹了關(guān)于spring boot實(shí)戰(zhàn)教程之shiro session過(guò)期時(shí)間的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起看看吧。
    2017-10-10
  • Java基礎(chǔ)學(xué)習(xí)之構(gòu)造方法詳解

    Java基礎(chǔ)學(xué)習(xí)之構(gòu)造方法詳解

    這篇文章主要為大家詳細(xì)介紹了Java基礎(chǔ)學(xué)習(xí)中構(gòu)造方法的概述及注意事項(xiàng),文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)Java有一定幫助,需要的可以參考一下
    2022-08-08
  • SpringCloud之Ribbon使用示例解析

    SpringCloud之Ribbon使用示例解析

    這篇文章主要為大家介紹了SpringCloud之Ribbon使用示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-06-06
  • 使用mtrace追蹤JVM堆外內(nèi)存泄露的方法

    使用mtrace追蹤JVM堆外內(nèi)存泄露的方法

    這篇文章主要給大家介紹了如何使用mtrace追蹤JVM堆外內(nèi)存泄露,文章通過(guò)代碼示例介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下
    2023-09-09
  • 解決dubbo錯(cuò)誤ip及ip亂入問(wèn)題的方法

    解決dubbo錯(cuò)誤ip及ip亂入問(wèn)題的方法

    今天小編就為大家分享一篇關(guān)于解決dubbo錯(cuò)誤ip及ip亂入問(wèn)題的方法,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2019-03-03
  • Java事務(wù)管理學(xué)習(xí)之Spring和Hibernate詳解

    Java事務(wù)管理學(xué)習(xí)之Spring和Hibernate詳解

    這篇文章主要給大家介紹了Java事務(wù)管理學(xué)習(xí)之Spring和Hibernate的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友們可以參考借鑒,下面來(lái)一起看看吧。
    2017-03-03
  • @SpringBootTest 注解報(bào)紅問(wèn)題及解決

    @SpringBootTest 注解報(bào)紅問(wèn)題及解決

    這篇文章主要介紹了@SpringBootTest 注解報(bào)紅問(wèn)題及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • 深入講解RocketMQ原理

    深入講解RocketMQ原理

    這篇文章主要介紹了詳解SpringBoot整合RocketMQ,RocketMQ作為一款純java、分布式、隊(duì)列模型的開(kāi)源消息中間件,支持事務(wù)消息、順序消息、批量消息、定時(shí)消息、消息回溯等,需要的朋友可以參考下
    2023-07-07

最新評(píng)論