<del id="nnjnj"></del><track id="nnjnj"></track>

<p id="nnjnj"></p>

<address id="nnjnj"></address>

    <pre id="nnjnj"><pre id="nnjnj"></pre></pre>

      <noframes id="nnjnj"><ruby id="nnjnj"><ruby id="nnjnj"></ruby></ruby>

      • 自動秒收錄
      • 軟件:1973
      • 資訊:57811|
      • 收錄網站:279872|

      IT精英團

      能夠在JAVA中自定義和擴展Swagger 自動生成參數值的含義 提高開發效率

      能夠在JAVA中自定義和擴展Swagger 自動生成參數值的含義 提高開發效率

      瀏覽次數:
      評論次數:
      編輯: 溫瑜
      信息來源: ITPUB
      更新日期: 2022-09-06 21:10:36
      摘要

      大家好,又見面了。在JAVA做前后端分離的項目開發的時候,服務端需要提供接口文檔供周邊人員做接口的對接指導。越來越多的項目都在嘗試使用一些基于代碼自動生成接口文檔的工具來替代由開發人員手動編寫接口文檔

      • 正文開始
      • 相關閱讀
      • 推薦作品

      大家好。又見面了。

      JAVA在做前后端分離的項目開發時,服務器需要提供接口文檔給外圍人員做接口對接指導。越來越多的項目在嘗試使用一些基于代碼自動生成界面文檔的工具,而不是開發人員手工編寫的界面文檔。Swagger作為一款優秀的在線界面文檔生成工具,以其強大的功能和易于集成而被廣泛使用。

      項目中有一個很常見的場景,就是接口的請求或響應參數中會有一些字段的取值會限定為固定的幾個可選值之一,這些可選值往往是通過在代碼中定義枚舉類來攜帶的,比如:

      根據操作類型,過濾相應類型的用戶操作日志列表。

      比如:http://127 . 0 . 0 . 0/test/queryoperatelogs?operateType=2

      這里,請求參數operateType傳入的值需要在后端同意的值范圍內。該值范圍的定義如下:

      @Getter

      @AllArgsConstructor

      公共枚舉操作類型{

      添加(1,“添加或創建操作”),

      修改(2,“更新現有數據操作”),

      刪除(3,'刪除數據操作'),

      查詢(4,‘查詢數據操作’);

      private int值;

      私弦desc;

      }

      這里我們需要在這個接口中指定operateType的可選值,并在接口文檔中指定每個可選值對應的含義信息,以便調用方在使用時知道應該傳入什么值。

      當我們基于Swagger提供的基本注釋能力實現它時,我們會經??吹揭韵聝煞N寫法:

      寫法1:接口定義的時候,指定入參的取值說明接口的URL中攜帶的請求參與信息,通過@ ApiImplicitParam注釋告訴調用者該接口允許接收的合法operateType的值的范圍以及每個值的含義。

      例如,以下場景:

      @GetMapping('/queryOperateLogs ')

      @ApiOperation('查詢指定操作類型的操作日志列表')

      @ apimplicitparam(name=' operate type ',value='操作類型,值描述:1,new2.更新;3、除;4,query ',datatype=' int ',param type=' query ')

      public list operatelogqueryoperatelogs(int operate type){

      返回testservice . queryoperatelogs(operate type);

      }

      這樣,就可以在swagger界面上顯示該字段的值描述信息。

      其實還有另外一種寫法,就是在代碼的參數前面加上@ApiParam注釋。例如:

      @GetMapping('/queryOperateLogs ')

      @ApiOperation('查詢指定操作類型的操作日志列表')

      ListOperatelog query operatelog(@ API param(value='操作類型,值描述:1,new2.更新;3.刪除;4,query ')@ request param(' type ')int operate type){

      返回testservice . queryoperatelogs(operate type);

      }

      這樣也能達到同樣的效果。

      寫法2:請求或者響應的Body體中解釋字段的取值說明可以使用@ApiModelProperty為需要通過json body傳輸的請求或響應消息體模型添加含義描述。

      @數據

      @ApiModel('操作記錄信息')

      公共類操作日志

      { @ApiModelProperty("操作類型,取值說明: 1,新增;2,更新;3,刪除;4,查詢") private int operateType; @ApiModelProperty("操作用戶") private String user; @ApiModelProperty("操作詳情") private String detail;}

      同樣,在Swagger界面就可以清楚的知道每個字段的具體含義與取值說明。

      但是上面的兩個寫法,都存在著同一個問題,就是如果枚舉類中的值內容含義有變更,比如OperateType枚舉類中新增了一個BATCH_DELETE(5, "批量刪除"), 則必須手動去修改所有涉及的接口上的Swagger描述信息。如果有大量場景都涉及此字段,則要改動的地方就非常多,且極易漏掉(因為不好通過代碼關聯關系直接搜索到)。這樣對于開發人員維護起來的成本就會增加,久而久之會導致接口文檔的內容與實際代碼處理情況不相匹配。

      那么,有沒有什么簡單的方式,可以讓接口文檔自動根據對應枚舉類的內容變更而動態變更呢?

      Swagger沒有提供原生的此方面能力支持,但是我們可以通過一些簡單的方式對Swagger的能力進行擴展,讓Swagger支持我們的這種訴求。一起來看下如何實現吧。

      擴展可行性分析

      既然想要改變生成的Swagger文檔中指定字段的描述內容,那么首先就應該是要搞清楚Swagger中現在的內容生成邏輯是如何處理的。我們以@ApiParam為例進行分析。因為@ApiParam中指定的內容會被顯示到Swagger界面上,那么在Swagger的框架中,一定有個地方會嘗試去獲取此注解中指定的相關字段值,然后將注解的內容轉為界面上的文檔內容。所以想要定制,首先必須要了解當前是如何處理的。

      翻看Swagger的源碼,發現在ApiParamParameterBuilder類中進行此部分邏輯的處理,處理邏輯如下:

      看了下此類是ParameterBuilderPlugin接口的一個實現類,Swagger框架在遍歷并逐個生成parameter說明信息的時候會被調用此實現類的邏輯來執行。

      到這里其實問題就已經很明顯了,我們可以自定義一個處理類并實現ParameterBuilderPlugin接口,然后將我們的訴求在自定義的處理類中進行實現,這樣不就可以實現我們的訴求了嗎?

      相同的策略,我們可以找到處理@ApiImplicitParam、@ApiModelProperty對應的接口類。

      根據上面的分析,我們只需要提供個自定義實現類,然后分別實現這幾個接口就可以搞定我們的訴求了。那應該如何進行封裝,將其作為一個通用能力供所有場景使用呢,下面詳細討論下。

      自定義注解實現基于枚舉類生成描述

      前面已經找到了一種思路將我們的定制邏輯注入到Swagger的文檔生成框架中進行調用,那么下一步我們就得確認一種相對簡單的策略,告訴框架哪個字段需要使用枚舉來自動生成取值說明,以及使用哪個枚舉類來生成。

      這里我們使用自定義注解的方式來實現。Swagger為不同的場景分別提供了@APIParam、@ApiImplicitParam、@ApiModelProperty等不同的注解,我們可以簡化下,提供一個統一的自定義注解即可。

      比如:

      @Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER })@Retention(RetentionPolicy.RUNTIME)public @interface ApiPropertyReference {    // 接口文檔上的顯示的字段名稱,不設置則使用field本來名稱    String name() default "";    // 字段簡要描述,可選    String value() default "";    // 標識字段是否必填    boolean required() default  false;    // 指定取值對應的枚舉類    Class<? extends Enum> referenceClazz();}

      這樣呢,對于需要添加取值說明的字段或者接口上,我們就可以添加@ApiPropertyReference并指定對應的枚舉類即可。

      比如下面這樣:

      @Data@ApiModel("操作記錄信息")public class OperateLog {    @ApiPropertyReference(value = "操作類型", referenceClazz = OperateType.class)    private int operateType;    // ... }

      上面示例代碼中,OperateType是一個已經定義好的枚舉類?,F在又遇到一個問題,枚舉類的實現形式其實也不一樣,要如何才能讓我們的自動內容生成服務知道獲取枚舉類中的哪些內容進行處理呢?當然我們可以約定用于Swagger注解中的枚舉類必須遵循某個固定的格式,但顯然這樣實施的難度就會提升,并非是我們想要的結果。

      先來看下面給定的這個枚舉類,其中包含order、value、desc三個屬性值,而value字段是我們的接口字段需要傳入的真實取值,desc是其對應的含義描述,那么該如何讓我們自定義Swagger擴展類知曉應該使用valuedesc字段來生成文檔描述內容呢?

      @Getter@AllArgsConstructorpublic enum OperateType {    ADD(1, 11, "新增"),    MODIFY(2, 22, "更新"),    DELETE(3, 33, "刪除");    private int order;    private int value;    private String desc;}

      答案其實不陌生,依舊是自定義注解!只要提供個自定義注解,然后添加到枚舉類上,指定到底使用枚舉類中的哪個字段作為value值,以及哪個字段用作含義描述desc字段值就行了。

      @Target({ ElementType.TYPE })@Retention(RetentionPolicy.RUNTIME)public @interface SwaggerDisplayEnum {    String value() default "value";    String desc() default "desc";}

      這樣,在枚舉類上添加下@SwaggerDisplayEnum并指定下字段的映射,即可用于Swagger注解中:

      到這里呢,我們需要的數據來源以及取值轉換規則就已經全部確定,剩下的就是如何將一個枚舉類中需要的值與描述字段給拼接成想要的內容了。因為是通用能力,所以此處需要通過反射的方式來實現:

      private String generateValueDesc(ApiPropertyReference propertyReference) {    Class<? extends Enum> rawPrimaryType = propertyReference.referenceClazz();    SwaggerDisplayEnum swaggerDisplayEnum = AnnotationUtils.findAnnotation(rawPrimaryType,            SwaggerDisplayEnum.class);    String enumFullDesc = Arrays.stream(rawPrimaryType.getEnumConstants())            .filter(Objects::nonNull)            .map(enumConsts -> {                Object fieldValue = ReflectUtil.getFieldValue(enumConsts, swaggerDisplayEnum.value());                Object fieldDesc = ReflectUtil.getFieldValue(enumConsts, swaggerDisplayEnum.desc());                return fieldValue + ":" + fieldDesc;            }).collect(Collectors.joining(";"));    return propertyReference.value() + "(" + enumFullDesc + ")";}

      測試下輸出如下面的格式,自動將枚舉類中所有的枚舉值及其描述信息都展示出來了。

      (1:新增;2:更新;3:刪除)

      實現自定義擴展處理器

      至此呢,我們已經做好了全部的準備工作,下面就可以按照前面分析的策略,來自定義一個實現類去實現相關接口,將我們的處理轉換邏輯注入到Swagger框架中去。

      @Component@Primarypublic class SwaggerEnumBuilderPlugin implements ModelPropertyBuilderPlugin, ParameterBuilderPlugin {    @Override    public void apply(ModelPropertyContext context) {        // Model中field字段描述的自定義處理策略    }    @Override    public void apply(ParameterContext parameterContext) {        // API中入參的自定義處理策略    }    @Override    public boolean supports(DocumentationType delimiter) {        return true;    }}

      下面只需要在apply方法中補充上我們的自定義處理邏輯即可。

      自動生成API入參的取值說明

      前面已經講了如何將指定的枚舉類中的枚舉值生成為描述字符串,在這里我們直接調用,然后將結果設置到context上下文中即可。

      @Overridepublic void apply(ParameterContext context) {    ApiPropertyReference reference =            context.getOperationContext().findAnnotation(ApiPropertyReference.class).orNull();    String desc = generateValueDesc(reference);    if (StringUtils.isNotEmpty(reference.name())) {        context.parameterBuilder().name(reference.name());    }    context.parameterBuilder().description(desc);    AllowableListValues allowableListValues = getAllowValues(reference);    context.parameterBuilder().allowableValues(allowableListValues);}

      自動生成Model中字段取值說明

      同樣的策略,我們處理下數據實體類中的field對應的含義說明。

      @Overridepublic void apply(ModelPropertyContext modelPropertyContext) {    if (!modelPropertyContext.getBeanPropertyDefinition().isPresent()) {        return;    }    BeanPropertyDefinition beanPropertyDefinition = modelPropertyContext.getBeanPropertyDefinition().get();    // 生成需要拼接的取值含義描述內容    String valueDesc = generateValueDesc(beanPropertyDefinition);    modelPropertyContext.getBuilder().description(valueDesc)            .type(modelPropertyContext.getResolver()                    .resolve(beanPropertyDefinition.getField().getRawType()));}}

      效果演示

      到這里呢,代碼層面的處理就全部完成了。接下來運行下程序,看下效果。先來看下API接口中入參的含義描述效果:

      從界面效果上可以看出,不僅自動將取值說明描述給顯示出來,同時界面調測的時候,輸入框也變為了下拉框 (因為我們自動給設置了allowableValues屬性),只能輸入允許的值。同樣的,再來看下Model中的字段的含義說明描述效果:

      可以看到,接口文檔中的參數描述信息中,已經自動帶上了枚舉類中定義的候選取值內容與說明。我們僅修改下枚舉類中的內容,其余地方不做修改,再次看下界面,發現Swagger接口中的描述內容已經同步更新為最新的內容。

      完美,大功告成

      python入門系列(十)學習Python文件處理
      ? 上一篇 2022-09-06
      大促銷活動如何抵御高流量DDoS攻擊?
      下一篇 ? 2022-09-06
      • 如何在Ubuntu中保留文件系統并備份當前開發板鏡像
        0閱讀 0條評論 個贊
        在Ubuntu保留文件系統或者說備份當前開發板鏡像的需求在不斷增加。比如Ubuntu文件系統需要安裝庫文件的話直接使用apt-get工具就可以下載,但由于需要下載的核心板較多,比較費時間,這時需要將安……
      • 國產核心板全志T507助力消防系統升級
        0閱讀 0條評論 個贊
        9月16日下午,位于湖南長沙市區內的中國電信大樓發生火災,建筑高度218米,現場濃煙滾滾,數十層樓體燃燒劇烈。消防救援人員趕到現場后很快將火勢控制住,目前大樓火勢已被撲滅,所幸未發現人員傷亡。湖南電信……
      • 教大家如何處理Spring Boot易流中的用戶和群體!
        0閱讀 0條評論 個贊
        1.準備工作2.用戶操作2.1添加用戶2.2修改用戶2.3刪除用戶2.4查詢用戶3.組操作3.1添加組3.2修改組3.3刪除組3.4查詢組4.查看表詳情雖然說我們在實際開發中,……
      • 從PG15開始WAL壓縮優化
        0閱讀 0條評論 個贊
        PG15傳聞中的超級令人激動的功能大多數跳票了,年初我也寫過一個關于PG15新功能跳票的文章。PG15BETA已經發出幾個月了,似乎PG15里令人激動人心的功能不多,不過從長長的新功能列表里,……
      • 深入了解美團葉子發射器開源方案
        0閱讀 0條評論 個贊
        大家好,我是樹哥。之前我們有聊過「如何設計一個分布式ID發號器」,其中有講過4種解決方案,分別是:UUID類雪花算法數據庫自增主鍵Redis原子自增美團以第2、3種解決方案為基礎,開發出……
      發表評論 共有條評論
      用戶名: 密碼:
      驗證碼: 匿名發表
      • spring接口有多個實現類 應該給哪個注入這個依賴?
        0閱讀 0條評論 個贊
        一、問題的描述在實際的系統應用開發中我經常會遇到這樣的一類需求,相信大家在工作中也會經常遇到:同一個系統在多個省份部署。一個業務在北京是一種實現方式,是基于北京用戶的需求。同樣的業務在上海是另外一種實……
      • SQL SERVER存儲過程學習筆記
        6閱讀 0條評論 個贊
        將常用的或很復雜的工作,預先用SQL語句寫好并用一個指定的名稱存儲起來,那么以后要叫數據庫提供與已定義好的存儲過程的功能相同的服務時,只需調用execute,即可自動完成命令。存儲過程的優點1.存儲……
      • web端pdf編輯能力的設計與實踐
        0閱讀 0條評論 個贊
        本期作者顧伊凡嗶哩嗶哩資深開發工程師2021年加入B站,負責UP主創作激勵、收益中心、電子簽約平臺前端建設。本文將從業務場景與技術實現等角度對“web端pdf編輯能力”進行基本的介紹。01背景B站電……
      • :自古以來 特工程序就是兵家必敗之地
        0閱讀 0條評論 個贊
        正向代理的血案前幾天打算使用golang做一個代理程序,golang標準庫net/http/httputil已經提供了這樣的能力。一把梭之后發現必然返回403Forbidden,我直接在targe……
      • Sql Server系列:分區表操作
        0閱讀 0條評論 個贊
        1.分區表簡介分區表在邏輯上是一個表,而物理上是多個表。從用戶角度來看,分區表和普通表是一樣的。使用分區表的主要目的是為改善大型表以及具有多個訪問模式的表的可伸縮性和可管理性。分區表是把數據……
      • Hadoop JMX監控和預警
        0閱讀 0條評論 個贊
        .css-1yuhvjn{margin-top:16px;}.css-3jt6os.FileLinkCard{-webkit-align-items:center;-webkit-box-align……
      • spring MVC(II)——請求處理參數和響應數據處理
        0閱讀 0條評論 個贊
        1、請求處理參數1.1請求參數@RequestParam1.1.1不使用@RequestParam注解請求參數處理,不使用參數注解:1.如果請求參數名和請求處理的形參名一致,springMv……
      • 圖解架構| SaaS、PaaS、IaaS
        0閱讀 0條評論 個贊
        這是悟空的第164篇原創文章官網:www.passjava.cn你好,我是悟空哥。上次聊到了架構圖如何畫,其中涉及到了云服務的架構圖,里面提到了很重要的三個概念PaaS、IaaS、SaaS,很有必要……
      • 用Python實現廣度優先搜索
        3閱讀 0條評論 個贊
        圖是一種善于處理關系型數據的數據結構,使用它可以很輕松地表示數據之間是如何關聯的圖的實現形式有很多,最簡單的方法之一就是用散列表背景圖有兩種經典的遍歷方式:廣度優先搜索和深度優先搜索。兩者是相似的。實……
      • Velox簡介:一個開源的統一執行引擎
        0閱讀 0條評論 個贊
        ?Meta正在引入Velox,這是一個開源的統一執行引擎(unifiedexecutionengine),旨在加速數據管理系統和簡化其開發。?Velox正在積極開發中,Meta在2022……
      • 教你如何構建JAVA分布式爬蟲
        0閱讀 0條評論 個贊
        在工作中,我們經常需要去獲取一些數據,但是這些數據可能需要從第三方平臺才可以獲取到。這個時候,爬蟲系統就可以幫助我們來完成這些事情。提到爬蟲系統,很多人都會想到使用python。但實際上,語言只……
      • 基于ASP.NET核心6.0的簡潔架構
        0閱讀 0條評論 個贊
        背景最近嘗試錄制了一個系列視頻:《ASP.NETCore6.0+Vue.js3實戰開發》,本節是視頻內部整潔架構的理論和實戰的文字稿。因為在錄制之前,我通常會編寫完整的文字內容作為視頻文案,這……
      • Java精進-手寫持久層框架
        0閱讀 0條評論 個贊
        前言本文適合有一定java基礎的同學,通過自定義持久層框架,可以更加清楚常用的mybatis等開源框架的原理。JDBC操作回顧及問題分析學習java的同學一定避免不了接觸過jdbc,讓我們來回顧下初學……
      • 簡單分析下的GOLDENDB
        0閱讀 0條評論 個贊
        GOLDENDB是金融行業使用的比較廣泛的一個數據庫產品,以前也經常有朋友希望我寫幾篇分析GoldenDB數據庫的文章。說實在的這類文章不好寫,必須對某個產品有一定程度的了解,特別是真正上手用過之后,……
      • 面試官:為什么系統不推薦雙寫?
        0閱讀 0條評論 個贊
        某日,阿雄跑去面試!于是有如下情形面試官:"阿雄是吧,做做自我介紹!"阿雄:"我叫阿雄,來自某a國際電商公司!"面試官:"我看你項目里用了elasticsearch,你是怎么同步數據的呢?"阿……
      • 解決ShardingJdbc不支持復雜SQL問題的說明
        18閱讀 0條評論 個贊
        背景介紹公司最近做分庫分表業務,接入了ShardingJDBC,接入完成后,回歸測試時發現好幾個SQL執行報錯,關鍵這幾個表都還不是分片表。報錯如下:這下糟了嘛。熟悉ShardingJDB……
      • 關于Redis在windows上運行的問題和fork函數
        0閱讀 0條評論 個贊
        Redis在將數據庫進行持久化操作時,需要fork一個進程,但是windows并不支持fork,導致在持久化操作期間,Redis必須阻塞所有的客戶端直至持久化操作完成。微軟的一些工程師花費時間在解決在……
      • 基于iframe的微前端框架——青田
        33閱讀 0條評論 個贊
        vivo互聯網前端團隊-JiangZuohan一、背景VAPD是一款專為團隊協作辦公場景設計的項目管理工具,實踐敏捷開發與持續交付,以「項目」為核心,融合需求、任務、缺陷等應用,使用敏捷迭代、小……
      • SpringMVC 03: 請求和響應的亂碼解決 + SpringMVC響應Ajax請求
        1閱讀 0條評論 個贊
        請求或響應的中文亂碼問題tomcat9解決了get請求和響應的中文亂碼問題,但是沒有解決post請求或響應的中文亂碼問題tomcat10解決了get和post請求以及響應的中文亂碼問題考慮到實際項目中……
      • 內存泄漏——原因、避免和位置
        0閱讀 0條評論 個贊
        .css-1yuhvjn{margin-top:16px;}.css-3jt6os.FileLinkCard{-webkit-align-items:center;-webkit-box-align……
      最近發布資訊
      更多
      警花高潮嗷嗷叫
      <del id="nnjnj"></del><track id="nnjnj"></track>

      <p id="nnjnj"></p>

      <address id="nnjnj"></address>

        <pre id="nnjnj"><pre id="nnjnj"></pre></pre>

          <noframes id="nnjnj"><ruby id="nnjnj"><ruby id="nnjnj"></ruby></ruby>