SpringBoot 开发 Restful 接口,有什么 API 标准吗?如何疾速生成 API 文档呢?Swagger 是一个用于生成、形容和调用 RESTful 接口的 Web 服务。艰深的来讲,Swagger 就是将我的项目中所有(想要裸露的)接口展示在页面上,并且能够进行接口调用和测试的服务。本文次要介绍 OpenAPI 标准,以及 Swagger 技术栈基于 OpenAPI 标准的集成计划。@pdai
-
SpringBoot 接口 – 如何生成接口文档之 Swagger 技术栈?
-
筹备知识点
- 什么是 OpenAPI 标准(AOS)?
- 什么是 Swagger?
- Swagger 和 SpringFox 有啥关系?
- 什么是 Knife4J? 和 Swagger 什么关系?
-
实现案例之 Swagger3
- POM
- Swagger Config
- controller 接口
- 运行测试
-
实现案例之 Knife4J
- POM
- yml 配置
- 注入配置
- Controller 接口
- 运行测试
- 示例源码
- 更多内容
-
筹备知识点
在生成文档前,你须要理解下 OpenAPI 标准,Swagger,SpringFox,Knife4J,Swagger UI 等之间的关系。@pdai
什么是 OpenAPI 标准(AOS)?
OpenAPI 标准(OAS)定义了一个规范的、语言无关的 RESTful API 接口标准,它能够同时容许开发人员和操作系统查看并了解某个服务的性能,而无需拜访源代码,文档或网络流量查看(既不便人类学习和浏览,也不便机器浏览)。正确定义 OAS 后,开发者能够应用起码的实现逻辑来了解近程服务并与之交互。
此外,文档生成工具能够应用 OpenAPI 标准来生成 API 文档,代码生成工具能够生成各种编程语言下的服务端和客户端代码,测试代码和其余用例。
官网 GitHub 地址:OpenAPI-Specification
什么是 Swagger?
Swagger 是一个用于生成、形容和调用 RESTful 接口的 Web 服务。艰深的来讲,Swagger 就是将我的项目中所有(想要裸露的)接口展示在页面上,并且能够进行接口调用和测试的服务。
从上述 Swagger 定义咱们不难看出 Swagger 有以下 3 个重要的作用:
- 将我的项目中所有的接口展示在页面上,这样后端程序员就不须要专门为前端使用者编写专门的接口文档;
- 当接口更新之后,只须要批改代码中的 Swagger 形容就能够实时生成新的接口文档了,从而躲避了接口文档老旧不能应用的问题;
- 通过 Swagger 页面,咱们能够间接进行接口调用,升高了我的项目开发阶段的调试老本。
Swagger3 齐全遵循了 OpenAPI 标准。Swagger 官网地址:https://swagger.io/。
Swagger 和 SpringFox 有啥关系?
Swagger 能够看作是一个遵循了 OpenAPI 标准的一项技术,而 springfox 则是这项技术的具体实现。就好比 Spring 中的 AOP 和 DI 一样,前者是思维,而后者是实现。
什么是 Knife4J? 和 Swagger 什么关系?
实质是 Swagger 的加强解决方案,前身只是一个 SwaggerUI(swagger-bootstrap-ui)
Knife4j 是为 Java MVC 框架集成 Swagger 生成 Api 文档的加强解决方案, 前身是 swagger-bootstrap-ui, 取名 kni4j 是心愿她能像一把匕首一样玲珑, 轻量, 并且性能强悍!
Knife4j 的前身是 swagger-bootstrap-ui,为了符合微服务的架构倒退, 因为原来 swagger-bootstrap-ui 采纳的是后端 Java 代码 + 前端 Ui 混合打包的形式, 在微服务架构下显的很臃肿, 因而我的项目正式更名为 knife4j
更名后次要专一的方面
- 前后端 Java 代码以及前端 Ui 模块进行拆散, 在微服务架构下应用更加灵便
- 提供 专一于 Swagger 的加强解决方案, 不同于只是改善加强前端 Ui 局部
相干文档请参考:https://doc.xiaominfo.com/kni…
实现案例之 Swagger3
咱们先看下最新 Swagger3 如何配置和实现接口。
POM
依据上文介绍,咱们引入 springfox 依赖包,最新的是 3.x.x 版本。和之前的版本比,只须要引入如下的 starter 包即可。
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
Swagger Config
咱们在配置中还减少了一些全局的配置,比方全局参数等
package tech.pdai.springboot.swagger.config;
import io.swagger.annotations.ApiOperation;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import springfox.documentation.builders.*;
import springfox.documentation.oas.annotations.EnableOpenApi;
import springfox.documentation.schema.ScalarType;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import tech.pdai.springboot.swagger.constant.ResponseStatus;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
* swagger config for open api.
*
* @author pdai
*/
@Configuration
@EnableOpenApi
public class SwaggerConfig {
/**
* @return swagger config
*/
@Bean
public Docket openApi() {return new Docket(DocumentationType.OAS_30)
.groupName("Test group")
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
.paths(PathSelectors.any())
.build()
.globalRequestParameters(getGlobalRequestParameters())
.globalResponses(HttpMethod.GET, getGlobalResponse());
}
/**
* @return global response code->description
*/
private List<Response> getGlobalResponse() {return ResponseStatus.HTTP_STATUS_ALL.stream().map(a -> new ResponseBuilder().code(a.getResponseCode()).description(a.getDescription()).build())
.collect(Collectors.toList());
}
/**
* @return global request parameters
*/
private List<RequestParameter> getGlobalRequestParameters() {List<RequestParameter> parameters = new ArrayList<>();
parameters.add(new RequestParameterBuilder()
.name("AppKey")
.description("App Key")
.required(false)
.in(ParameterType.QUERY)
.query(q -> q.model(m -> m.scalarModel(ScalarType.STRING)))
.required(false)
.build());
return parameters;
}
/**
* @return api info
*/
private ApiInfo apiInfo() {return new ApiInfoBuilder()
.title("Swagger API")
.description("test api")
.contact(new Contact("pdai", "http://pdai.tech", "suzhou.daipeng@gmail.com"))
.termsOfServiceUrl("http://xxxxxx.com/")
.version("1.0")
.build();}
}
controller 接口
package tech.pdai.springboot.swagger.controller;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import tech.pdai.springboot.swagger.entity.param.UserParam;
import tech.pdai.springboot.swagger.entity.vo.AddressVo;
import tech.pdai.springboot.swagger.entity.vo.UserVo;
import java.util.Collections;
import java.util.List;
/**
* @author pdai
*/
@Api
@RestController
@RequestMapping("/user")
public class UserController {
/**
* http://localhost:8080/user/add .
*
* @param userParam user param
* @return user
*/
@ApiOperation("Add User")
@PostMapping("add")
@ApiImplicitParam(name = "userParam", type = "body", dataTypeClass = UserParam.class, required = true)
public ResponseEntity<String> add(@RequestBody UserParam userParam) {return ResponseEntity.ok("success");
}
/**
* http://localhost:8080/user/list .
*
* @return user list
*/
@ApiOperation("Query User List")
@GetMapping("list")
public ResponseEntity<List<UserVo>> list() {List<UserVo> userVoList = Collections.singletonList(UserVo.builder().name("dai").age(18)
.address(AddressVo.builder().city("SZ").zipcode("10001").build()).build());
return ResponseEntity.ok(userVoList);
}
}
运行测试
打开文档 API 网页
测试增加一个用户
查问用户列表
实现案例之 Knife4J
这里展现目前应用 Java 生成接口文档的最佳实现: SwaggerV3(OpenAPI)+ Knife4J。
POM
<!-- https://mvnrepository.com/artifact/com.github.xiaoymin/knife4j-spring-boot-starter -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
yml 配置
server:
port: 8080
knife4j:
enable: true
documents:
- group: Test Group
name: My Documents
locations: classpath:wiki/*
setting:
# default lang
language: en-US
# footer
enableFooter: false
enableFooterCustom: true
footerCustomContent: MIT | [Java 全栈](https://pdai.tech)
# header
enableHomeCustom: true
homeCustomLocation: classpath:wiki/README.md
# models
enableSwaggerModels: true
swaggerModelName: My Models
注入配置
package tech.pdai.springboot.knife4j.config;
import com.github.xiaoymin.knife4j.spring.extension.OpenApiExtensionResolver;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import springfox.documentation.builders.*;
import springfox.documentation.oas.annotations.EnableOpenApi;
import springfox.documentation.schema.ScalarType;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import tech.pdai.springboot.knife4j.constant.ResponseStatus;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
* swagger config for open api.
*
* @author pdai
*/
@Configuration
@EnableOpenApi
public class OpenApiConfig {
/**
* open api extension by knife4j.
*/
private final OpenApiExtensionResolver openApiExtensionResolver;
@Autowired
public OpenApiConfig(OpenApiExtensionResolver openApiExtensionResolver) {this.openApiExtensionResolver = openApiExtensionResolver;}
/**
* @return swagger config
*/
@Bean
public Docket openApi() {
String groupName = "Test Group";
return new Docket(DocumentationType.OAS_30)
.groupName(groupName)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
.paths(PathSelectors.any())
.build()
.globalRequestParameters(getGlobalRequestParameters())
.globalResponses(HttpMethod.GET, getGlobalResponse())
.extensions(openApiExtensionResolver.buildExtensions(groupName))
.extensions(openApiExtensionResolver.buildSettingExtensions());
}
/**
* @return global response code->description
*/
private List<Response> getGlobalResponse() {return ResponseStatus.HTTP_STATUS_ALL.stream().map(a -> new ResponseBuilder().code(a.getResponseCode()).description(a.getDescription()).build())
.collect(Collectors.toList());
}
/**
* @return global request parameters
*/
private List<RequestParameter> getGlobalRequestParameters() {List<RequestParameter> parameters = new ArrayList<>();
parameters.add(new RequestParameterBuilder()
.name("AppKey")
.description("App Key")
.required(false)
.in(ParameterType.QUERY)
.query(q -> q.model(m -> m.scalarModel(ScalarType.STRING)))
.required(false)
.build());
return parameters;
}
/**
* @return api info
*/
private ApiInfo apiInfo() {return new ApiInfoBuilder()
.title("My API")
.description("test api")
.contact(new Contact("pdai", "http://pdai.tech", "suzhou.daipeng@gmail.com"))
.termsOfServiceUrl("http://xxxxxx.com/")
.version("1.0")
.build();}
}
其中 ResponseStatus 封装
package tech.pdai.springboot.knife4j.constant;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* @author pdai
*/
@Getter
@AllArgsConstructor
public enum ResponseStatus {SUCCESS("200", "success"),
FAIL("500", "failed"),
HTTP_STATUS_200("200", "ok"),
HTTP_STATUS_400("400", "request error"),
HTTP_STATUS_401("401", "no authentication"),
HTTP_STATUS_403("403", "no authorities"),
HTTP_STATUS_500("500", "server error");
public static final List<ResponseStatus> HTTP_STATUS_ALL = Collections.unmodifiableList(Arrays.asList(HTTP_STATUS_200, HTTP_STATUS_400, HTTP_STATUS_401, HTTP_STATUS_403, HTTP_STATUS_500));
/**
* response code
*/
private final String responseCode;
/**
* description.
*/
private final String description;
}
Controller 接口
package tech.pdai.springboot.knife4j.controller;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import tech.pdai.springboot.knife4j.entity.param.AddressParam;
/**
* Address controller test demo.
*
* @author pdai
*/
@Api(value = "Address Interfaces", tags = "Address Interfaces")
@RestController
@RequestMapping("/address")
public class AddressController {
/**
* http://localhost:8080/address/add .
*
* @param addressParam param
* @return address
*/
@ApiOperation("Add Address")
@PostMapping("add")
@ApiImplicitParams({@ApiImplicitParam(name = "city", type = "query", dataTypeClass = String.class, required = true),
@ApiImplicitParam(name = "zipcode", type = "query", dataTypeClass = String.class, required = true)
})
public ResponseEntity<String> add(AddressParam addressParam) {return ResponseEntity.ok("success");
}
}
运行测试
自定义用户主页
model 模型
全局参数 和配置
自定义文档
接口文档和测试接口
示例源码
其它旧版本的实现:
- swagger2
- Swagger2+BootstrapUI
- Knife4j v2
更多例子都可在如下仓库中找到
https://github.com/realpdai/t…
更多内容
辞别碎片化学习,无套路一站式体系化学习后端开发: Java 全栈常识体系(https://pdai.tech)