SpringBoot(十八):SpringBoot2.1.1引入SwaggerUI工具

Swagger是一個有用web界面的提供實體模型結構展現,接口展現,調測等的一個工具,使用它能夠提升開發者開發效率,特別是先後端配合開發時,大大省去了溝通接口耗費的時間:服務端開發完接口發佈後,UI端直接就能夠經過Swagger提供的文檔信息就能很容易理解哪些接口須要傳遞哪些參數,以及參數是否必填,參數類型等。html

上邊只是提到了我的使用過程當中,感覺到的優點,就這些優點足夠吸引開發者使用該工具,使用Swagger須要完整一下幾步操做:java

1)新建SpringBoot工程,並還引入swagger ui依賴包;git

2)在SpringBoot中添加Swagger配置類,啓用swagger,並設置配置項;github

3)定義實體類,實體類加上文檔註解;web

4)定義Restful Api接口,並添加文檔註解;spring

5)發佈訪問。數據庫

下邊針對上邊的步驟進行詳細介紹:apache

1)新建SpringBoot工程,並還引入swagger ui依賴包;

修改maven工程後,引入springboot parent,引入swagger ui相關依賴包。修改後的pom.xml以下:json

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.dx.sort</groupId>
    <artifactId>springboot-with-fastjson</artifactId>
    <version>1.0-SNAPSHOT</version>

    <name>springboot-with-fastjson</name>
    <!-- FIXME change it to the project's website -->
    <url>http://www.example.com</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <dependencies>
        <!-- springboot web組件依賴 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- fastjson -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.56</version>
        </dependency>

        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.9.2</version>
        </dependency>
        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>swagger-bootstrap-ui</artifactId>
            <version>1.9.6</version>
        </dependency>
        <dependency>
            <groupId>io.swagger</groupId>
            <artifactId>swagger-models</artifactId>
            <version>1.5.24</version>
        </dependency>
        <dependency>
            <groupId>io.swagger</groupId>
            <artifactId>swagger-annotations</artifactId>
            <version>1.5.24</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
            <plugins>
                <!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
                <plugin>
                    <artifactId>maven-clean-plugin</artifactId>
                    <version>3.1.0</version>
                </plugin>
                <!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
                <plugin>
                    <artifactId>maven-resources-plugin</artifactId>
                    <version>3.0.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.8.0</version>
                </plugin>
                <plugin>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <version>2.22.1</version>
                </plugin>
                <plugin>
                    <artifactId>maven-jar-plugin</artifactId>
                    <version>3.0.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-install-plugin</artifactId>
                    <version>2.5.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-deploy-plugin</artifactId>
                    <version>2.8.2</version>
                </plugin>
                <!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
                <plugin>
                    <artifactId>maven-site-plugin</artifactId>
                    <version>3.7.1</version>
                </plugin>
                <plugin>
                    <artifactId>maven-project-info-reports-plugin</artifactId>
                    <version>3.0.0</version>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</project>
View Code

修改springboot入口函數:bootstrap

package com.dx.test.app;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * Hello world!
 */
@SpringBootApplication(scanBasePackages = {"com.dx.test"})
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }
}

在src/main下添加resources資源文件夾,在resources文件夾下添加application.yml文件,文件內容爲:

server:
  port: 8080

配置服務器運行端口爲8080。

2)在SpringBoot中添加Swagger配置類,啓用swagger,並設置配置項;

在項目中新建Swagger2Configuration類,並修改該類爲以下:

package com.dx.test.web.config;

import com.github.xiaoymin.swaggerbootstrapui.annotations.EnableSwaggerBootstrapUI;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
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;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Configuration
@EnableSwagger2
@EnableSwaggerBootstrapUI
public class Swagger2Configuration implements WebMvcConfigurer {
    @Bean
    public Docket createDocApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .groupName("default") // 默認就是 default
                .apiInfo(createApiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.dx.test"))
                .paths(PathSelectors.any())
                .build();
    }

