好物安利:Swagger2

目錄

 

●What & Why

●引入依賴

●正常開發

●Swagger2配置

●編輯API接口

●Swagger-UI查看文檔

●彩蛋:swagger-ui-layer

●小結


●What & Why

大家加入一個項目團隊,接手一個全新的項目時有沒有遇到這種情況:項目參與人數衆多,開發週期長,沒有很好的API文檔,甚至代碼中註釋也寥寥無幾,有時候一個方法,或者一個類只有一句話描述,必須要自己去通讀代碼才能理解。筆者作爲新人,加入目前的項目之初就有這樣的想法,當時覺得要是有一個完善的API文檔該多好

但現實中,想要輸出一個好的API文檔其實困難重重,首先,因爲團隊作戰,風格統一是最大的一道坎,API文檔應該怎麼去寫,有什麼格式規定,必須要保持一致,否則難以維護;其次,大家工作都很飽和,想要擠出時間來生成與維護這樣一份文檔,其實是蠻花費時間和精力的一件事。

筆者最近學習SpringBoot時就發現了一個利器,可以很好的解決這個問題,它就是Swagger2。它能規範API文檔的格式,並且它能自動生成API文檔,給大家省了很多事兒!

Swagger2在日常使用中,其實是分爲兩部分的。一是Swagger2-core,它的作用是提供註解,程序員在開發過程中,對方法進行註解,該方法被標記成了API文檔中的一項,之後他就能生成API文檔的JSON字符串;二是Swagger2-UI,它的作用是解析生成的API文檔JSON字符串,並將其在頁面上進行展示。

唯一需要注意的是,Swagger2是基於OpenAPI3.0規範的,換句話說,它適用的API是RESTful風格的,舉個例子,就像現在很多公司的開放平臺,例如阿里、百度的那樣,通過Url去調用對方RESTful風格的API。大家如果覺得抽象可以去阿里雲這樣的開放平臺看看他們的API調用相關內容就瞭解了。

話不多說,我們來看看如何使用。

●引入依賴

根據剛纔說的,我們需要引入兩部分的依賴,以maven的pom文件爲例:

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.8.0</version>
</dependency>
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.8.0</version>
</dependency>

●正常開發

接下來就可以開始正常開發過程了,當然了,如果各位是在項目開發或者維護階段,中途引入pom也是可以的,直接進行配置和註解就行。這裏,我們將結合實際的開發來舉例子說明。

我們使用SpringBoot工程爲例,也順便和大家一起學習下如何快速開始一個SpringBoot項目的搭建與開發。首先,我們進入https://start.spring.io/,通過官方網站快速生成一個空的SpringBoot項目,大家如果習慣用IDEA自己新建也是OK的。注意紅框的地方,按需填寫,然後點擊Switch to the full version,選擇其他相關依賴,筆者選了Web、JPA、MySQL,後期大家也可以隨時根據項目需要的依賴直接添加到pom文件即可。最後點擊Generate Project生成項目。

使用IDEA或者大家喜歡的IDE導入剛生成的maven項目,然後開始擼代碼。假設有這麼一個簡單的業務場景:管理設備資源,可以對設備進行添加、刪除以及查詢操作。

先準備一個實體類:

@Entity
@Table(name = "device_info")
public class deviceInfo implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id", unique = true, nullable = false)
    private Long id;
    
    @Column(name = "device_name")
    private String deviceName;
    @Column(name = "device_owner")
    private String deviceOwner;

    /* 篇幅有限,省略構造函數和get、set函數 */
}

dao層接口使用Spring Data JPA來寫,不清楚的朋友可以查看之前的一篇文章

public interface DeviceInfoRepository extends JpaRepository<DeviceInfo, Long> {
    /**
     * 按歸屬者查找設備
     * @param deviceOwner
     * @return 設備列表
     */
    List<DeviceInfo> findByDeviceOwner(String deviceOwner);

    /**
     * 按名字刪除設備
     * @param deviceName
     * @return 狀態值
     */
    int deleteByDeviceName(String deviceName);

    /**
     * 修改設備名
     * @param deviceName
     * @param id
     * @return 狀態值
     */
    @Modifying
    @Query("update DeviceInfo d set d.deviceName = ?1 where d.id = ?2")
    int modifyById(String  deviceName, Long id);
}

service層包括以下幾個方法,提供設備添加、刪除、修改和查詢:

@Service
public class DeviceInfoService {
    @Autowired
    DeviceInfoRepository deviceInfoRepository;

    public void addDevice(List<DeviceInfo> deviceInfos){
        deviceInfoRepository.saveAll(deviceInfos);
    }

    public int deteleByDeviceName(String deviceName){
        return deviceInfoRepository.deleteByDeviceName(deviceName);
    }

    public int modifyDeviceNameById(String deviceName , Long id){
        return deviceInfoRepository.modifyById(deviceName,id);
    }

    public List<DeviceInfo> findByOwner(String deviceOwner){
        return deviceInfoRepository.findByDeviceOwner(deviceOwner);
    }

