Swagger相关技术栈

背景:
简单讲述一下Swagger的产生背景,可参考博文API文档管理工具
前后端分离,各司其职,后端提供接口,契约先行的开发模式……产生如Swagger这里文档管理工具。

Swagger

Swagger是一个流行的API开发框架,这个框架以开放API声明(OAS )为基础,对整个API的开发周期都提供相应的解决方案,是一个非常庞大的项目(包括设计、编码和测试,几乎支持所有语言)。

注:OAS,OpenAPI Specification,是一套规范,定义该如何去描述一个RESTful API,其GitHub:https://github.com/OAI/OpenAPI-Specification/

从其GitHub官网可知,主要包括四个模块。

Swagger-UI

swagger-ui
生成一个Web的可交互的文档页面。

Swagger-codegen

swagger-codegen
生成客户端代码

Swagger-editor

swagger-editor
Swagger specification file可以手动编写,swagger-editor为了手动编写的工具提供预览的功能。但是实际写起来也是非常麻烦的,同时还得保持代码和文档的两边同步。于是针对各种语言的各种框架都有一些开源的实现来辅助自动生成这个`Swagger specification file。

TODO:Swagger mock API??

Swagger-core

其中,swagger-core是一个Java的实现,支持JAX-RS,现已推出版本3,主要包括下面两个GAV:

<dependency>
    <groupId>io.swagger.core.v3</groupId>
    <artifactId>swagger-core</artifactId>
    <version>2.1.1</version>
</dependency>

swagger-annotation定义一套注解给用户用来描述API,

<dependency>
    <groupId>io.swagger.core.v3</groupId>
    <artifactId>swagger-annotations</artifactId>
    <version>2.1.1</version>
</dependency>

鉴于Spring在Java世界No.1的统治地位,基于Spring,将swagger集成到springmvc中来的组件swagger-springmvc发展起来,springfox则是这个组件的二代产品。

springfox

官方文档

工作原理

在Spring中集成Swagger,即Springfox,在项目启动过程中,spring上下文在初始化的过程,框架自动根据配置加载一些Swagger相关的bean到当前的上下文中,并自动扫描swaggerconfig中配置需要生成api文档的包,并生成相应的Json格式的信息缓存起来。然后再集成Swagger-ui,将json信息可视化展示出来。
Swagger还提供相应的测试界面,自动显示json格式的响应信息,类似于PostMan的接口测试过程。

springfox支持Spring MVC, swagger-annotation定义的部分注解,框架有两部分,springfox-swagger2 提供后端实现,springfox-swagger-ui 提供前端展示实现:

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.9.2</version>
</dependency>
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.9.2</version>
</dependency>

入门实例

  1. 添加 swagger 配置类,Springfox通过定义Docket对象来全局的定义API的一些属性:
@SpringBootApplication
@EnableSwagger2
@ComponentScan(basePackageClasses = {
	DemoController.class
})
public class Swagger2SpringBoot {
	public static void main(String[] args) {
		ApplicationContext ctx = SpringApplication.run(Swagger2SpringBoot.class, args);
	}
	@Bean
	public Docket demoApi() {
		return new Docket(DocumentationType.SWAGGER_2)
			// 定义需要生成API文档的endpoint,api()方法可以通过RequestHandlerSelectors的各种选择器来选择,比如说选择所有注解@RsestController的类中的所有API e.g. .apis(RequestHandlerSelectors.withClassAnnotation(RestController.class))。path()方法可以通过PathSelectors的来匹配路径,提供regex匹配或者ant匹配
			.select()
			.apis(RequestHandlerSelectors.any())
			.paths(PathSelectors.any())
			.build()
			// 定义API的根路径
			.pathMapping("/")
			.directModelSubstitute(LocalDate.class,
			String.class)
			// 遇到对应泛型类型的外围类,直接解析成泛型类型,比如说ResponseEntity<T>,应该直接输出成类型T
			.genericModelSubstitutes(ResponseEntity.class)
			.alternateTypeRules(
			newRule(typeResolver.resolve(DeferredResult.class,
			typeResolver.resolve(ResponseEntity.class, WildcardType.class)),
			typeResolver.resolve(WildcardType.class)))
			// 是否使用默认的ResponseMessage, false则需要随后添加
			.useDefaultResponseMessages(false)
			// 全局有效
			.globalResponseMessage(RequestMethod.GET,
			newArrayList(new ResponseMessageBuilder()
			.code(500)
			.message("500 message")
			.responseModel(new ModelRef("Error"))
			.build()))
			// 定义API支持的SecurityScheme,指的是认证方式,支持OAuth、APIkey
			.securitySchemes(newArrayList(this.apiKey()))
			// 定义具体上下文路径对应的认证方式
			.securityContexts(newArrayList(this.securityContext()));
	}

	@Autowired
	private TypeResolver typeResolver;

	private ApiKey apiKey() {
		return new ApiKey("mykey", "api_key", "header");
	}
	
	private SecurityContext securityContext() {
		return SecurityContext.builder()
			.securityReferences(this.defaultAuth())
			.forPaths(PathSelectors.regex("/anyPath.*"))
			.build();
	}
	
	List<SecurityReference> defaultAuth() {
		AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
		AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
		authorizationScopes[0] = authorizationScope;
		return newArrayList(new SecurityReference("mykey", authorizationScopes));
	}
	
	@Bean
	SecurityConfiguration security() {
		return new SecurityConfiguration(
		"test-app-client-id",
		"test-app-realm",
		"test-app",
		"apiKey");
	}
	
	@Bean
	UiConfiguration uiConfig() {
		return new UiConfiguration("validatorUrl");
	}
}
  1. 然后需要对controller层接口添加注解:

    1. @ApiOperation 描述方法名称,描述
    2. @ApiResponses 描述方法发生异常时返回的code以及message
    3. @ApiImplicitParams 显示的描述方法的参数,默认情况下springfox会根据参数的@RequestParam、@PathParam等注解来自动获取参数。 但是如果没有注解则会识别为request body。方法的一些参数是由容器注入的,并不是客户端的参数。
    4. @ApiIgnore忽略
  2. 生成文档

关闭

默认情况下,我们在开发环境才需要做接口联调,暴露出我们的API,生产环境需要关闭这个URL暴露出来的信息。
很简单

@Configuration
@EnableSwagger2
@Profile("dev")
public class SwaggerConfig {
    // your swagger configuration
}

另一种稍嫌麻烦的思路是多个环境有多个配置信息不同的文件:

swagger:
  enable: true
@Value("${swagger.enable}")
private boolean enableSwagger;

@Bean 
public Docket customImplementation(){
    return new Docket(SWAGGER_2)
        .enable(enableSwagger);
}

批评

对于Swagger的批评声音:

  • 与业务无关的注解大量污染Controller代码,造成维护困难;
  • 灵活性差,部署在内网的文档的部分特定接口想要暴露给特定人(比如第三方)比较麻烦;
  • 发布生产时需要特殊处理来关闭swagger;
  • 有时会与其他jar包冲突(比如springfox-swagger2.6.0会导致注册Eureka异常)。

针对第二点,解决方法:
在这里插入图片描述

对比

分类 Swagger RAP WIKI
描述 用于生成、描述、调用和可视化RESTful风格的Web服务的框架 可视化接口管理工具 可供多人协同创作的超文本系统
格式 json json html
规范 各个参数、返回值的具体结构、类型有统一规范 同swagger 需要自己约定规范
成本 直接嵌入项目中,通过开发时编写注释,自动生成接口文档,成本较低 需要开发按照平台规则手动输入,成本较高 需要按照约定规范,手动输入,成本较高

Swagger2Markup

简介

项目背景:项目使用Swagger之后,如果需要生成文档,需要引入Swagger-UI,或使用单独部署的swagger-ui和/v2/api-docs返回的配置信息才能展现出您所构建的API文档。
官网:https://github.com/Swagger2Markup/swagger2markup
Swagger2Markup开源项目主要用来将Swagger自动生成的文档转换成几种流行的格式以便于静态部署和使用:AsciiDoc、Markdown、Confluence。

入门

生成AsciiDoc

有两种方式,Java API、Maven/Gradle plugin。:仅以maven举例,完全替换为Gradle。

Java API

<dependency>
    <groupId>io.github.swagger2markup</groupId>
    <artifactId>swagger2markup</artifactId>
    <version>1.3.3</version>
</dependency>
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
public class DemoApplicationTests {
    @Test
    public void generateAsciiDocs() throws Exception {
        // 输出Ascii格式
        Swagger2MarkupConfig config = new Swagger2MarkupConfigBuilder()
        		// 指定要输出的最终格式,还有MARKDOWN和CONFLUENCE_MARKUP
                .withMarkupLanguage(MarkupLanguage.ASCIIDOC)
                .build();
         // 指定生成静态部署文档的源头配置,可以是这样的URL形式,也可以是符合Swagger规范的String类型或者从文件中读取的流。如果是对当前使用的Swagger项目,通过使用访问本地Swagger接口的方式,如果是从外部获取的Swagger文档配置文件,就可以通过字符串或读文件的方式
        Swagger2MarkupConverter.from(new URL("http://localhost:8080/api-docs"))
                .withConfig(config)
                .build()
                // 指定最终生成文件的具体目录位置
                .toFolder(Paths.get("src/docs/asciidoc/generated"));
                // 输出到单个文件, 最终生成html也是单一的
                .toFile(Paths.get("src/docs/asciidoc/generated/all"));
    }
}

最后生成的目录:

src
--docs
----asciidoc
------generated
--------definitions.adoc
--------overview.adoc
--------paths.adoc
--------security.adoc

生成4个不同的静态文件,文件名后缀.adoc
静态文档可以通过Swagger2MarkupResultHandler执行生成asciidoc或者SwaggerResultHandler生成swagger.json,ResultHandler的使用要配合Spring Test Framework。

Maven plugin

将json文件转为asciidoc

<plugin>
    <groupId>io.github.swagger2markup</groupId>
    <artifactId>swagger2markup-maven-plugin</artifactId>
    <version>1.3.7</version>
    <configuration>
        <swaggerInput>http://localhost:8080/api-docs</swaggerInput>
        <outputDir>src/docs/asciidoc/generated</outputDir>
        <config>
            <swagger2markup.markupLanguage>ASCIIDOC</swagger2markup.markupLanguage>
        </config>
    </configuration>
</plugin>

生成HTML

完成从Swagger文档配置文件到AsciiDoc的源文件转换之后,可进一步借助于Maven插件将AsciiDoc转换成可部署的HTML(pdf)内容:

<plugin>
    <groupId>org.asciidoctor</groupId>
    <artifactId>asciidoctor-maven-plugin</artifactId>
    <version>1.5.6</version>
    <configuration>
           <sourceDirectory>src/docs/asciidoc/generated</sourceDirectory>
           <outputDirectory>src/docs/asciidoc/html</outputDirectory>
           <backend>html</backend>
           <sourceHighlighter>coderay</sourceHighlighter>
           <attributes>
           		<toc>left</toc>
          </attributes>
      </configuration>
</plugin>

执行该插件的asciidoctor:process-asciidoc命令后,就能在 src/docs/asciidoc/html目录下生成最终可用的静态部署HTML。Spring Cloud的E版之前的文档也是这样的!

生成Markdown

修改withMarkupLanguage、toFolder参数,文件名后缀.md。Markdown文件,有很多静态部署工具,如Hexo、Jekyll。

生成Confluence

同上,修改withMarkupLanguage、toFolder参数,文件名后缀.txt。生成的txt文档,可以归归档到团队内部的Confluence文档管理系统里。

原创文章 131 获赞 175 访问量 32万+

猜你喜欢

转载自blog.csdn.net/lonelymanontheway/article/details/104442863