    private ApiInfo createApiInfo(){
        return new ApiInfoBuilder()
                .title("Dx系統Restful Apis")
                .description("Dx系統Restful Apis詳細說明")
                .license("")
                .licenseUrl("")
                .termsOfServiceUrl("")
                .contact(new Contact("dx","http://xxx.com","dx@xx.com.cn"))
                .version("1.0.0")
                .build();
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/**")
                .addResourceLocations("classpath:/static/");
        registry.addResourceHandler("swagger-ui.html")
                .addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**")
                .addResourceLocations("classpath:/META-INF/resources/webjars/");
        registry.addResourceHandler("doc.html")
                .addResourceLocations("classpath:/META-INF/resources/");
    }
}

3)定義實體類,實體類加上文檔註解;

添加文章實體Article類,並對文章實體屬性添加swagger文檔註解,以及對字段顯示順序進行排序。

package com.dx.test.module;

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

import java.io.Serializable;
import java.util.Date;

@ApiModel(value = "文章實體")
public class Article implements Serializable {
    @ApiModelProperty(value = "文章id", position = 0)
    private Long id;
    @ApiModelProperty(value = "標題", position = 1)
    private String title;
    @ApiModelProperty(value = "做者", position = 2)
    private String author;
    @ApiModelProperty(value = "內容", position = 3)
    private String content;
    @ApiModelProperty(value = "建立人", position = 4)
    private String createUser;
    @ApiModelProperty(value = "建立人id", position = 5)
    private String createUserId;
    @ApiModelProperty(value = "建立時間", position = 6)
    private Date createTime;
    @ApiModelProperty(value = "修改人", position = 7)
    private String modifyUser;
    @ApiModelProperty(value = "修改人id", position = 8)
    private String modifyUserId;
    @ApiModelProperty(value = "修改時間", position = 9)
    private Date modifyTime;

    public Article(Long id, String title, String author, String content, Date createTime) {
        this.id = id;
        this.title = title;
        this.author = author;
        this.content = content;
        this.createTime = createTime;
    }

    /**
     * @return the id
     */
    public Long getId() {
        return id;
    }

    /**
     * @param id the id to set
     */
    public void setId(Long id) {
        this.id = id;
    }

    /**
     * @return the title
     */
    public String getTitle() {
        return title;
    }

    /**
     * @param title the title to set
     */
    public void setTitle(String title) {
        this.title = title;
    }

    /**
     * @return the author
     */
    public String getAuthor() {
        return author;
    }

    /**
     * @param author the author to set
     */
    public void setAuthor(String author) {
        this.author = author;
    }

    /**
     * @return the content
     */
    public String getContent() {
        return content;
    }

    /**
     * @param content the content to set
     */
    public void setContent(String content) {
        this.content = content;
    }

    /**
     * @return the createTime
     */
    public Date getCreateTime() {
        return createTime;
    }

    /**
     * @param createTime the createTime to set
     */
    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

    /**
     * @return the modifyTime
     */
    public Date getModifyTime() {
        return modifyTime;
    }

    /**
     * @param modifyTime the modifyTime to set
     */
    public void setModifyTime(Date modifyTime) {
        this.modifyTime = modifyTime;
    }

    /**
     * @return the createUser
     */
    public String getCreateUser() {
        return createUser;
    }

    /**
     * @param createUser the createUser to set
     */
    public void setCreateUser(String createUser) {
        this.createUser = createUser;
    }

    /**
     * @return the createUserId
     */
    public String getCreateUserId() {
        return createUserId;
    }

    /**
     * @param createUserId the createUserId to set
     */
    public void setCreateUserId(String createUserId) {
        this.createUserId = createUserId;
    }

    /**
     * @return the modifyUser
     */
    public String getModifyUser() {
        return modifyUser;
    }

    /**
     * @param modifyUser the modifyUser to set
     */
    public void setModifyUser(String modifyUser) {
        this.modifyUser = modifyUser;
    }

    /**
     * @return the modifyUserId
     */
    public String getModifyUserId() {
        return modifyUserId;
    }

    /**
     * @param modifyUserId the modifyUserId to set
     */
    public void setModifyUserId(String modifyUserId) {
        this.modifyUserId = modifyUserId;
    }
}

其中字段屬性註解@ApiModelProperty的value值就是文檔顯示該字段的意義,position是該文檔屬性顯示順序。

爲了能正常訪問接口,對接口中date類型參數、@RequestHeader的header參數中文進行解碼、對返回接口數據爲json數據(採用fastjson)須要添加WebMvcConfig配置類:

package com.dx.test.web.config;

import com.dx.test.web.converter.HandlerHeaderMethodArgumentResolver;
import com.dx.test.web.converter.RequestHeaderDecodeConverter;
import com.dx.test.web.converter.StringToDateConverter;
import com.dx.test.web.converter.StringToEnumConverterFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
import org.springframework.context.annotation.*;
import org.springframework.http.converter.AbstractHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.stereotype.Controller;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import org.springframework.http.MediaType;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;

/**
 * WebMvcConfigurerAdapter 這個類在SpringBoot2.0已過期,官方推薦直接實現 WebMvcConfigurer 這個接口
 */
@Configuration
@Import({WebMvcAutoConfiguration.class})
@ComponentScan(
        value = "com.dx.test.web",
        includeFilters = {
                @ComponentScan.Filter(type = FilterType.ANNOTATION, value = Controller.class)
        })
public class WebMvcConfig implements WebMvcConfigurer {
    @Bean
    public RequestHeaderDecodeConverter requestHeaderDecodeConverter() {
        return new RequestHeaderDecodeConverter(null);
    }

