簡單易懂,高效實用的介面檔案編寫技巧

2023-06-27 15:01:17

大家好!我是sum墨,一個一線的底層碼農,平時喜歡研究和思考一些技術相關的問題並整理成文,限於本人水平,如果文章和程式碼有表述不當之處,還請不吝賜教。

以下是正文!

介面檔案是什麼

介面檔案是一個軟體系統的重要組成部分,它描述了系統中所有可供外部應用程式使用的介面。簡單來說,介面檔案就是用來幫助開發者開發和對接系統的指南。

在軟體開發過程中,不同的系統之間需要進行資料互動和資訊傳遞,這就要求系統必須提供一些公開的介面。

介面檔案的展現形式也很多如:Swagger、Word、PDF、Postman、開放平臺檔案等。不同的展現形式提供了不同的載體來呈現介面檔案,但是最終的關鍵還是內容本身。

一份清晰、詳細、準確的介面檔案是開發團隊是否能夠準確理解和使用系統介面的關鍵。

總之,一份好的介面檔案應該覆蓋所有的介面使用場景,詳盡而不冗長,方便開發者快速查詢和使用。而對於不同的展現形式,開發者需要根據專案的需求和開發流程選擇最適合的展現方式,從而提高開發效率和工作質量。

Swagger介面檔案

Swagger是一套用於設計、構建、記錄和使用RESTful API的工具集,可以自動生成API檔案,並提供互動式UI,能夠大大提高開發效率和共同作業效率。它支援多種程式語言和框架,能夠生成多種展現形式,如Swagger UI、Swagger Editor和Swagger Codegen等工具。同時,Swagger還提供強大的API管理功能,包括API監控、偵錯、測試和安全性等,能夠幫助開發者更好地管理和維護API。

展示一下

存取方式一

存取地址:http://localhost:8080/swagger-ui.html#/

首頁

詳情頁

存取方式二

存取地址:http://localhost:8080/doc.html

首頁

側邊欄

詳情頁

SpringBoot整合Swagger2

1、組態檔

SpringBoot專案pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>springboot-swagger</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springboot-swagger</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- swagger -->
        <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.7.0</version>
        </dependency>
        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>swagger-bootstrap-ui</artifactId>
            <version>1.9.2</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

這裡需要注意一個版本對應的問題,如果使用了高版本的SpringBoot框架,低版本的Swagger,
會出現如下報錯:

org.springframework.context.ApplicationContextException: Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.NullPointerException
	at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:181)
	at org.springframework.context.support.DefaultLifecycleProcessor.access$200(DefaultLifecycleProcessor.java:54)
	at org.springframework.context.support.DefaultLifecycleProcessor$LifecycleGroup.start(DefaultLifecycleProcessor.java:356)
	at java.lang.Iterable.forEach(Iterable.java:75)
	at org.springframework.context.support.DefaultLifecycleProcessor.startBeans(DefaultLifecycleProcessor.java:155)
	at org.springframework.context.support.DefaultLifecycleProcessor.onRefresh(DefaultLifecycleProcessor.java:123)
	at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:935)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:586)
	at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:145)
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:740)
	at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:415)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:303)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1312)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1301)

這是因為:因為Springfox 使用的路徑匹配是基於AntPathMatcher的,而Spring Boot 2.6.X使用的是PathPatternMatcher。

以下幾個版本是相容的

SpringBoot版本 Swagger版本
2.5.6 2.9.2
SpringBoot版本 Swagger版本
2.6.5 3.0.0

2、專案程式碼

專案結構

SwaggerConfig.java

package com.example.springbootswagger.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;

@Configuration
public class SwaggerConfig {

