1. 程式人生 > >微服務之Swagger

微服務之Swagger

boot 輸入格式 round ner rst 新的 attr 簡單的 media

Swagger使用

1. Swagger UI

按以下步驟配置,項目啟動後訪問:
http://localhost:8080/swagger-ui.html

1.1 添加依賴

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

1.2 配置類

@Configuration  
@EnableSwagger2  
public class Swagger2 {

    public static final String SWAGGER_SCAN_BASE_PACKAGE = "abc.boot.examples.web";
    public static final String VERSION = "1.0.0";

    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage(SWAGGER_SCAN_BASE_PACKAGE))//api接口包掃描路徑
                .paths(PathSelectors.any())//可以根據url路徑設置哪些請求加入文檔,忽略哪些請求
                .build();
    }
    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
            .title("Swagger2 接口文檔示例")//設置文檔的標題
            .description("更多內容請關註:http://www.abc.com")//設置文檔的描述->1.Overview
            .version(VERSION)//設置文檔的版本信息-> 1.1 Version information
            .contact(new Contact("ABC Boot", "http://www.abc.comt", ""))//設置文檔的聯系方式->1.2 Contact information
            .termsOfServiceUrl("www.abc.com")//設置文檔的License信息->1.3 License information
            .build();
    }
}

1.3 註解使用

@ApiOperation

@ApiOperation(value="獲取用戶列表", notes="獲取所有用戶列表",produces = "application/json")  
@RequestMapping(value="/users", method= RequestMethod.GET)
public List<User> getUserList() {  
List<User> r = new ArrayList<User>(users.values());
    return r;
}

@ApiResponses

@ApiOperation(value="獲取用戶詳細信息", notes="根據url的id來獲取用戶詳細信息",produces = "application/json")
// ApiResponses 增加返回結果的描述
@ApiResponses(value = {@ApiResponse(code = 405,message = "Invalid input",response = Integer.class)}) (1)
@ApiImplicitParam(name = "id",value = "用戶ID",dataType = "int",paramType = "path")  (2)
@RequestMapping(value="/users/{id}", method= RequestMethod.GET)
public User getUser(@PathVariable Integer id) {
    return users.get(id);
}

(1) 在默認Response的基礎上增加新的Response說明
(2) 使用ApiImplicitParam描述接口參數

@ApiImplicitParams

@ApiOperation(value="更新用戶名稱", notes="更新指定用戶的名稱")
@RequestMapping(value="/users/{id}", method= RequestMethod.POST)
@ApiImplicitParams({  (1)
        @ApiImplicitParam(name = "id",value = "用戶ID",paramType = "path",dataType = "int"),  (2)
        @ApiImplicitParam(name = "userName",value = "用戶名稱",paramType = "form",dataType = "string")
})
public void updateUserName(@PathVariable Integer id,@RequestParam String userName){
    User u = users.get(id);
    u.setName(userName);
}

(1) 使用ApiImplicitParams描述多個參數
(2) 使用ApiImplicitParam時,需要指定paramType,這樣也便於swagger ui 生成參數的輸入格式。

paramType 有五個可選值 : path, query, body, header, form

@ApiParam

@ApiOperation(value="創建用戶-傳遞簡單對象", notes="傳遞簡單對象",produces = "application/json")
@RequestMapping(value="/users-1", method= RequestMethod.POST)
//可以不加ApiParam註解,需要給參數添加描述時可以使用這個註解,或者使用ApiImplicitParams註解 (1)
public Map postUser(@RequestParam  String userName,@ApiParam("地址") @RequestParam(required = false) String address) { 
    User user = new User();
    user.setId(Math.round(10));
    user.setName(userName);
    user.setAddress(address);
    users.put(user.getId(), user);
    return ImmutableMap.of("user",user);
}

(1) 使用ApiParam描述接口參數

ApiImplicitParam 與 ApiParam 的區別
ApiImplicitParam: This is the only way to define parameters when using Servlets or other non-JAX-RS environments.

  • 對Servlets或者非 JAX-RS的環境,只能使用 ApiImplicitParam。
  • 在使用上,ApiImplicitParam比ApiParam具有更少的代碼侵入性,只要寫在方法上就可以了,但是需要提供具體的屬性才能配合swagger ui解析使用。
  • ApiParam只需要較少的屬性,與swagger ui配合更好。