    @Bean
    public StringToDateConverter stringToDateConverter() {
        return new StringToDateConverter();
    }

    /**
     * 使用 fastjson 代替 jackson
     *
     * @param converters
     */
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        /*
         先把JackSon的消息轉換器刪除.
         備註:(1)源碼分析可知,返回json的過程爲:
                 Controller調用結束後返回一個數據對象,for循環遍歷conventers,找到支持application/json的HttpMessageConverter,而後將返回的數據序列化成json。
                 具體參考org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor的writeWithMessageConverters方法
             (2)因爲是list結構,咱們添加的fastjson在最後。所以必需要將jackson的轉換器刪除,否則會先匹配上jackson,致使沒使用 fastjson
        */
//        for (int i = converters.size() - 1; i >= 0; i--) {
//            if (converters.get(i) instanceof MappingJackson2HttpMessageConverter) {
//                converters.remove(i);
//            }
//        }
//
//        FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter();
//        //自定義fastjson配置
//        FastJsonConfig config = new FastJsonConfig();
//        config.setSerializerFeatures(
//                SerializerFeature.WriteMapNullValue,        // 是否輸出值爲null的字段,默認爲false,咱們將它打開
//                SerializerFeature.WriteNullListAsEmpty,     // 將Collection類型字段的字段空值輸出爲[]
//                SerializerFeature.WriteNullStringAsEmpty,   // 將字符串類型字段的空值輸出爲空字符串
//                SerializerFeature.WriteNullNumberAsZero,    // 將數值類型字段的空值輸出爲0
//                SerializerFeature.WriteDateUseDateFormat,
//                SerializerFeature.DisableCircularReferenceDetect    // 禁用循環引用
//        );
//        fastJsonHttpMessageConverter.setFastJsonConfig(config);
//
//        // 添加支持的MediaTypes;不添加時默認爲*/*,也就是默認支持所有
//        // 可是MappingJackson2HttpMessageConverter裏面支持的MediaTypes爲application/json
//        // 參考它的作法, fastjson也只添加application/json的MediaType
//        List<MediaType> fastMediaTypes = new ArrayList<>();
//        fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
//        fastJsonHttpMessageConverter.setSupportedMediaTypes(fastMediaTypes);
//        converters.add(fastJsonHttpMessageConverter);
    }

    /**
     * +支持fastjson的HttpMessageConverter
     *
     * @return HttpMessageConverters
     */
    @Bean
    public HttpMessageConverters fastJsonHttpMessageConverters() {
        AbstractHttpMessageConverter abstractHttpMessageConverter = null;
        //1.須要定義一個convert轉換消息的對象;
        FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter();

        //2:添加fastJson的配置信息;
        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        fastJsonConfig.setSerializerFeatures(
                SerializerFeature.WriteMapNullValue,
                SerializerFeature.WriteDateUseDateFormat,
                SerializerFeature.DisableCircularReferenceDetect);
        fastJsonConfig.setCharset(Charset.forName("utf-8"));

        //3處理中文亂碼問題
        List<MediaType> fastMediaTypes = new ArrayList<>();
        fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);

        //4.在convert中添加配置信息.
        fastJsonHttpMessageConverter.setSupportedMediaTypes(fastMediaTypes);
        fastJsonHttpMessageConverter.setFastJsonConfig(fastJsonConfig);

        HttpMessageConverter<?> converter = fastJsonHttpMessageConverter;

        return new HttpMessageConverters(converter);
    }

}
View Code

WebMvcConfig中的StringToDateConverter(對date參數類型轉化)在上篇文章中有它的源碼;RequestHeaderDecodeConverter是實現對header中中文進行解碼使用,在上篇文章中也有其源碼。

4)定義Restful Api接口,並添加文檔註解;

添加ArticleController類,並在接口上添加文檔註解:

package com.dx.test.web.controller;

