一、swagger简介

1.什么是swagger

Swagger是一个规范和完整的框架,用于生成、描述、调用和可视化RESTful风格的Web服务(2015年,Swagger项目被SmartBear Software收购。Swagger 规范被捐赠给 Linux 基金会并更名为 OpenAPI)。简单来说,Swagger是一个功能强大的接口管理工具,帮你设计接口API,生成接口API的文档,甚至可以对接口API进行测试,并且提供了多种编程语言的前后端分离解决方案。

Swagger有大致有3个优点:

  1. Swagger可以整合到代码中,在开发时通过注解,编写注释,自动生成API文档。
  2. 将前端后台分开,不会有过分的依赖。
  3. 界面清晰,无论是editor的实时展示还是ui的展示都十分人性化,如果自己仅仅用markdown来编写,又要纠结该如何展现,十分痛苦。

2.swagger注解

swagger通过注解表明该接口会生成文档,包括接口名、请求方法、参数、返回信息的等等。

@Api:修饰整个类,描述Controller的作用

@ApiOperation:描述一个类的一个方法,或者说一个接口

@ApiParam:单个参数描述

@ApiModel:用对象来接收参数

@ApiProperty:用对象接收参数时,描述对象的一个字段

@ApiResponse:HTTP响应其中1个描述

@ApiResponses:HTTP响应整体描述

@ApiIgnore:使用该注解忽略这个API

@ApiError :发生错误返回的信息

@ApiImplicitParam:一个请求参数

@ApiImplicitParams:多个请求参数

二、springboot整合Swagger-UI 3.0

1、添加依赖

pom.xml中添加:

<!-- swagger -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>

备注:

  1. 什么是springfox?

    springfox就是对swagger规范在spring下的封装实现,我们看得到的界面就是springfox-swagger-ui

    Springfox官方文档:http://springfox.github.io/springfox/docs/snapshot/

    Springfox的GitHub仓库:https://github.com/springfox/springfox

    Springfox3.0版本特性:https://github.com/springfox/springfox/releases/tag/3.0.0

