Swagger 是一个流行的API开发框架,该框架以"开放API声明"(OpenAPI Specification,OAS)为基础,对整个 API 的开发周期都提供了相应的解决方案。本文主要介绍 Spring Boot 与Swagger 的结合使用,文中所使用到的软件版本:Spring Boot 2.4.4、jdk1.8.0_181、springfox-swagger2 3.0.0。

1、简介

1.1、Swagger简介

Swagger是一系列用于Restful API开发的工具,开源的部分包括:

OpenAPI Specification:API规范,规定了如何描述一个系统的API

Swagger Codegen:用于通过API规范生成服务端和客户端代码

Swagger Editor:用来编写API

Swagger UI:用于展示API

非开源的部分包括:

Swagger Hub:云服务,相当于Editor + Codegen + UI

Swagger Inspector:手动测试API的工具

SoapUI Pro:功能测试和安全测试的自动化工具

LoadUI Pro:压力测试和性能测试的自动化工具

1.2、Springfox简介

Springfox是一个通过扫描代码提取代码中信息生成API文档的工具。API文档的格式不止Swagger的OpenAPI Specification,还有RAML,jsonapi,Springfox同样支持这些格式。Springfox实现了对Swagger注解的支持,并集成了Swagger UI。

2、Swagger常用注解



注解

使用的地方

用途

@Api

描述类的主要用途

@ApiOperation

方法

描述方法的用途

@ApiImplicitParam

方法

用于描述接口的单个参数

@ApiImplicitParams

方法

用于描述接口的参数集,包含多个@ApiImplicitParam

@ApiIgnore

类/方法/参数

Swagger 文档不会显示拥有该注解的接口

@ApiModel

参数实体类

描述参数实体类的主要用途

@ApiModelProperty

参数实体类属性

描述参数实体类属性的主要用途

@ApiResponse

方法

描述一个响应信息

@ApiResponses

方法

描述一组响应信息


3、Spring Boot 整合 Swagger

3.1、引入依赖


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


3.2、Swagger 配置


package com.abc.demo.config;

import io.swagger.annotations.ApiOperation;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.*;
import springfox.documentation.oas.annotations.EnableOpenApi;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;


@Configuration
@EnableOpenApi
public class SwaggerConfig {
private static final String AUTH_HEADER_NAME = "token";

@Bean
public Docket docket() {
return new Docket(DocumentationType.OAS_30)
.apiInfo(apiInfo())
.select()
//加了ApiOperation注解的方法,才生成接口文档
.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
//特定包下的类,才生成接口文档
//.apis(RequestHandlerSelectors.basePackage("com.abc.demo.controller"))
.paths(PathSelectors.any())
.build();
}

private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("XXX系统")
.description("XXX系统接口文档")
.termsOfServiceUrl("https://www.abc.com")
.contact(new Contact("Jack", "/jack", "123456@qq.com"))
.version("1.0.0")
.build();
}

}


3.3、编写Controller


package com.abc.demo.controller;
import com.abc.demo.entity.R;
import com.abc.demo.entity.Student;
import com.abc.demo.form.StudentForm;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

@RestController
@RequestMapping("/api/student")
@Api(tags = "学生相关接口")
public class StudentController {
private static Logger logger = LoggerFactory.getLogger(StudentController.class);
@PostMapping("add")
@ApiOperation("增加学生(json方式提交)")
public R<Long> add(@RequestBody StudentForm studentForm) {
logger.info("studentForm={}", studentForm);
//TODO: service调用

return R.ok(new Random().nextLong());
}


@PostMapping("add2")
@ApiOperation("增加学生(form方式提交)")
public R<Long> add2(StudentForm studentForm) {
logger.info("studentForm={}", studentForm);
//TODO: service调用

return R.ok(new Random().nextLong());
}

@GetMapping("get")
@ApiOperation("根据姓名查询学生")
@ApiImplicitParam(name = "name", value = "学生姓名", dataTypeClass = String.class, required = true)
public R<Student> get(String name) {
logger.info("name={}", name);
//TODO: service调用

return R.ok(new Student(new Random().nextLong(), "杜甫", 21, 175));
}

@GetMapping("list")
@ApiOperation("获取学生列表")
public R<List<Student>> list() {
//TODO: service调用
List<Student> students = new ArrayList(){{
add(new Student(new Random().nextLong(), "杜甫", 21, 175));
add(new Student(new Random().nextLong(), "李商隐", 22, 175));
}};
return R.ok(students);
}

}


Controller用到的参数实体类StudentForm:


package com.abc.demo.form;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.ToString;

@Data
@ToString
@ApiModel(value = "学生表单")
public class StudentForm {
@ApiModelProperty(value = "姓名", example = "李白")
private String name;

@ApiModelProperty(value = "年龄", example = "20")
private Integer age;

@ApiModelProperty(value = "身高", example = "175")
private Integer height;
}


Controller用到的实体类Student:


package com.abc.demo.entity;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

@NoArgsConstructor
@AllArgsConstructor
@Data
@ToString
@ApiModel(value = "学生信息")
public class Student {
@ApiModelProperty(value = "学生id", example = "1234")
private Long id;

@ApiModelProperty(value = "学生姓名", example = "李白")
private String name;

@ApiModelProperty(value = "年龄", example = "20")
private Integer age;

@ApiModelProperty(value = "身高", example = "175")
private Integer height;
}