傳遞復雜對象 By ModelAttribute

@ApiOperation(value="創建用戶-傳遞復雜對象", notes="傳遞復雜對象DTO, url參數拼接",produces = "application/json")
@RequestMapping(value="/users-2", method= RequestMethod.POST)
//傳遞對象推薦使用ModelAttribute註解
public Map postUser2(@ModelAttribute User user) {  (1)
    users.put(user.getId(),user);
    return ImmutableMap.of("user",user);
}

(1) ModelAttribute 是Spring mvc的註解,這裏Swagger可以解析這個註解,獲得User的屬性描述

@ApiModel

@ApiModel(value = "User", description = "用戶對象")
public class User {

    @ApiModelProperty(value = "ID")
    private Integer id;
    @ApiModelProperty(value = "姓名")
    private String name;
    @ApiModelProperty(value = "地址")
    private String address;
    @ApiModelProperty(value = "年齡",access = "hidden")
    private int age;
    @ApiModelProperty(value = "性別")
    private int sex;
    .......
}

傳遞復雜對象 By RequestBody

@ApiOperation(value="創建用戶-傳遞復雜對象", notes="傳遞復雜對象DTO,json格式傳遞數據",produces = "application/json")
@RequestMapping(value="/users-3", method= RequestMethod.POST)
//json格式傳遞對象使用RequestBody註解
public User postUser3(@RequestBody User user) {
    users.put(user.getId(),user);
    return user;
}

PathVariable

@ApiOperation(value="刪除用戶- PathVariable", notes="根據url的id來指定刪除對象")
@RequestMapping(value="/users/{id}", method = RequestMethod.DELETE)
public void deleteUser(@PathVariable Integer id) {  (1)
    users.remove(id);
}

(1) PathVariable是Spring 的註解,對於這種簡單的參數,就可以不用寫ApiParam來描述接口參數。

數組的描述

@ApiOperation(value="刪除用戶-傳遞數組", notes="刪除對象,傳遞數組")
@RequestMapping(value="/users/deleteByIds", method = RequestMethod.DELETE)
public void deleteUser(@ApiParam("用戶ID數組") @RequestParam Integer[] ids) {  (1)
    for (int id:ids){
        users.remove(id);
    }
}

(1) 這裏用ApiParam為數組參數添加描述

1.4 可選配置

在application.properties中加入以下配置,用於設置測試請求的host,默認在swagger ui上做請求測試時都是以/users/1為路徑發送請求。
如果需要改變請求的根路徑,就需要配置這個參數:
springfox.documentation.swagger.v2.host = yourapp.abc.com

配置獲取api docs json數據的請求路徑 ,默認為/v2/api-docs:
springfox.documentation.swagger.v2.path = /api

2. springfox-staticdocs 生成靜態文檔

技術分享圖片
springfox

2.1 Maven 配置

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-staticdocs</artifactId>
    <version>2.2.2</version>
    <scope>test</scope>
</dependency>

2.2 生成json文件

編寫Junit測試,這樣在測試環節就可以將api-docs的json數據寫入文檔,便於下一步生成asciidoc文件。

@WebAppConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = DemoBootApplication.class)
public class Swagger2MarkupTest {

    @Autowired
    private WebApplicationContext context;

    private MockMvc mockMvc;

    @Before
    public void setUp() {
        this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context).build();
    }

    @Test
    public void createSpringfoxSwaggerJson() throws Exception {
        String outputDir = "src/docs/json";  //將api-docs的json數據寫入文件
        MvcResult mvcResult = this.mockMvc.perform(get("/v2/api-docs")
                .accept(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk())
                .andReturn();

        MockHttpServletResponse response = mvcResult.getResponse();
        String swaggerJson = response.getContentAsString();
        Files.createDirectories(Paths.get(outputDir));
        try (BufferedWriter writer = Files.newBufferedWriter(Paths.get(outputDir, "swagger.json"), StandardCharsets.UTF_8)) {
            writer.write(swaggerJson);
        }
    }
}

2.3 配置Maven Plugin