    public DeviceInfo findById(Long id){
        return deviceInfoRepository.findById(id).orElseGet(() -> new DeviceInfo());
    }
}

最後是controller層,也就是對外提供API的地方,值得注意的是,RESTful的接口命名要規範,不要在URL中暴露動詞:

@RestController
@RequestMapping(value="/device_info")
public class DeviceInfoController {
    @Autowired
    DeviceInfoService deviceInfoService;

    @RequestMapping(value="/{owner}", method=RequestMethod.GET)
    public List<DeviceInfo> getDeviceListByDeviceOwner(@PathVariable String owner) {
        // 處理"/device_info/"的GET請求,用來獲取設備列表
        List<DeviceInfo> r = deviceInfoService.findByOwner(owner);
        return r;
    }

    
    @RequestMapping(value="/{id}", method=RequestMethod.GET)
    public DeviceInfo getDeviceById(@PathVariable Long id) {
        // 處理"/device_info/{id}"的GET請求,用來獲取url中id值的User信息
        return deviceInfoService.findById(id);
    }

    
    @RequestMapping(value="/", method=RequestMethod.POST)
    public String addDevice(@ModelAttribute DeviceInfo deviceInfo) {
        // 處理"/device_info/"的POST請求,用來新增設備
        List<DeviceInfo> deviceInfos = new ArrayList<>();
        deviceInfos.add(deviceInfo);
        deviceInfoService.addDevice(deviceInfos);
        return "success";
    }

    
    @RequestMapping(value="/{deviceName}", method=RequestMethod.DELETE)
    public String deleteDevice(@PathVariable String deviceName) {
        // 處理"/device_info/{deviceName}"的DELETE請求,用來刪除設備
        deviceInfoService.deteleByDeviceName(deviceName);
        return "success";
    }

    
    @RequestMapping(value="/{id}", method=RequestMethod.PUT)
    public String modifyDevice(@PathVariable String deviceName,@PathVariable Long id) {
        // 處理"/device_info/{id}"的PUT請求,用來更新設備信息
        deviceInfoService.modifyDeviceNameById(deviceName,id);
        return "success";
    }
}

以上,就是常規的從domain→dao→service→controller分層的寫法,大家應該已經很熟悉了,至此我們就模擬了一個已經開發了的項目。接下來我們要做的就是對這個已經存在的項目進行一定的改造,讓Swagger2爲我們自動生成API文檔。

Swagger2配置

Swagger2的配置很簡單,我們採用java類的形式來寫。直接在項目的啓動類同級新建一個Swagger2類,如下:

@Configuration
@EnableSwagger2
public class Swagger2 {
    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.xenophon.swagger2demo.controller"))
                .paths(PathSelectors.any())
                .build();
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("Spring Boot中使用Swagger2構建RESTful APIs")
                .description("第一個Swagger2自動構建演示項目")
                .termsOfServiceUrl("https://blog.csdn.net/jui121314?t=1")
                .contact("色諾芬")
                .version("1.0")
                .build();
    }
}

需要注意RequestHandlerSelectors.basePackage()中填寫需要掃描的API所在的包名,apiInfo()中填寫相關的信息即可。

●編輯API接口

我們選擇需要加入API文檔的接口,添加上註解就OK了,是不是很簡單。我們來學習一下Swagger2提供的註解以及用法,我們將剛纔controller層中的接口全部添加到文檔中:

@RestController
@RequestMapping(value="/device_info")
@Api(tags = "設備信息相關API")
public class DeviceInfoController {
    @Autowired
    DeviceInfoService deviceInfoService;

    @ApiOperation(value="獲取歸屬者設備列表", notes="")
    @ApiImplicitParam(name = "owner", value = "設備歸屬者姓名", required = true, dataType = "String")
    @RequestMapping(value="/{owner}", method=RequestMethod.GET)
    public List<DeviceInfo> getDeviceListByDeviceOwner(@PathVariable String owner) {
        // 處理"/device_info/"的GET請求,用來獲取設備列表
        // 還可以通過@RequestParam從頁面中傳遞參數來進行查詢條件或者翻頁信息的傳遞
        List<DeviceInfo> r = deviceInfoService.findByOwner(owner);
        return r;
    }

    @ApiOperation(value="獲取設備詳細信息", notes="根據url的id來獲取設備詳細信息")
    @ApiImplicitParam(name = "id", value = "設備ID", required = true, dataType = "Long")
    @RequestMapping(value="/{id}", method=RequestMethod.GET)
    public DeviceInfo getDeviceById(@PathVariable Long id) {
        // 處理"/device_info/{id}"的GET請求,用來獲取url中id值的User信息
        // url中的id可通過@PathVariable綁定到函數的參數中
        return deviceInfoService.findById(id);
    }