    @Bean
    public Docket createDocket() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .enable(true)
                .groupName("我的介面檔案")
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.example.springbootswagger.controller"))
                .paths(PathSelectors.any())
                .build();
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                //標題
                .title("鳳求凰")
                //作者、連結、郵箱等
                .contact(new Contact(
                        "司馬相如",
                        "https://hanyu.baidu.com/shici/detail?pid=ecb82707a98c418995c5a0c50b770af0&from=kg0",
                        ""
                ))
                //描述
                .description("有一美人兮,見之不忘。\n" +
                        "一日不見兮,思之如狂。\n" +
                        "鳳飛翱翔兮,四海求凰。\n" +
                        "無奈佳人兮,不在東牆。\n" +
                        "將琴代語兮,聊寫衷腸。\n" +
                        "何日見許兮,慰我彷徨。\n" +
                        "願言配德兮,攜手相將。\n" +
                        "不得於飛兮,使我淪亡。\n" +
                        "鳳兮鳳兮歸故鄉,遨遊四海求其凰。\n" +
                        "時未遇兮無所將,何悟今兮升斯堂!\n" +
                        "有豔淑女在閨房,室邇人遐毒我腸。\n" +
                        "何緣交頸為鴛鴦,胡頡頏兮共翱翔!\n" +
                        "凰兮凰兮從我棲,得託孳尾永為妃。\n" +
                        "交情通意心和諧,中夜相從知者誰?\n" +
                        "雙翼俱起翻高飛,無感我思使餘悲。")
                //更新說明
                .termsOfServiceUrl("這是第一版")
                //版本號
                .version("1.0.0").build();
    }
}

TestController.java

package com.example.springbootswagger.controller;

import com.example.springbootswagger.req.AddReq;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;

@RestController
@Api(tags = {"測試介面類"}, hidden = true)
@RequestMapping("/test")
public class TestController {

    @ApiOperation("GET請求,查詢方法")
    @GetMapping("/query")
    public String query() {
        return "查詢成功";
    }

    @ApiImplicitParams({
            @ApiImplicitParam(name = "param1", value = "引數1", required = true),
            @ApiImplicitParam(name = "param2", value = "引數2", required = false)
    })
    @ApiOperation("PUT請求,新增方法")
    @PutMapping("/update")
    public String update(
            @RequestParam(required = true) String param1,
            @RequestParam(required = false) String param2) {
        return "更新成功";
    }

    @ApiOperation("POST請求,修改方法")
    @PostMapping("/add")
    public String add(@RequestBody AddReq addReq) {
        return "新增成功";
    }

    @ApiImplicitParam(name = "id", value = "使用者ID", required = true)
    @ApiOperation("DELETE請求,刪除方法")
    @DeleteMapping("/del")
    public String del(Long id) {
        return "刪除成功";
    }
}

AddReq.java

package com.example.springbootswagger.req;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;

@ApiModel("新增引數")
public class AddReq {

    @ApiModelProperty("名字")
    private String name;

    @ApiModelProperty("密碼")
    private String password;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

SpringbootSwaggerApplication.java

package com.example.springbootswagger;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@EnableSwagger2
@SpringBootApplication
public class SpringbootSwaggerApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootSwaggerApplication.class, args);
    }

}

Word、PDF等檔案類介面檔案

為什麼還需要檔案類介面檔案呢?首先,Swagger檔案存在相容性問題,有些系統不支援,這時候檔案類介面檔案就能派上用場。其次,Swagger檔案不能離線使用,如果網路不穩定或者沒有網路連線,就無法檢視介面檔案,而檔案類介面檔案可以在任何時候離線瀏覽。

之前我有寫過一篇關於系統間互動的文章:多方合作時,系統間的互動是怎麼做的?,系統間的介面互動一般提供的都是檔案類檔案,像Word、PDF這種。

在實際開發中,我發現不同的開發團隊提供的介面檔案格式存在很大的差異。有些團隊提供的檔案非常詳細,甚至會給出呼叫範例程式碼,而有些團隊則只提供了非常簡單的介面說明,甚至連引數說明都沒有。這種情況下,如果介面檔案很詳細,我可以很快地進行偵錯和聯調,但是如果檔案不夠詳細,很容易遇到各種坑(一言難盡的坑),必須要去找對方的開發。

我覺得一份好的介面檔案應該包括以下內容:

  • 介面概述:包括介面的名稱、描述、版本號等資訊,讓開發者瞭解介面的基本資訊。

  • 介面引數:包括請求引數和返回引數,需要詳細說明每個引數的名稱、型別、描述、預設值、是否必須等資訊,讓開發者清晰地知道每個引數的含義和使用方法。

  • 介面使用範例:提供一個或多個請求和相應的範例,讓開發者更好地理解介面的使用方法和返回結果。

  • 介面錯誤碼:列出所有可能出現的錯誤碼和相應的錯誤資訊,讓開發者瞭解如何識別和處理介面返回的錯誤。

  • 介面限制和安全性:包括介面的存取限制、頻次限制、安全性等資訊,讓開發者知道如何正確地使用介面。

以下是我認為樣式較為簡潔和清晰的 Word 模板介面檔案範例(最下方是模板下載連結):

模板下載連結