配置以下兩個插件:
swagger2markup-maven-plugin,該插件將json文件轉為asciidoc
asciidoctor-maven-plugin, 該插件將asciidoc轉為html/pdf

執行Maven命令 : mvn swagger2markup:convertSwagger2markup process-resources

生成的html文檔存儲在src\main\resources\META-INF\resources\docs目錄下。
啟動DemoBootApplication,直接訪問http://localhost:8080/docs/index.html。

<pluginRepositories>
    <pluginRepository>
        <id>jcenter-snapshots</id>
        <name>jcenter</name>
        <url>http://oss.jfrog.org/artifactory/oss-snapshot-local/</url>
    </pluginRepository>
    <pluginRepository>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
        <id>jcenter-releases</id>
        <name>jcenter</name>
        <url>http://jcenter.bintray.com</url>
    </pluginRepository>
</pluginRepositories>

<build>
    <plugins>
        <!-- First, use the swagger2markup plugin to generate asciidoc -->
        <plugin>
            <groupId>io.github.swagger2markup</groupId>
            <artifactId>swagger2markup-maven-plugin</artifactId>
            <version>${swagger2markup.plugin.version}</version>
            <dependencies>
                <dependency>
                    <groupId>io.github.swagger2markup</groupId>
                    <artifactId>swagger2markup-import-files-ext</artifactId>
                    <version>${swagger2markup.extension.version}</version>
                </dependency>
                <dependency>
                    <groupId>io.github.swagger2markup</groupId>
                    <artifactId>swagger2markup</artifactId>
                    <version>${swagger2markup.version}</version>
                </dependency>
            </dependencies>
            <configuration>
                <!--The URL or file path to the Swagger specification-->
                <swaggerInput>${swagger.input}</swaggerInput>
                <outputDir>${generated.asciidoc.directory}</outputDir>
                <config>
                    <!--設置輸出文件的語言:ASCIIDOC, MARKDOWN, CONFLUENCE_MARKUP-->
                    <swagger2markup.markupLanguage>ASCIIDOC</swagger2markup.markupLanguage>
                    <!--設置目錄的展現方式-->
                    <swagger2markup.pathsGroupedBy>TAGS</swagger2markup.pathsGroupedBy>
                    <!--擴展Overview的內容,可以增加一些自定義的內容-->
                    <!--<swagger2markup.extensions.dynamicOverview.contentPath>${project.basedir}/src/docs/asciidoc/extensions/overview</swagger2markup.extensions.dynamicOverview.contentPath>
                    <swagger2markup.extensions.dynamicDefinitions.contentPath>${project.basedir}/src/docs/asciidoc/extensions/definitions</swagger2markup.extensions.dynamicDefinitions.contentPath>
                    <swagger2markup.extensions.dynamicPaths.contentPath>${project.basedir}/src/docs/asciidoc/extensions/paths</swagger2markup.extensions.dynamicPaths.contentPath>
                    <swagger2markup.extensions.dynamicSecurity.contentPath>${project.basedir}src/docs/asciidoc/extensions/security</swagger2markup.extensions.dynamicSecurity.contentPath>-->
                </config>
            </configuration>
            <executions>
                <execution>
                    <phase>generate-sources</phase>
                    <goals>
                        <goal>convertSwagger2markup</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>



        <!-- Run the generated asciidoc through Asciidoctor to generate
             other documentation types, such as PDFs or HTML5 -->
        <plugin>
            <groupId>org.asciidoctor</groupId>
            <artifactId>asciidoctor-maven-plugin</artifactId>
            <version>1.5.3</version>
            <!-- Include Asciidoctor PDF for pdf generation -->
            <dependencies>
                <dependency>
                    <groupId>org.asciidoctor</groupId>
                    <artifactId>asciidoctorj-pdf</artifactId>
                    <version>1.5.0-alpha.11</version>
                </dependency>
                <!-- Comment this section to use the default jruby artifact provided by the plugin -->
                <dependency>
                    <groupId>org.jruby</groupId>
                    <artifactId>jruby-complete</artifactId>
                    <version>${jruby.version}</version>
                </dependency>
                <!-- Comment this section to use the default AsciidoctorJ artifact provided by the plugin -->
                <dependency>
                    <groupId>org.asciidoctor</groupId>
                    <artifactId>asciidoctorj</artifactId>
                    <version>${asciidoctorj.version}</version>
                </dependency>
            </dependencies>
            <!-- Configure generic document generation settings -->
            <configuration>
                <!--默認指向 ${basedir}/src/main/asciidoc-->
                <sourceDirectory>${asciidoctor.input.directory}</sourceDirectory>
                <!--an override to process a single source file; 默認指向 ${sourceDirectory} 中的所有文件-->
                <!--<sourceDocumentName>index.adoc</sourceDocumentName>-->
                <attributes>
                    <doctype>book</doctype>
                    <toc>left</toc>
                    <toclevels>3</toclevels>
                    <numbered></numbered>
                    <hardbreaks></hardbreaks>
                    <sectlinks></sectlinks>
                    <sectanchors></sectanchors>
                    <generated>${generated.asciidoc.directory}</generated>
                </attributes>
            </configuration>
            <!-- Since each execution can only handle one backend, run
                 separate executions for each desired output type -->
            <executions>
                <execution>
                    <id>output-html</id>
                    <phase>generate-resources</phase>
                    <goals>
                        <goal>process-asciidoc</goal>
                    </goals>
                    <configuration>
                        <backend>html5</backend>
                        <outputDirectory>${asciidoctor.html.output.directory}</outputDirectory>
                    </configuration>
                </execution>


                <!-- 生成PDF -->
                <!--<execution>
                    <id>output-pdf</id>
                    <phase>generate-resources</phase>
                    <goals>
                        <goal>process-asciidoc</goal>
                    </goals>
                    <configuration>
                        <backend>pdf</backend>
                        <outputDirectory>${asciidoctor.pdf.output.directory}</outputDirectory>
                    </configuration>
                </execution>-->

            </executions>
        </plugin>
    </plugins>