Controller用到的返回对象R:

Spring Boot 入门实战(8)--使用 Swagger 构建 API 文档_Spring BootSpring Boot 入门实战(8)--使用 Swagger 构建 API 文档_Spring Boot_02


package com.abc.demo.entity;


/**
* 返回数据
*/
public class R<T> {
/**
* 返回码
* 0 正常,其他异常
*/
private int returnCode = 0;

/**
* 描述
*/
private String description = "OK";

/**
* 结果数据
*/
private T result;

public int getReturnCode() {
return returnCode;
}
public String getDescription() {
return description;
}
public T getResult() {
return result;
}

public static R ok() {
return new R();
}

public static <T> R<T> ok(T result) {
R<T> r = new R<>();
r.result = result;
return r;
}

public static <T> R<T> error() {
R<T> r = new R();
r.returnCode = -1;
r.description = "未知异常,请联系管理员";
return r;
}

public static <T> R<T> error(String description) {
R<T> r = new R();
r.returnCode = -1;
r.description = description;
return r;
}

public static <T> R<T> error(int returnCode, String description) {
R<T> r = new R();
r.returnCode = returnCode;
r.description = description;
return r;
}

}

R.java

3.4、查看接口信息

访问 ​http://localhost:8080/swagger-ui/index.html​,就可以在页面查看并测试接口了:

Spring Boot 入门实战(8)--使用 Swagger 构建 API 文档_java_03

3.5、Swagger 带 Token 访问

在很多应用中访问接口需要传token来验证登录情况,可以先访问不要token的接口(如登录接口)来获取token,然后用该token来访问接口,在 Swagger 中有两种方式来传token。

3.5.1、全局token

设置一个全局的token,每次请求时会把这个token加上。


package com.abc.demo.config;

import io.swagger.annotations.ApiOperation;
import io.swagger.models.auth.In;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.*;
import springfox.documentation.oas.annotations.EnableOpenApi;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;


@Configuration
@EnableOpenApi
public class SwaggerConfig {
private static final String AUTH_HEADER_NAME = "token";

@Bean
public Docket docket() {
return new Docket(DocumentationType.OAS_30)
.apiInfo(apiInfo())
.select()
//加了ApiOperation注解的方法,才生成接口文档
.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
//特定包下的类,才生成接口文档
//.apis(RequestHandlerSelectors.basePackage("com.abc.demo.controller"))
.paths(PathSelectors.any())
.build()
//设置全局token
.securitySchemes(securitySchemes())
.securityContexts(securityContexts());
}

private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("XXX系统")
.description("XXX系统接口文档")
.termsOfServiceUrl("https://www.abc.com")
.contact(new Contact("Jack", "/jack", "123456@qq.com"))
.version("1.0.0")
.build();
}

private List<SecurityScheme> securitySchemes() {
return Arrays.asList(new ApiKey(AUTH_HEADER_NAME, "auth", In.HEADER.name()));
}

private List<SecurityContext> securityContexts() {
List<SecurityContext> securityContexts = new ArrayList<>();
securityContexts.add(SecurityContext
.builder()
.securityReferences(securityReferences())
.operationSelector(operationContext -> operationContext.requestMappingPattern().startsWith("/api/"))
.build());
return securityContexts;
}

private List<SecurityReference> securityReferences() {
AuthorizationScope[] authorizationScopes = new AuthorizationScope[] {new AuthorizationScope("global", "accessEverything")};
List<SecurityReference> securityReferences = new ArrayList<>();
securityReferences.add(new SecurityReference(AUTH_HEADER_NAME, authorizationScopes));
return securityReferences;
}

}


效果如下:

Spring Boot 入门实战(8)--使用 Swagger 构建 API 文档_接口文档_04

3.5.2、每个接口单独传token


package com.abc.demo.config;

import io.swagger.annotations.ApiOperation;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.*;
import springfox.documentation.oas.annotations.EnableOpenApi;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;

import java.util.Arrays;
import java.util.List;


@Configuration
@EnableOpenApi
public class SwaggerConfig {
private static final String AUTH_HEADER_NAME = "token";

@Bean
public Docket docket() {
return new Docket(DocumentationType.OAS_30)
.apiInfo(apiInfo())
.select()
//加了ApiOperation注解的方法,才生成接口文档
.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
//特定包下的类,才生成接口文档
//.apis(RequestHandlerSelectors.basePackage("com.abc.demo.controller"))
.paths(PathSelectors.any())
.build()
//每个接口传token
.globalRequestParameters(globalRequestParameters());
}

private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("XXX系统")
.description("XXX系统接口文档")
.termsOfServiceUrl("https://www.abc.com")
.contact(new Contact("Jack", "/jack", "123456@qq.com"))
.version("1.0.0")
.build();
}

private List<RequestParameter> globalRequestParameters() {
return Arrays.asList(new RequestParameterBuilder()
.name(AUTH_HEADER_NAME)
.description("access token")
.in(ParameterType.HEADER)
.required(false)
.build());
}

}


效果如下:

Spring Boot 入门实战(8)--使用 Swagger 构建 API 文档_spring_05