誰要是再敢用Map傳參,我過去就是一JIO

image


還記得上次我寫過一篇關於實際項目代碼分層和規劃的文章《看完這篇,別人的開源項目結構應該能看懂了》, 在文尾處提到過一些注意事項,其中第一條就是:java

  • Contorller層參數傳遞建議不要使用HashMap,推薦使用數據模型定義

私信里居然有不少小夥伴提問說,爲何不能這樣作?後端

我內心暗自尋思:難道這麼作的小夥伴都沒有被同事捶嗎?(滑稽)markdown

得嘞,今天我們就掰扯掰扯這件事,這是實際寫代碼時常忽略的一個問題app


是否是有人也這麼寫過?

我本身曾經接手過一個前人留下來的老項目,拿到代碼,導入IDEA的那一刻,我哭出了聲。工具

image

由於它的Controller層代碼都是相似這樣寫的:oop

@RestController
@RequestMapping("/index")
public class IndexController {

    // 獲取App首頁內容
    @PostMapping("/getIndexContent")
    public ResponseWrapper getIndexContent( @RequestBody Map<String, Object> paramMap ) {

        ResponseWrapper res = new ResponseWrapper();

        // 下面開始作傳參有效性的校驗
        if (!paramMap.containsKey("article_id")) {
            res.setCode(500);
            res.setMsg("缺乏 article_id 信息");
            return res;
        }

        if (!paramMap.containsKey("page")) {
            res.setCode(500);
            res.setMsg("缺乏 page 信息");
            return res;
        }

        if (!paramMap.containsKey("size")) {
            res.setCode(500);
            res.setMsg("缺乏 size 信息");
            return res;
        }

        if (!paramMap.containsKey("version")) {
            res.setCode(500);
            res.setMsg("缺乏 version 信息");
            return res;
        }

        // ...... 此處省略

    }

    // ...... 此處省略

}
複製代碼

別的咱先不說,竟然明目張膽地在Controller層裏方法裏用Map傳參?!簡直喪心病狂了。幸好下面還有一波傳參有效性的驗證,對於傳遞的參數,我好歹也能猜個大概,否則那真是喵了個咪了。測試

接下來,咱們就好好嘮一嘮:爲何不要在Controller層傳參時使用Map類型!spa


Map一時爽,維護爽歪歪

正好,這地方有一個咱小夥伴活生生的例子。插件

記得以前有個小夥伴提問,問過一個這樣的問題,說他接手了一個別人的老項目,問了我一個相似這樣的問題:3d

image

看到沒!

Map傳參的第一個(也是最大的一個)弊端就是:這會致使後續接手和維護的人懷疑本身的人生,由於他根本不知道代碼傳的啥參數,想要構造參數去調試接口只能靠腦補摸瞎、以及猜想了。

試想一下,其實咱們代碼裏任何一個地方的傳參均可以使用Map來傳,若是真的這麼作了,代碼中連任何數據模型類都不須要定義了,果然如此的話,這樣的代碼咱能看懂嗎?

並且這位小夥伴接手的項目竟然還用的是LinkedHashMap參數,能夠說很秀了。

image

除此以外,緊接着還會帶來下面這個問題。


好用的API工具與你無緣了

我以前寫過一篇文章《先後端都分離了,該搞個好用的API管理系統了!》,聊過如今市面上一些比較好用的、能極大提高先後端開發效率的API管理工具,這對於先後端開發來講,簡直是莫大的福音。

咱們就以Swagger這個API工具爲例,若是Controller傳參使用Map的話:

// 獲取App首頁內容
@ApiOperation("獲取App首頁內容")
@PostMapping("/getIndexContent")
public ResponseWrapper getIndexContent( @RequestBody Map<String, Object> paramMap ) {

    // ...... 此處省略

}
複製代碼

API工具沒法讀取具體參數項目和參數類型,因此傳參什麼的也看不出來:

image

換言之,我若是將上面的Map傳參改成自定義數據模型類IndexQueryDto來傳參的話:

// 獲取App首頁內容
@ApiOperation("獲取App首頁內容(改造後)")
@PostMapping("/getIndexContent")
public ResponseWrapper getIndexContent( @RequestBody IndexQueryDto indexQueryDto ) {

    // ...... 此處省略

}
複製代碼
@ApiModel(value = "App首頁內容請求參數實體對象")
class IndexQueryDto {

    @ApiModelProperty(value = "文章ID號")
    @NotNull(message = "缺乏 article_id 信息")
    private Long article_id;


    @ApiModelProperty(value = "頁面數")
    @NotNull(message = "缺乏 page 信息")
    private Integer page;

    @ApiModelProperty(value = "每頁條目數")
    @NotNull(message = "缺乏 size 信息")
    private Integer size;

    @ApiModelProperty(value = "App版本號")
    @NotNull(message = "缺乏 version 信息")
    private String version;

    // ...... 此處省略set/get方法

}
複製代碼

則相似Swagger這種API工具就很是方便地能幫助咱們管理參數了:

image

這樣不論是本身調試,仍是前、後端對接口都會方便得多。


同理,除了Swagger這種API管理工具以外,像在個人前文《沒用過這些IDEA插件?怪不得寫代碼頭疼》中推薦過的一個很是好用的接口管理插件RestfulToolkit也沒法識別出Map類型所盛放的具體參數:

image

可是對於數據模型的定義參數,就能很是清晰的給出參數細節,並方便地提供接口測試:

image


優秀的註解無法使用了

仍是以文章開頭舉例的代碼來講,無論怎麼樣,寫這段代碼的哥們仍是負責的,畢竟兢兢業業地用手工連環if()判斷完成了全部參數的有效性校驗:

image

但問題是,咱們真的須要這種辣眼睛的手工連環if()判斷來作參數校驗嗎?

image

一樣在前文《啥?據說你還在手寫複雜的參數校驗?》中也說過了,咱們其實能夠經過註解來方便地規避繁雜的參數校驗工做,但前提是不能使用Map類型傳參,須要使用數據模型的定義,就像這樣:

class IndexQueryDto {

    @NotNull(message = "缺乏 article_id 信息")
    private Long article_id;

    @NotNull(message = "缺乏 page 信息")
    private Integer page;

    @NotNull(message = "缺乏 size 信息")
    private Integer size;

    @NotNull(message = "缺乏 version 信息")
    private String version;

    // ...... 此處省略get/set方法
}
複製代碼

一個NotNull註解便可搞定,它不香嗎?


Map傳參真的一無可取嗎?

有些小夥伴表示用Map傳參的好處就是能夠隨意擴展,後期變更靈活,想往裏面塞幾個參數就塞幾個參數;並且也省去了各類對象定義和命名的煩惱。

image


若是非要用Map傳參

若是實在不能避免用Map傳參,也麻請配備完備的測試用例吧,免得讓後來接手維護的人每天看着代碼懷疑人生了。

經過測試用例,後來接手維護的人也能快速搞清代碼間的參數傳遞和調用,否則真的只能靠腦補畫面去調試了。


噓...

好了,說了這麼多,若是你項目的Controller層代碼還在使用Map傳參的話,答應我,二話別說,趕快所有偷偷去改掉,快!速度!跑步前進!

image
相關文章
相關標籤/搜索