</build>

3. 其他說明

3.1 如何修改/v2/api-docs路徑?

swagger-ui是通過獲取接口的json數據渲染頁面的,即通過swagger的註解將生成接口的描述服務,默認地址為/v2/api-docs,如果需要改變這個請求地址,可以在properties中配置springfox.documentation.swagger.v2.path。

3.2 如何設置所有請求的統一前綴?

默認請求都是以 / 根路徑開始,如果我們的應用不是部署在根路徑,比如以/platform部署,則可以通過一下方式設置請求的統一前綴。

@Bean
public Docket createV1RestApi() {
    return new Docket(DocumentationType.SWAGGER_2)
            .apiInfo(apiInfo())
            .select()
            .apis(RequestHandlerSelectors.basePackage(SWAGGER_SCAN_BASE_PACKAGE))
            .paths(PathSelectors.any()) 
            .build()
            .pathMapping("/platform"); // 在這裏可以設置請求的統一前綴
}

3.3 接口文檔中1.4和1.5的信息生成

接口文檔中的 1.4和 1.5 則通過以下方式生成:
1.4 URI scheme
// 可以通過在properties中設置 springfox.documentation.swagger.v2.host屬性
Host : localhost

// 待確認
BasePath : /

該Host也是swagger-ui發送測試請求的Host, 通常我們會將將接口文檔部署在測試服務器,這樣就需要設置Host,
否則請求都是通過localhost發送,請求不到測試服務器的接口。

1.5 Tags
@Api(value = "/v1/users",tags = "Users",description = "用戶接口V1")
tags由Api註解的tags標簽設置,如果不設置,則以類名作為tag

3.4 設置響應對象的Example

通過ApiModelProperty註解的example屬性設置響應對象的示例:

@ApiModelProperty(value = "ID",example = "1")
private Integer id;
@ApiModelProperty(value = "姓名",example = "Admin")
private String name;
@ApiModelProperty(value = "地址",example = "171")
private String address;
@ApiModelProperty(value = "年齡",access = "hidden",example = "20")
private int age;
@ApiModelProperty(value = "性別",example = "1")
private int sex;
@ApiModelProperty(value = "生日",example = "2000-10-22")

鏈接

springfox文檔

http://www.jianshu.com/p/b730b969b6a2

微服務之Swagger