import com.dx.test.module.Article;
import com.dx.test.module.ArticleType;
import com.dx.test.web.annonations.HeaderTestArgument;
import io.swagger.annotations.*;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Api(value = "文章管理", tags = {"文章管理:增、刪、改、查"})
@ApiSort(value = 1)
@RestController
@RequestMapping(value = "/api/v1")
public class ArticleController {
    @ApiOperation(value = "根據文章id,查詢文章詳情", code = 200, httpMethod = "GET", produces = "application/json", notes = "queryById方法定義說明:根據數據庫中article表的自增id,查詢article信息。")
    @ApiImplicitParams(value = {
            @ApiImplicitParam(name = "userId", paramType = "header", value = "操做用戶id", required = false, dataType = "String"),
            @ApiImplicitParam(name = "userName", paramType = "header", value = "操做用戶", required = false, dataType = "String"),
            @ApiImplicitParam(name = "id", paramType = "path", value = "文章id", required = true, dataType = "Long")
    })
    @RequestMapping(value = {"/article/{id}"}, method = {RequestMethod.GET}, produces = {MediaType.APPLICATION_JSON_VALUE})
    @ResponseBody
    public Article getById(
            @RequestHeader(value = "userId", required = false) String userId,
            @RequestHeader(value = "userName", required = false) String userName,
            @PathVariable(value = "id", required = true) Long id,
            Article article) {
        List<Article> articles = new ArrayList<>();
        articles.add(new Article(1L, "文章1", "", "", new Date()));
        articles.add(new Article(2L, "文章2", "", "", new Date()));
        articles.add(new Article(3L, "文章3", "", "", new Date()));
        articles.add(new Article(4L, "文章4", "", "", new Date()));
        System.out.println(userName);
        return articles.get(0);
    }

    @ApiOperation(value = "查詢文章列表", code = 200, httpMethod = "GET", produces = "application/json", notes = "queryById方法定義說明:根據title檢索文章,返回文章列表。")
    @ApiImplicitParams(value = {
            @ApiImplicitParam(name = "userId", paramType = "header", value = "操做用戶id", required = false, dataType = "String"),
            @ApiImplicitParam(name = "userName", paramType = "header", value = "操做用戶", required = false, dataType = "String"),
            @ApiImplicitParam(name = "title", paramType = "query", value = "文章標題檢索值", required = false, dataType = "String"),
            @ApiImplicitParam(name = "articleType", paramType = "query", value = "文章類型", required = false, dataType = "ArticleType"),
            @ApiImplicitParam(name = "createTime", paramType = "query", value = "文章發佈時間", required = false, dataType = "Date")
    })
    @RequestMapping(value = {"/articles"}, method = {RequestMethod.GET}, produces = {MediaType.APPLICATION_JSON_VALUE})
    @ResponseBody
    public List<Article> queryList(
            @RequestHeader(value = "userId", required = false) String userId,
            @RequestHeader(value = "userName", required = false) String userName,
            @RequestParam(value = "title", required = false) String title,
            @RequestParam(value = "articleType",required = false) ArticleType articleType,
            @RequestParam(value = "createTime", required = false) Date createTime) {
        System.out.println(createTime);
        List<Article> articles = new ArrayList<>();
        articles.add(new Article(1L, "文章1", "", "", new Date()));
        articles.add(new Article(2L, "文章2", "", "", new Date()));
        articles.add(new Article(3L, "文章3", "", "", new Date()));
        articles.add(new Article(4L, "文章4", "", "", new Date()));

        return articles.stream().filter(s -> s.getTitle().contains(title)).collect(Collectors.toList());
    }

    @ApiOperation(value = "刪除文章", code = 200, httpMethod = "HEAD", produces = "application/json", notes = "queryById方法定義說明:刪除文章")
    @ApiImplicitParams(value = {
            @ApiImplicitParam(name = "userId", paramType = "header", value = "操做用戶id", required = false, dataType = "String"),
            @ApiImplicitParam(name = "userName", paramType = "header", value = "操做用戶", required = false, dataType = "String"),
            @ApiImplicitParam(name = "id", paramType = "query", value = "文章id", required = true, dataType = "Long")
    })
    @RequestMapping(value = {"/article/delete"}, method = {RequestMethod.HEAD}, produces = {MediaType.APPLICATION_JSON_VALUE})
    @ResponseBody
    public Integer delete(@RequestHeader(value = "userId", required = false) String userId,
                          @RequestHeader(value = "userName", required = false) String userName,
                          @RequestParam(value = "id", required = true) Long id) {
        return 1;
    }
}

5)發佈訪問。

打開App入口類,右鍵運行,運行起來後,在瀏覽器中輸入http://localhost:8080/doc.html,回車會顯示以下界面:

 

 到此本篇文章已經結束,應該按照這些步驟均可以配置成功。

 若是swagger啓動後,點擊swagger頁面出現錯誤「java.lang.NumberFormatException: For input string: ""」,解決方案請參考《https://www.bookstack.cn/read/swagger-bootstrap-ui/39.md

 源碼請參考《https://github.com/478632418/springboot-eureka/tree/master/Java-List-Object-Order/springboot-with-fastjson

相關文章
相關標籤/搜索