本文属于原创,转载注明出处,欢迎关注微信小程序小白AI博客
微信公众号小白AI
或者网站 xiaobaiai.nethtml
[TOC]前端
在现在先后端分离开发的模式下,前端调用后端提供的API去实现数据的展现或者相关的数据操做,保证及时更新和完整的REST API文档将会大大地提升两边的工做效率,减小没必要要的沟通成本。本文采用的Swagger2就是一个当前流行的经过少许的注解就能够生成漂亮的API文档工具,且在生成的在线文档中提供相似POSTMAN直接调试能力,不只仅是静态的文档。接下来将会利用这个工具与Spring Boot项目结合,最终生成咱们上一篇文章中所涉及到的REST API文档。java
这一篇文章基本将Swagger2在生产环境中可能会用到的配置都有涉及,慢慢看吧,看了这一篇因该是够了。git
Swagger是与用于实现 OpenAPI 文档普遍使用的工具,Swagger工具集包括开源工具,免费工具和商业工具的组合,可在API生命周期的不一样阶段使用。github
Swagger Editor
(开源):使用Swagger编辑器,能够在浏览器内的YAML文档中编辑OpenAPI规范并支持实时预览文档,能够参考官方的Demo https://editor.swagger.io/ Swagger UI
(开源):让Swagger产生的文档更漂亮,并且支持API交互操做,在生成文档后,直接在浏览器中浏览,并能够实现相似curl
命令或者postman
访问咱们的API,并返回相关数据。 Swagger Codegen
(开源): 是一个代码生成器,能够经过Swagger API定义生成不一样语言版本的服务端和客户端工程代码。 Swagger Core
(开源):用于生成Swagger API规范的示例和服务器集成,可轻松访问REST API,结合Swagger UI
,让生成的文档更漂亮。 Swagger Parser
(开源): Java开发,解析OpenAPI定义的独立库 Swagger Inspector
(免费):API在线测试工具,验证API并从现有API生成OpenAPI定义功能 https://goo.gl/fZYHWz SwaggerHub
(免费和商用版):API设计和文档化,为使用OpenAPI的团队打造。 参考《Spring Boot从零入门5_五脏俱全的RESTful Web Service构建》。构建好后有以下REST API:web
# 获取全部用户信息
GET http://localhost:8080/api/v1/users
# 新增一个用户,参数经过body传递
POST http://localhost:8080/api/v1/users
# 更新一个用户信息
PUT http://localhost:8080/api/v1/users/{id}
# 删除指定用户
DELETE http://localhost:8080/api/v1/users/{id}复制代码
构建好RESTful WEB服务后,接下来咱们集成Swagger,而后对上节中的REST API自动生成接口文档。正则表达式
集成Swagger2,须要在pom.xml中添加依赖源:spring
<dependencies>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<!-- 截至2019年11月7日为止,最新版本为2.9.2 -->
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 -->
<version>2.9.2</version>
</dependency>
</dependencies>复制代码
springfox
有一个专用对象Docket,能够灵活的配置Swagger的各类属性,首先咱们简单的建立一个Swagger配置类Swagger2Config.java
:json
@Configuration
@EnableSwagger2
public class Swagger2Config {
@Bean("UsersApis")
public Docket usersApis() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any())
.build();
}
}复制代码
这里的@Configuration
注解用于定义配置类,被注解的类内部包含有一个或多个被@Bean
注解的方法,这些方法将会被AnnotationConfigApplicationContext
类进行扫描,并用于构建Bean定义,初始化对象。@ComponentScan
会自动获取全部的Spring Components,包括@Configuration
类。另外这里的“用户管理模块”API生成配置很简单,对全部路径上API都去生成文档。小程序
当完成Swagger2的配置类时,启动WEB服务,经过http://localhost:8080/v2/api-docs就能够访问生成文档内容,可是浏览器返回的是JSON内容,基本上很难给须要用到相关API的开发人员进行参考。这个时候就须要用到Swagger2 UI
了。
pom.xml添加依赖,而后重启WEB服务就能够了,再次访问http://localhost:8080/swagger-ui.html,这时候看到的就是WEB文档了。
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>复制代码
从swagger-ui页面看到的内容有一部无关的内容,或者是如何明显表现跟项目相关的内容呢?下面章节详细讲解Swagger的各类配置,可以应用到实际生产环境中去。
首先,若是要将咱们最后生成的API文档给生产环境的开发人员查阅,那么友好的展现信息和归类是颇有必要的,咱们接下来实现以下目标:
为了更好地展现API分组功能,这里另外加了一组REST API (代码层面上只须要将User相关的代码所有复制一份,将User关键字所有改成Product就能够了,包括大小写):
# 获取全部产品信息
GET http://localhost:8080/api/v1/products
# 新增一个产品,参数经过body传递
POST http://localhost:8080/api/v1/products
# 更新一个产品信息
PUT http://localhost:8080/api/v1/products/{id}
# 删除指定产品
DELETE http://localhost:8080/api/v1/products/{id}复制代码
@Configuration
@EnableSwagger2
public class Swagger2Config {
@Bean("UsersApis")
public Docket usersApis() {
return new Docket(DocumentationType.SWAGGER_2)
// select()返回的是ApiSelectorBuilder对象,而非Docket对象
.select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any())
// build()返回的是Docket对象
.build()
// 测试API时的主机URL
.host("https://xiaobaiai.net")
// API前缀
.pathProvider(new RelativePathProvider(null) {
@Override
public String getApplicationBasePath() {
return "/prefix";
}
})
.apiInfo(apiInfo());
}
public ApiInfo apiInfo() {
// API负责人的联系信息
final Contact contact = new Contact(
"Ethan", "https://xiaobaiai.net", "ycm_hy@163.com");
return new ApiInfoBuilder()
// API文档标题
.title("X系统平台接口文档")
// API文档描述
.description("用户/产品相关API, 更多请关注公众号: 小白AI 或微信小程序:小白AI博客")
// 服务条款URL
.termsOfServiceUrl("https://github.com/yicm")
// API文档版本
.version("1.0")
// API负责人的联系信息
.contact(contact)
// API的许可证Url
.licenseUrl("http://license.coscl.org.cn/MulanPSL")
.license("MulanPSL")
.build();
}
}复制代码
经过添加文档信息编译对象ApiInfoBuilder
能够配置API文档的各类信息,包括标题、描述、服务条款、版本、责任人、许可证等。最后在Docket中添加信息配置对象便可生效。
上面的文档信息配置中默认是没有对API分组的,即全部的API都展现在了一个页面,没有隔离,若是须要分组,那咱们须要对不一样API组分配Bean,目前示例能够分为用户API组和产品API组,而后经过apis()
和 paths()
进行API过滤。
为了避免显示某个包下面API或某个URL路径下API, Docket
提供了 apis()
和 paths()
两 个方法来帮助咱们在不一样级别上过滤接口(上面示例咱们默认对这两个设置是不作任何过滤,扫描全部API):
apis()
:这种方式能够经过指定包名的方式,让 Swagger2 只去某些包下面扫描 paths()
:这种方式能够经过筛选 API 的 URL 来进行过滤 apis和paths中的Predicates
除了any
、ant
、none
,还支持regex
正则表达式。
如:
PathSelectors.regex("/api/v2/users.*")复制代码
下面就是分组示例代码,实现分组,很简单,就是在Docket中配置组名就行了:
@Configuration
@EnableSwagger2
public class Swagger2Config {
@Bean
public Docket usersApis() {
return new Docket(DocumentationType.SWAGGER_2)
.groupName("用户管理接口")
// select()返回的是ApiSelectorBuilder对象,而非Docket对象
.select()
.apis(RequestHandlerSelectors.basePackage("com.xiaobaiai.user"))
.paths(Predicates.or(
// 两个**,能够匹配底下全部URL
// 一个*,只能匹配一级URL分段
PathSelectors.ant("/api/v1/users/**"),
PathSelectors.ant("/api/v1/users/*")))
// build()返回的是Docket对象
.build()
// 测试API时的主机URL
.host("https://xiaobaiai.net")
// API前缀,最终全部API的基础地址就是host+prefix: https://xiaobaiai.net/prefix
.pathProvider(new RelativePathProvider(null) {
@Override
public String getApplicationBasePath() {
return "/prefix";
}
})
.apiInfo(apiInfo());
}
@Bean
public Docket productsApis() {
return new Docket(DocumentationType.SWAGGER_2)
.groupName("产品管理接口")
// select()返回的是ApiSelectorBuilder对象,而非Docket对象
.select()
.apis(RequestHandlerSelectors.basePackage("com.xiaobaiai.product"))
.paths(Predicates.or(
// 两个**,能够匹配底下全部URL
// 一个*,只能匹配一级URL分段
PathSelectors.ant("/api/v1/products/**"),
PathSelectors.ant("/api/v1/products/*")))
// build()返回的是Docket对象
.build()
// 测试API时的主机URL
.host("https://xiaobaiai.net")
// API前缀
.pathProvider(new RelativePathProvider(null) {
@Override
public String getApplicationBasePath() {
return "/prefix";
}
})
.apiInfo(apiInfo());
}
public ApiInfo apiInfo() {
// API负责人的联系信息
final Contact contact = new Contact(
"Ethan", "https://xiaobaiai.net", "ycm_hy@163.com");
return new ApiInfoBuilder()
// API文档标题
.title("X系统平台接口文档")
// API文档描述
.description("用户/产品相关API, 更多请关注公众号: 小白AI 或微信小程序:小白AI博客")
// 服务条款URL
.termsOfServiceUrl("https://github.com/yicm")
// API文档版本
.version("1.0")
// API负责人的联系信息
.contact(contact)
// API的许可证Url
.licenseUrl("http://license.coscl.org.cn/MulanPSL")
.license("MulanPSL")
.build();
}
}复制代码
分组配置完成后,从新启动,打开浏览器就能够看到效果了:
虽然上面咱们已经能够控制API的显示和分组了,可是对于API一些更详细,对组内API再次归类之类的,好比小组的描述信息,以及每一个API如何去控制它的参数说明,返回值说明等。这些都是经过注解去实现的,接下来咱们讲述经常使用的注解及做用:
@Api
: 将这个注解添加到控制器类上,则能够给控制器添加描述类信息: 相关可设置参数有:
示例:
// Swagger配置类
@Configuration
@EnableSwagger2
public class Swagger2Config {
@Bean
public Docket productsApis() {
return new Docket(DocumentationType.SWAGGER_2)
.groupName("产品管理接口")
.select()
.apis(RequestHandlerSelectors.basePackage("com.xiaobaiai.product"))
.paths(Predicates.or(
PathSelectors.ant("/api/v1/products/**"),
PathSelectors.ant("/api/v1/products/*")))
.build()
.host("https://xiaobaiai.net")
.pathProvider(new RelativePathProvider(null) {
@Override
public String getApplicationBasePath() {
return "/prefix";
}
})
.apiInfo(apiInfo())
.tags(new Tag("产品操做分组1", "产品查询相关操做."),
new Tag("产品操做分组2", "产品添加或删除相关操做."),
new Tag("产品操做分组3", "产品更新相关操做."),
new Tag("产品操做分组4", "产品相关所有操做."));
}
}复制代码
// 控制器类
@RestController
@RequestMapping("/api/v1")
@Api(tags={"产品接口文档列表"})
public class ProductServiceController { ... }复制代码
效果以下:
@ApiIgnore
: 做用在REST API控制器方法
上,则该API不会被显示出来: @ApiIgnore
@RequestMapping(value = "/users/{id}", method = RequestMethod.DELETE)
public ResponseEntity<Object> delete(@PathVariable("id") String id) { ... }复制代码
@ApiOperation
注解用于控制器方法
上面,用于对方法的描述,相关参数设置描述以下: 示例:
@ApiOperation(value = "获取全部产品", notes = "每调用一次,就耗费流量100M", response = String.class)
@GetMapping(value = "/products")
public ResponseEntity<Object> getProduct() {
return new ResponseEntity<>(productService.getProducts(), HttpStatus.OK);
}复制代码
最后效果就是:
@ApiImplicitParams
和@ApiImplicitParam
注解用于控制器方法传入参数的说明。默认状况下,Swagger会根据API方法中的传入参数进行参数说明的生成,不过参数说明默认就是变量名,由于这两个注解不必定须要。相关参数设置说明以下: @RequestHeader
(代码中接收注解) @RequestParam
(代码中接收注解) @PathVariable
(代码中接收注解) @RequestBody
(代码中接收注解) 示例:
// 若是只有一个参数,则仅仅@ApiImplicitParam就能够了
@ApiImplicitParams({
@ApiImplicitParam(name="id", value="产品ID值", required = true),
@ApiImplicitParam(name="product", value="产品内容", required = true)
})
@RequestMapping(value = "/products/{id}", method = RequestMethod.PUT)
public ResponseEntity<Object> updateProduct(@PathVariable("id") String id, @RequestBody Product product) {
productService.updateProduct(id, product);
return new ResponseEntity<>("Product is updated successsfully", HttpStatus.OK);
}复制代码
@ApiParam
: 做用同ApiImplicitParam,单个参数描述通常经常使用该注解,并且该注解只能与JAX-RS 1.x/2.x注解结合使用。参数设置说明以下: @ApiResponses
、@ApiResponse
: 用于控制器方法返回值的说明,参数设置说明以下: 示例:
@ApiOperation(value = "获取全部产品", notes = "每调用一次,就耗费流量100M",response =Product.class, responseContainer="List")
@ApiResponses({
@ApiResponse(code = 200, message = "成功!", response=Product.class),
@ApiResponse(code = 401, message = "未受权!", response=Product.class),
@ApiResponse(code = 404, message = "页面未找到!", response=Product.class),
@ApiResponse(code = 403, message = "出错了!", response=Product.class)
})
@GetMapping(value = "/products")
public ResponseEntity<Object> getProduct() {
return new ResponseEntity<>(productService.getProducts(), HttpStatus.OK);
}复制代码
效果以下:
@Deprecated
: 做用于控制器方法上,标注该方法已通过时,建议开发者采用新的方式之类的。 @ApiModel
:做用在JavaBean类上,说明JavaBean的用途,如咱们定义的Product.java类。经常使用参数设置以下: 示例:
@ApiModel(value="Product",description="对产品定义的描述")
public class Product { ... }复制代码
@ApiModelProperty
: 一样用于在JavaBean类的属性上面,说明相关属性。相似于方法上说明的@ApiImplicitParam
。设置参数有: 管理不一样API版本有好几种方式:
/api/v1/users
。经过这种方式,咱们能够在Docket中过滤出不一样版本,结合分组,能够实现不一样版本的API管理。 /api/users?version=1
curl -H "Accept: application/vnd.piomin.v1+json" http://localhost:8080/api/users
这里咱们对第一种方式示例展现:
在Swagger2Config.java中新添加一个用户API Docket:
@Configuration
@EnableSwagger2
public class Swagger2Config {
@Bean("UsersApis_V1")
public Docket usersApisV1() {
return new Docket(DocumentationType.SWAGGER_2)
.groupName("用户管理接口V1")
.select()
.apis(RequestHandlerSelectors.basePackage("com.xiaobaiai.user"))
.paths(Predicates.or(
// 过滤版本v1
PathSelectors.ant("/api/v1/users/**"),
PathSelectors.ant("/api/v1/users/*")))
.build()
.host("https://xiaobaiai.net")
.pathProvider(new RelativePathProvider(null) {
@Override
public String getApplicationBasePath() {
return "/prefix";
}
})
.apiInfo(apiInfo());
}
@Bean("UsersApis_V21")
public Docket usersApisV2() {
return new Docket(DocumentationType.SWAGGER_2)
.groupName("用户管理接口V2")
.select()
.apis(RequestHandlerSelectors.basePackage("com.xiaobaiai.user"))
.paths(Predicates.or(
// 过滤版本v1
PathSelectors.ant("/api/v2/users/**"),
PathSelectors.ant("/api/v2/users/*")))
.build()
.host("https://xiaobaiai.net")
.pathProvider(new RelativePathProvider(null) {
@Override
public String getApplicationBasePath() {
return "/prefix";
}
})
.apiInfo(apiInfo());
}
@Bean
public Docket productsApis() {
return new Docket(DocumentationType.SWAGGER_2)
.....
}
public ApiInfo apiInfo() {
final Contact contact = new Contact(
"Ethan", "https://xiaobaiai.net", "ycm_hy@163.com");
return new ApiInfoBuilder()
.title("X系统平台接口文档")
.description("用户/产品相关API, 更多请关注公众号: 小白AI 或微信小程序:小白AI博客")
.termsOfServiceUrl("https://github.com/yicm")
.version("1.0")
.contact(contact)
.licenseUrl("http://license.coscl.org.cn/MulanPSL")
.license("MulanPSL")
.build();
}
}复制代码
而后控制器添加新版本API方法:
@RestController
@RequestMapping("/api")
public class UserServiceController {
@Autowired
UserService userService;
@DeleteMapping({"/v1/users/{id}", "/v2/users/{id}"})
public ResponseEntity<Object> delete(@PathVariable("id") String id) {
userService.deleteUser(id);
return new ResponseEntity<>("User is deleted successsfully", HttpStatus.OK);
}
@PutMapping({"/v1/users/{id}", "/v2/users/{id}"})
public ResponseEntity<Object> updateUser(@PathVariable("id") String id, @RequestBody User user) {
userService.updateUser(id, user);
return new ResponseEntity<>("User is updated successsfully", HttpStatus.OK);
}
@PostMapping({"/v1/users", "/v2/users"})
public ResponseEntity<Object> createUser(@RequestBody User user) {
userService.createUser(user);
return new ResponseEntity<>("User is created successfully", HttpStatus.CREATED);
}
@GetMapping({"/v1/users"})
@Deprecated
public ResponseEntity<Object> getUser() {
return new ResponseEntity<>(userService.getUsers(), HttpStatus.OK);
}
@GetMapping(value = "/v2/users")
public ResponseEntity<Object> getUser(@RequestParam String id) {
return new ResponseEntity<>(userService.getUsers(), HttpStatus.OK);
}
}复制代码
最后效果:
其余的方式相似也差很少,如在Header中区分版本,这里就不展开了。
当咱们的REST API加入的受权机制时,即需具备对该API的访问权限,才可以操做该API,可是咱们想在Swagger UI中去调试API,那么如何解决每一个API一次性受权,所有API可访问呢?增长使用的方便性,不用每次都对每一个API进行受权。不过须要在WEB服务中已经使用了API受权机制才会须要这项配置。这里暂不展开,后面单独讲述Spring Security
+ Swagger2 UI
配置。
应该是不能的: https://github.com/swagger-api/swagger-ui#known-issues
这一篇从介绍Swagger2入手,讲述在Spring Boot中如何集成和配置Swagger2,并生成生成环境中的在线API文档,包括如何将API分组,组信息描述,API信息描述,API方法参数描述,若是对API版本进行管理等,最后还扩展了内容,包括如何为每一个API配置全局Token等。内容很全,参考这一篇应该是够了,继续!
本文属于原创,转载注明出处,欢迎关注CSDNfreeape或微信小程序小白AI博客
微信公众号小白AI
或者网站 xiaobaiai.net