2、配置Swagger-UI

  1. 新建SwaggerConfig类,并在SwaggerConfig.java文件中进行配置:

    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.oas.annotations.EnableOpenApi;
    import springfox.documentation.service.ApiInfo;
    import springfox.documentation.service.Contact;
    import springfox.documentation.spi.DocumentationType;
    import springfox.documentation.spring.web.plugins.Docket;

    /**
    * Swagger-ui配置
    */
    @Configuration
    @EnableOpenApi
    public class SwaggerConfig {

    /**
    * 创建API应用
    * apiInfo() 增加API相关信息
    * 通过select()函数返回一个ApiSelectorBuilder实例,用来控制哪些接口暴露给Swagger来展现,
    * 本例采用指定扫描的包路径来定义指定要建立API的目录。
    *
    * @return
    */
    @Bean
    public Docket restApi() {
    return new Docket(DocumentationType.SWAGGER_2)
    .groupName("标准接口")
    .apiInfo(apiInfo("Spring Boot中使用Swagger3构建RESTful APIs", "1.0"))
    .useDefaultResponseMessages(true)
    .forCodeGeneration(false)
    .select()
    .apis(RequestHandlerSelectors.basePackage("com.qiancheng.springboot.controller"))
    .paths(PathSelectors.any())
    .build();
    }

    /**
    * 创建该API的基本信息(这些基本信息会展现在文档页面中)
    * 访问地址:http://ip:port/swagger-ui/index.html
    *
    * @return
    */
    private ApiInfo apiInfo(String title, String version) {
    return new ApiInfoBuilder()
    .title(title)//标题
    .description("更多请关注: https://qianchenggit.github.io/")//描述
    .termsOfServiceUrl("https://qianchenggit.github.io/")//服务条款URL
    .contact(new Contact("qiancheng", "https://qianchenggit.github.io/", "zehong.zhang@qq.com"))
    .version(version)//版本
    .build();
    }
    }

  2. 运行程序,如果报以下错误:

    Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
    2022-08-24 21:42:28.564 ERROR 8600 --- [ main] o.s.boot.SpringApplication : Application run failed

    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) ~[spring-context-5.3.22.jar:5.3.22]
    at org.springframework.context.support.DefaultLifecycleProcessor.access$200(DefaultLifecycleProcessor.java:54) ~[spring-context-5.3.22.jar:5.3.22]
    at org.springframework.context.support.DefaultLifecycleProcessor$LifecycleGroup.start(DefaultLifecycleProcessor.java:356) ~[spring-context-5.3.22.jar:5.3.22]
    at java.lang.Iterable.forEach(Iterable.java:75) ~[na:1.8.0_191]
    at org.springframework.context.support.DefaultLifecycleProcessor.startBeans(DefaultLifecycleProcessor.java:155) ~[spring-context-5.3.22.jar:5.3.22]
    at org.springframework.context.support.DefaultLifecycleProcessor.onRefresh(DefaultLifecycleProcessor.java:123) ~[spring-context-5.3.22.jar:5.3.22]
    at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:935) ~[spring-context-5.3.22.jar:5.3.22]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:586) ~[spring-context-5.3.22.jar:5.3.22]
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:147) ~[spring-boot-2.7.3.jar:2.7.3]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:734) [spring-boot-2.7.3.jar:2.7.3]
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:408) [spring-boot-2.7.3.jar:2.7.3]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:308) [spring-boot-2.7.3.jar:2.7.3]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306) [spring-boot-2.7.3.jar:2.7.3]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1295) [spring-boot-2.7.3.jar:2.7.3]
    at com.qiancheng.springboot.SpringbootApplication.main(SpringbootApplication.java:12) [classes/:na]
    Caused by: java.lang.NullPointerException: null
    at springfox.documentation.spring.web.WebMvcPatternsRequestConditionWrapper.getPatterns(WebMvcPatternsRequestConditionWrapper.java:56) ~[springfox-spring-webmvc-3.0.0.jar:3.0.0]
    at springfox.documentation.RequestHandler.sortedPaths(RequestHandler.java:113) ~[springfox-core-3.0.0.jar:3.0.0]
    at springfox.documentation.spi.service.contexts.Orderings.lambda$byPatternsCondition$3(Orderings.java:89) ~[springfox-spi-3.0.0.jar:3.0.0]
    at java.util.Comparator.lambda$comparing$77a9974f$1(Comparator.java:469) ~[na:1.8.0_191]
    at java.util.TimSort.countRunAndMakeAscending(TimSort.java:355) ~[na:1.8.0_191]
    at java.util.TimSort.sort(TimSort.java:220) ~[na:1.8.0_191]
    at java.util.Arrays.sort(Arrays.java:1512) ~[na:1.8.0_191]
    at java.util.ArrayList.sort(ArrayList.java:1462) ~[na:1.8.0_191]
    at java.util.stream.SortedOps$RefSortingSink.end(SortedOps.java:387) ~[na:1.8.0_191]
    at java.util.stream.Sink$ChainedReference.end(Sink.java:258) ~[na:1.8.0_191]
    at java.util.stream.Sink$ChainedReference.end(Sink.java:258) ~[na:1.8.0_191]
    at java.util.stream.Sink$ChainedReference.end(Sink.java:258) ~[na:1.8.0_191]
    at java.util.stream.Sink$ChainedReference.end(Sink.java:258) ~[na:1.8.0_191]
    at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482) ~[na:1.8.0_191]
    at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471) ~[na:1.8.0_191]
    at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708) ~[na:1.8.0_191]
    at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[na:1.8.0_191]
    at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499) ~[na:1.8.0_191]
    at springfox.documentation.spring.web.plugins.WebMvcRequestHandlerProvider.requestHandlers(WebMvcRequestHandlerProvider.java:81) ~[springfox-spring-webmvc-3.0.0.jar:3.0.0]
    at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193) ~[na:1.8.0_191]
    at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1382) ~[na:1.8.0_191]
    at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481) ~[na:1.8.0_191]
    at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471) ~[na:1.8.0_191]
    at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708) ~[na:1.8.0_191]
    at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[na:1.8.0_191]
    at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499) ~[na:1.8.0_191]
    at springfox.documentation.spring.web.plugins.AbstractDocumentationPluginsBootstrapper.withDefaults(AbstractDocumentationPluginsBootstrapper.java:107) ~[springfox-spring-web-3.0.0.jar:3.0.0]
    at springfox.documentation.spring.web.plugins.AbstractDocumentationPluginsBootstrapper.buildContext(AbstractDocumentationPluginsBootstrapper.java:91) ~[springfox-spring-web-3.0.0.jar:3.0.0]
    at springfox.documentation.spring.web.plugins.AbstractDocumentationPluginsBootstrapper.bootstrapDocumentationPlugins(AbstractDocumentationPluginsBootstrapper.java:82) ~[springfox-spring-web-3.0.0.jar:3.0.0]
    at springfox.documentation.spring.web.plugins.DocumentationPluginsBootstrapper.start(DocumentationPluginsBootstrapper.java:100) ~[springfox-spring-web-3.0.0.jar:3.0.0]
    at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:178) ~[spring-context-5.3.22.jar:5.3.22]
    ... 14 common frames omitted

    Process finished with exit code 1

​ 原因是:SpringFox正在使用 WebMvc 但尚未使用@EnableWebMvc注解,请在SpringbootApplication启动类增加@EnableWebMvc注解:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

@SpringBootApplication
@EnableWebMvc
public class SpringbootApplication {

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

}

  1. 运行程序,访问:http://{ip}:{port}/swagger-ui/index.html

三、使用第三方UI(knife4j)

  1. 在pom.xml文件添加依赖(knife4j文档

    <!-- swagger-bootstrap-ui依赖,不使用增强功能只为swagger-ui换前端皮肤 -->
    <dependency>
    <groupId>com.github.xiaoymin</groupId>
    <artifactId>knife4j-spring-ui</artifactId>
    <version>2.0.9</version>
    </dependency>

    项目地址:https://github.com/xiaoymin/knife4j

  2. 重新启动项目,访问:http://{ip}:{port}/doc.html

    1. 若出现404页面,且控制台出现No mapping for GET /doc.html的提示。

    2. 出错原因:因为doc.html是在jar包里的,需要使用资源处理器注册静态资源。

    3. 解决办法:让SpringbootApplication启动类实现WebMvcConfigurer接口,使用资源处理器注册静态资源。

      import org.springframework.boot.SpringApplication;
      import org.springframework.boot.autoconfigure.SpringBootApplication;
      import org.springframework.web.servlet.config.annotation.EnableWebMvc;
      import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
      import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

      @SpringBootApplication
      @EnableWebMvc
      public class SpringbootApplication implements WebMvcConfigurer {

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

      /**
      * 使用SpringBoot项目继承Knif4j访问doc.html页面,出现No mapping for GET /doc.html
      * 出错原因:
      * 因为doc.html是在jar包里的,需要使用资源处理器注册静态资源。
      * @param registry
      */
      @Override
      public void addResourceHandlers(ResourceHandlerRegistry registry) {
      registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");
      registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
      }

      }