Swagger ?
- 什么是Swagger?官网首页如下介绍
Swagger is the world’s largest framework of API developer tools for the OpenAPI Specification(OAS), enabling development across the entire API lifecycle, from design and documentation, to test and deployment. (Swagger是世界上最大的基于OAS规范的API开发工具集框架,允许开发者贯穿整个API生命周期,从设计到文档,测试至部署)
Swagger项目下主要包含了有swagger-editor、swagger-ui、swagger-Specification、swagger-Swagger Codegen
几个项目,每个项目的作用、使用在官网都有详细介绍和帮助文档,可自行查阅。
本文要点摘要
- 简单介绍swagger-editor
- 使用swagger-editor和预定义的文档规范生成相应的Java服务端代码。并逐一介绍生成的代码。
1. swagger-editor
swagger-editor ?
swagger-editor
可以理解为是一个以OpenAPI规范来编写初始化文档一种预定义文档编辑器,其支持的类型主要有json、yaml
两种文档格式,如果对于这两种文档格式有不了解的可以百度搜索,有很多相关的介绍和教程。我们将编辑好的预定义文档粘贴如swagger-editor中,便可以利用swagger-codegen来生成相应的服务端或者客户端代码。一些有用的链接(强烈推荐)
- swagger 预定义文档的编写详细介绍,参考1:swagger从入门到精通
- 阮一峰老师的yaml的基本语法,参考2:YAML 语言教程
熟悉以上推荐的两个教程以后,下面的工作就是手到擒来的事儿了。下面我假设您已经对swagger预定义文档和yaml有一定程度了解,至少能读懂相应代码,了解其意义了。
swagger-editor图解
面板分为两个区域,左边是基于OpenAPI规范的预定义文档,右边是根据预定义文档生成的API文档预览,顶上工具栏部分为一些功能,可以上传本地定义好的文档,将其他类型文档转换为YAML文档,根据文档生成各种语言和框架的服务端和客户端代码,但是官网的在线版本有一个bug,如下所示
具体含义大致是因为混用https和http导致请求被锁定,无法完成代码生成的工作,所以我们使用离线版本,离线版本的安装运行请参照,参考3:swagger-editor离线版下载及使用说明
文档中下载时使用的时wget
链接为wget https://github.com/swagger-api/swagger-editor/releases/download/v2.10.4/swagger-editor.zip
在linux上,直接复制到命令行便可运行,当在windows上操作时直接将链接地址
https://github.com/swagger-api/swagger-editor/releases/download/v2.10.4/swagger-editor.zip
复制到浏览器便可以下载,下载后解压,然后按照说明进行相应操作便可。启动后界面和在线版一样。
例子使用的预定义文档
swagger: '2.0'
info:
version: 1.0.0
title: Simple API
description: A simple API to learn how to write OpenAPI Specification
schemes:
- https
host: simple.api
basePath: /openapi101
paths:
/persons:
get:
summary: get a person by username
description: get a person
parameters:
- name: username
in: query
description: a user's name
required: true
type: string
format: string
responses:
'200':
description: a person
schema:
type: object
items:
properties:
username:
type: string
address:
type: string
birthday:
type: string
该文档定义了一个名/persons
的接口,其访问地址为:https://simple.api/openapi101/persons?username=
定义类get
方法,该方法需要一个string类型的参数,该接口返回200时返回一个对象,对象里包含了person的详细信息。
将以上内容输入swagger-editor以后,会在右边生成文档预览如下图所示:
然后我们选择要生成的接口代码类型generate server - spring
生成java接口我们选择spring而不选择java语言,选择spring时生成的接口代码是集成Swagger
和SpringBoot
的,目前Java开发API大多利用SrpingBoot
来进行开发,若想了解其区别可分别选择java和spring下载生成的服务端代码。下载完代码解压后如图所示:
可以删除.swagger-codgen
相关的东西,只保留pom.xml
和src
目录下的内容
下面我们使用maven
将项目打包如图所示
打包成功以后进入target
目录运行生成的jar包
等到项目启动成功之后访问:http://localhost:8081/openapi101/
(因为我启动http-server时占用了8080端口,所以已经提前将src/main/resource/application.properties中的server.port改为8081
)效果如图所示
我们的第一个基于swagger和spring的接口便完成了。后面我们分析代码
2. 生成代码分析
- 生成代码结构
Springboot和Swagger集成以及配置:Swagger2SpringBoot.java
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@SpringBootApplication
@EnableSwagger2
@ComponentScan(basePackages = { "io.swagger", "io.swagger.api" })
public class Swagger2SpringBoot implements CommandLineRunner {
@Override
public void run(String... arg0) throws Exception {
if (arg0.length > 0 && arg0[0].equals("exitcode")) {
throw new ExitException();
}
}
public static void main(String[] args) throws Exception {
new SpringApplication(Swagger2SpringBoot.class).run(args);
}
class ExitException extends RuntimeException implements ExitCodeGenerator {
private static final long serialVersionUID = 1L;
@Override
public int getExitCode() {
return 10;
}
}
}
该类的主要作用是SpringBoot的启动类,除了SpringBoot的注解之外,添加了Swagger2的注解@EnableSwagger2
以提供对Swagger的支持。
日期转换类 RFC3339DateFormat.java
public class RFC3339DateFormat extends ISO8601DateFormat {
// Same as ISO8601DateFormat but serializing milliseconds.
@Override
public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition) {
String value = ISO8601Utils.format(date, true);
toAppendTo.append(value);
return toAppendTo;
}
}
文档页面跳转 configuration/HomeController.class ,具体作用注释和代码已经写得很明白了
/**
* Home redirection to swagger api documentation
*/
@Controller
public class HomeController {
@RequestMapping(value = "/")
public String index() {
System.out.println("swagger-ui.html");
return "redirect:swagger-ui.html";
}
}
Swagger文档配置 configuration/SwaggerDocumentationConifg.java
// 该注解是swagger-codgen在生成代码时自动加入的,没有实际用于,主要是用于标记,标识区分swagger自动生成的类和后期开发中开发者写得类,可以删除不用。
@javax.annotation.Generated(value = "io.swagger.codegen.languages.SpringCodegen", date = "2017-10-14T15:20:48.971Z")
@Configuration
public class SwaggerDocumentationConfig {
//里面的字段有没有很熟悉的感觉?这就是我们预定义文档中相应的值,用于生成文档的,设置文档的基本信息。
ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("Simple API")
.description("A simple API to learn how to write OpenAPI Specification")
.license("")
.licenseUrl("http://unlicense.org")
.termsOfServiceUrl("")
.version("1.0.0")
.contact(new Contact("","", ""))
.build();
}
//设置文档类型,载入文档基本信息
@Bean
public Docket customImplementation(){
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage("io.swagger.api"))
.build()
.directModelSubstitute(org.joda.time.LocalDate.class, java.sql.Date.class)
.directModelSubstitute(org.joda.time.DateTime.class, java.util.Date.class)
.apiInfo(apiInfo());
}
}
跨域处理和请求方法处理的类api/ApiOriginFilter.java 该类实现了java.servlet.Filter接口
public class ApiOriginFilter implements javax.servlet.Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletResponse res = (HttpServletResponse) response;
//设置跨域信息和允许的请求方法等请求头信息。
res.addHeader("Access-Control-Allow-Origin", "*");
res.addHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
res.addHeader("Access-Control-Allow-Headers", "Content-Type");
chain.doFilter(request, response);
}
@Override
public void destroy() {
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
}
最后两个需要介绍的是我们要的API api/PersonsApi.java 接口和其实现 api/PersonsApiController.java
//这是我们在预定于文档中指定的person的pai接口
@javax.annotation.Generated(value = "io.swagger.codegen.languages.SpringCodegen", date = "2017-10-14T15:20:48.971Z")
//该注解的描述是我们在预定于的yaml文档中编写的可以参照上面的yaml文档来理解以下的注释及其含义,里面设置到的spring相关的东西就不在赘述了。
@Api(value = "persons", description = "the persons API")
public interface PersonsApi {
@ApiOperation(value = "get a person by username", notes = "get a person", response = Object.class, tags={ })
@ApiResponses(value = {
@ApiResponse(code = 200, message = "a person", response = Object.class) })
@RequestMapping(value = "/persons",
method = RequestMethod.GET)
ResponseEntity<Object> personsGet( @NotNull@ApiParam(value = "a user's name", required = true) @RequestParam(value = "username", required = true) String username);
}
//这是person api的实现
@javax.annotation.Generated(value = "io.swagger.codegen.languages.SpringCodegen", date = "2017-10-14T15:20:48.971Z")
@Controller
public class PersonsApiController implements PersonsApi {
public ResponseEntity<Object> personsGet( @NotNull@ApiParam(value = "a user's name", required = true) @RequestParam(value = "username", required = true) String username) {
// !ResponseEntity有多个构造方法,每个构造方法及其含义请参考其API文档。都写得很简单。在此也不在说了。可以利用其提供的构造方法来返回接口调用所需要的数据
return new ResponseEntity<Object>(HttpStatus.OK);
}
}
除了以上几个类之外,swagger-codgen还生成了一些处理异常的类,这个大家自己查看吧。!
总结
其实这个东西就是帮助我们了解Swagger框架,帮助我们快速入门和开发,接口都可以由预定义文档结合swagger-editor(实际代码生成是用swagger-codgen)来自动生成,我们只需要塞入相应的业务逻辑便可。我们理解了swagger-editor这个东西以后至少解决了有两个问题:
1:如何使用swagger来自动生成接口文档和接口
2:如何在项目中集成swagger(无论什么语言,无论什么框架,只要在其支持的基础之上)–只需要选择相应的客户端/客户端代码便可,swagger-codgen会自动集成,然后我们再基于其代码来集成便可,下次便不用费这么多功夫来解决集成的问题了。