Swagger使用————接口参数注解的使用缺陷
問(wèn)題描述
在使用springboot開(kāi)發(fā)web項(xiàng)目時(shí),用到了swagger框架,來(lái)生成web api文檔。但是其中有一項(xiàng)是舉例說(shuō)明參數(shù)的結(jié)構(gòu),如下圖:
但是,這個(gè)功能真的是非常方便,因?yàn)榭梢宰屒岸碎_(kāi)發(fā)人員第一時(shí)間得知參數(shù)的內(nèi)部結(jié)構(gòu)是什么樣的,這尤其適用于那些json體結(jié)構(gòu)的參數(shù)。網(wǎng)上的例子都是這樣的:
但是,我無(wú)論如何都弄不出來(lái)這個(gè)樣子,前前后后研究了有好幾個(gè)小時(shí)。
終于找出了問(wèn)題。
問(wèn)題原因
網(wǎng)上的api接口中,幾乎全是傳入一個(gè)完整的Java Bean對(duì)象,而不是傳JsonObject對(duì)象。
我的代碼是這樣:
@ApiOperation(value = "添加景區(qū)下的特價(jià)門(mén)票", notes = "{\"scenicIdArr\" : [53361,53356]}")@PostMapping(value = "/special_price/add")public JSONObject addSpecialPrice(@RequestBody JSONObject scenicIdArr) {return sprSvc.addSpecialPrice(scenicIdArr);}別人的代碼是這樣:
????@ApiOperation("更改用戶信息")@PostMapping("/updateUserInfo")public int updateUserInfo(@RequestBody @ApiParam(name="用戶對(duì)象",value="傳入json格式",required=true) User user){int num = userService.updateUserInfo(user);return num;}經(jīng)過(guò)比較,很容易就發(fā)現(xiàn)了問(wèn)題,我的接口中的參數(shù)是無(wú)法得知內(nèi)部數(shù)據(jù)結(jié)構(gòu)的JSONObject類型,而別人的參數(shù)是一個(gè)已知其內(nèi)部數(shù)據(jù)結(jié)構(gòu)的User對(duì)象。
既然知道了原因,那我也將接口進(jìn)行了一些修改:
創(chuàng)建一個(gè)符合我業(yè)務(wù)要求的數(shù)據(jù)結(jié)構(gòu)實(shí)體類,然后將這個(gè)實(shí)體類作為參數(shù)傳入接口中:
@ApiOperation(value = "添加景區(qū)下的特價(jià)門(mén)票", notes = "{\"scenicIdArr\" : [53361,53356]}")@PostMapping(value = "/special_price/add")public JSONObject addSpecialPrice(@RequestBody ScenicIdArr scenicIdArr) {return null;}@ApiModelclass ScenicIdArr {@ApiModelProperty(value = "景區(qū)id數(shù)組")int[] scenicIdArr;}上述代碼中,我定義了一個(gè)成員內(nèi)部類,并將實(shí)體類以@ApiModel進(jìn)行注解。效果如下:
呵呵,沒(méi)有一丁點(diǎn)效果!我陷入了沉思... ...
于是我大膽的猜想:swagger框架可能是自動(dòng)調(diào)用了get或set方法,并完成頁(yè)面渲染。
于是我又修改了代碼:
@ApiOperation(value = "添加景區(qū)下的特價(jià)門(mén)票", notes = "{\"scenicIdArr\" : [53361,53356]}")@PostMapping(value = "/special_price/add")public JSONObject addSpecialPrice(@RequestBody ScenicIdArr scenicIdArr) {return null;}@ApiModelclass ScenicIdArr {@ApiModelProperty(value = "景區(qū)id數(shù)組")int[] scenicIdArr;public int[] getScenicIdArr() {return scenicIdArr;}}我加了一個(gè)get方法,來(lái)獲取實(shí)體類中的屬性,看一下效果:
上圖中可以看到,不論是整體的實(shí)體類結(jié)構(gòu),還是字段上的注釋“景區(qū)id數(shù)組”都很好的顯示了出來(lái)。這樣,我們?cè)陧?yè)面點(diǎn)擊小黃框的時(shí)候,就可以將數(shù)據(jù)自動(dòng)的加載到參數(shù)填寫(xiě)的白框內(nèi)。
這樣,我們省去了手動(dòng)書(shū)寫(xiě)結(jié)構(gòu)和key值的過(guò)程,而只需要我們輸入具體的value值即可。
由于本篇博客并不是教你如何使用spring-boot-starter-swagger自動(dòng)依賴配置模塊中的各種注解如何使用,因此,此處只是簡(jiǎn)單解析了一下接口參數(shù)的模板生成方式。
但是,題目中既然提到了這個(gè)功能的缺陷,就不得不回過(guò)頭來(lái)吐槽一下這個(gè)破JB玩意兒!
吐槽一下
這個(gè)在小黃框顯示對(duì)外接口參數(shù)結(jié)構(gòu)的功能真的應(yīng)該說(shuō)是非常實(shí)用的一個(gè)功能,我并不知道這個(gè)功能具體的名稱是什么,暫且就稱它為“參數(shù)樣例功能”。
為什么說(shuō)這個(gè)功能非常實(shí)用?
首先,書(shū)寫(xiě)簡(jiǎn)便。REST接口風(fēng)格的參數(shù)多以json結(jié)構(gòu)體傳輸數(shù)據(jù),而這樣一個(gè)自動(dòng)生成結(jié)構(gòu)體的功能,可以為我們免去書(shū)寫(xiě)大量括號(hào)、冒號(hào)、逗號(hào)、引號(hào)、空格等json體的必須元素,而且自動(dòng)排版,避免手寫(xiě)出錯(cuò),達(dá)到零錯(cuò)誤。在真正通過(guò)頁(yè)面的api接口測(cè)試的時(shí)候,只需要簡(jiǎn)單輸入幾個(gè)value值就可以“try it out”了,著實(shí)提高了不少效率。
其次,方便前端開(kāi)發(fā)。我們都知道,不論是傳入JavaBean對(duì)象,還是傳入沒(méi)有在后端強(qiáng)制類型約束的Json字符串,前端調(diào)用controller中的接口時(shí),僅僅是傳入一個(gè)key-value的結(jié)構(gòu),才不會(huì)管你什么JavaBean。對(duì)于springboot,其一系列內(nèi)嵌的HttpMessageConverter會(huì)將json結(jié)構(gòu)轉(zhuǎn)化成對(duì)應(yīng)的JavaBean,再交給Controller。前端開(kāi)發(fā)人員甚至可以將小黃框內(nèi)的內(nèi)容,直接拷貝過(guò)來(lái),稍作修改(value賦值)即可完成對(duì)后端接口對(duì)接的全部編碼。
第三,覆蓋了其他部分注解。個(gè)人認(rèn)為,swagger中的注解關(guān)于參數(shù)注釋方面,有些重復(fù),這一點(diǎn)不做展開(kāi)討論,且僅僅是個(gè)人觀點(diǎn),可以參考官方api文檔體會(huì)一下。另外關(guān)于response一類的注解,完全沒(méi)有必要。返回值是什么結(jié)構(gòu)的,完全可以通過(guò)“try it out”調(diào)用一次接口即可了解到。估計(jì)swagger開(kāi)發(fā)團(tuán)隊(duì)考慮到功能的完整性,或者在后端由于某種原因?qū)е陆涌诓豢捎枚龅囊环N補(bǔ)足方案(比如,數(shù)據(jù)庫(kù)中暫無(wú)數(shù)據(jù)等原因)。
雖然這個(gè)功能實(shí)用,但是依然存在一個(gè)很別扭的情況。
那就是,我們不得不因?yàn)橐凇皡?shù)樣例功能”中展示我們的參數(shù)結(jié)構(gòu)而創(chuàng)建一個(gè)Java Bean。不論這個(gè)Java Bean在后臺(tái)邏輯中有無(wú)實(shí)際意義。
就比方說(shuō)我之前的那個(gè)接口:
????@ApiOperation(value = "添加景區(qū)下的特價(jià)門(mén)票", notes = "{\"scenicIdArr\" : [53361,53356]}")@PostMapping(value = "/special_price/add")public JSONObject addSpecialPrice(@RequestBody JSONObject scenicIdArr)我需要拿到一個(gè)有景區(qū)id組成的json體的數(shù)據(jù)結(jié)構(gòu),然后跑到service中去處理,可能我的這種api結(jié)構(gòu)并不規(guī)范,但是不可能不存在這樣一種情況:僅僅規(guī)定一個(gè)json結(jié)構(gòu),而不是Java Bean來(lái)作為參數(shù)進(jìn)行處理。(抱歉,最近在看《Thinking In Java》句子寫(xiě)起來(lái)有那么一點(diǎn)模仿布魯斯埃克爾的腔調(diào))
我查找了很多資料,包括官方的API說(shuō)明,并沒(méi)有很好解決方案。于是,才有了后面的成員內(nèi)部類的出現(xiàn)。但是這種代碼除了方便測(cè)試以外完全沒(méi)有實(shí)際意義。如果為每個(gè)以json結(jié)構(gòu)體作為參數(shù)的接口另起一個(gè)class文件去明確傳入?yún)?shù)的結(jié)構(gòu),就顯得有些愚蠢。它會(huì)使你的代碼非常的臃腫和凌亂。
這就是我說(shuō)的swagger的這個(gè)缺陷,以純json結(jié)構(gòu)體作為參數(shù)的接口,無(wú)法實(shí)現(xiàn)非常重要的“參數(shù)樣例功能”。
綜上,就是我對(duì)swagger框架的一點(diǎn)看法和總結(jié),如有疑問(wèn),歡迎文末留言。
總結(jié)
以上是生活随笔為你收集整理的Swagger使用————接口参数注解的使用缺陷的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: c 语言运算符号大全,c语言运算符号详细
- 下一篇: oracle用户密码复杂度查询,11gR