    @ApiOperation(value="新增設備", notes="根據Device對象創建設備")
    @ApiImplicitParam(name = "deviceInfo", value = "設備詳細實體deviceInfo", required = true, dataType = "DeviceInfo")
    @RequestMapping(value="/", method=RequestMethod.POST)
    public String addDevice(@ModelAttribute DeviceInfo deviceInfo) {
        // 處理"/device_info/"的POST請求,用來新增設備
        // 除了@ModelAttribute綁定參數之外,還可以通過@RequestParam從頁面中傳遞參數
        List<DeviceInfo> deviceInfos = new ArrayList<>();
        deviceInfos.add(deviceInfo);
        deviceInfoService.addDevice(deviceInfos);
        return "success";
    }

    @ApiOperation(value="刪除設備", notes="根據url的設備名來指定刪除對象")
    @ApiImplicitParam(name = "deviceName", value = "設備名", required = true, dataType = "String")
    @RequestMapping(value="/{deviceName}", method=RequestMethod.DELETE)
    public String deleteDevice(@PathVariable String deviceName) {
        // 處理"/device_info/{deviceName}"的DELETE請求,用來刪除設備
        deviceInfoService.deteleByDeviceName(deviceName);
        return "success";
    }

    @ApiOperation(value="更新設備名", notes="根據url的id來指定更新對象,並根據傳過來的deviceName來更新設備名")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "deviceName", value = "設備名", required = true, dataType = "String"),
            @ApiImplicitParam(name = "id", value = "設備ID", required = true, dataType = "Long"),
    })
    @RequestMapping(value="/{id}", method=RequestMethod.PUT)
    public String modifyDevice(@PathVariable String deviceName, @PathVariable Long id) {
        // 處理"/device_info/{id}"的PUT請求,用來更新設備信息
        deviceInfoService.modifyDeviceNameById(deviceName,id);
        return "success";
    }
}

相比之前,變化僅僅在於方法之前添加的幾個註解。我們逐一解釋一下:

首先,我們在類上加了一個@Api的註解。該註解用在請求的類上,表示對類的說明。其中,常用的參數包括:tags,用來對類的作用進行說明;hidden,默認爲false, 配置爲true 將在文檔中隱藏(下面幾個註解都具備,不再一一解釋)。

其次,我們在方法上加了一個@ApiOperation的註解。該註解用在請求的方法上,說明方法的用途、作用。其中,常用的參數包括:value,說明方法的用途、作用;notes,方法的備註說明;response,響應類型。

然後,我們在方法上加了一個@ApiImplicitParam(s)的註解。如果是多個請求的情況,@ApiImplicitParams用在請求的方法上,表示一組參數說明;@ApiImplicitParam用在@ApiImplicitParams註解中,指定一個請求參數的說明。常用的參數包括:name,參數名;value,參數的說明、解釋;required,參數是否必須傳,默認爲false,進行POST等請求必須要求參數時爲true;dataType,參數類型,默認String,可以是任意Java對象,例如剛纔定義的設備實體類DeviceInfo;defaultValue,參數的默認值。

至此,程序員需要人工做的就全部完成了

●Swagger-UI查看文檔

現在,Swagger2已經幫我們生成好API文檔了,我們要做的就是啓動項目,進入http://localhost:8080/swagger-ui.html。當然,根據配置的IP、端口、路徑,這個訪問地址會有所不同,筆者僅舉例默認情況下的訪問路徑。打開後我們就可以通過網頁查看API文檔了,如圖:

每個方法都可以具體點開查看,甚至還能點擊Try it out直接調用!

至此,Swagger2就算成功使用了,大家完全可以拿出以前的項目來試試,僅僅是導入依賴,添加配置,給方法寫註解這麼簡單。

●彩蛋:swagger-ui-layer

正片結束,給大家放送一個彩蛋,第三方開源UI組件swagger-ui-layer。只需要引入一個依賴,就可以給Swagger2的UI界面換一套衣服。實際用下來,感覺還是蠻不錯的,看上去挺舒服的。也許是Swagger2當時考慮用戶會自己開發UI,所以隨意給了個將就看得過去的頁面設計。

swagger-ui-layer需要引入的依賴如下:

dependency>
    <groupId>com.github.caspar-chen</groupId>
    <artifactId>swagger-ui-layer</artifactId>
    <version>1.1.0</version>
</dependency>

打開默認的訪問鏈接http://localhost:8080/docs.html界面如下:

對的!你沒看錯,只需要引入一個依賴,更換一個訪問地址就行,其餘地方完全不用修改。頁面更舒服耐看,同樣也支持調試。唯一需要注意的是,該第三方組件截止撰文時依舊沒有支持Swagger2的分組,因此大家在配置的時候,如果有group的設置,需要去掉。

●小結

其實Swagger2的可用性還是蠻高的。例如可以自己開發SwaggerUI頁面,可以用更多的註解,可以分組,可以搭配其他框架(例如spring security)加入權限,等等,筆者只介紹了最簡單的使用方法。大家如何真的需要使用的話,可以參考官方的文檔進行。今天,你學會了嗎?

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章