Swagger相关技术栈

勤奋不是嘴上说说而已,而是实际的行动,在勤奋的苦度中持之以恒,永不退却。业精于勤,荒于嬉;行成于思,毁于随。在人生的仕途上,我们毫不迟疑地选择勤奋,她是几乎于世界上一切成就的催产婆。只要我们拥着勤奋去思考,拥着勤奋的手去耕耘,用抱勤奋的心去对待工作,浪迹红尘而坚韧不拔,那么,我们的生命就会绽放火花,让人生的时光更加的闪亮而精彩。

导读:本篇文章讲解 Swagger相关技术栈,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

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

Swagger

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

OAS,Open API Specification,一套规范,定义该如何去描述一个RESTful API,参考OAS GitHub

从Swagger的GitHub可知,主要包括四个模块。

Swagger-UI

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

Swagger-codegen

swagger-codegen,用于生成客户端代码。

Swagger-editor

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

Swagger-core

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

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

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

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

鉴于Spring在Java世界No.1的统治地位,基于Spring,将swagger集成到spring mvc中来的组件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>
</dependency>
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
</dependency>

入门实例

  1. 添加 swagger 配置类,Springfox通过定义Docket对象来全局的定义API的一些属性:
@SpringBootApplication
@EnableSwagger2
@ComponentScan(basePackageClasses = {
	DemoController.class
})
public class Swagger2SpringBoot {

	@Autowired
	private TypeResolver typeResolver;

	@Bean
	private SecurityConfiguration security() {
		return new SecurityConfiguration(
		"test-app-client-id",
		"test-app-realm",
		"test-app",
		"apiKey");
	}
	
	@Bean
	private UiConfiguration uiConfig() {
		return new UiConfiguration("validatorUrl");
	}

	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()));
	}
	
	private SecurityContext securityContext() {
		return SecurityContext.builder()
			.securityReferences(this.defaultAuth())
			.forPaths(PathSelectors.regex("/anyPath.*"))
			.build();
	}
	
	private List<SecurityReference> defaultAuth() {
		AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
		AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
		authorizationScopes[0] = authorizationScope;
		return newArrayList(new SecurityReference("mykey", authorizationScopes));
	}

	private ApiKey apiKey() {
		return new ApiKey("mykey", "api_key", "header");
	}

}
  1. 然后需要对controller层接口添加注解:

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

关闭

默认情况下,在开发环境才需要做接口联调,暴露出API,生产环境需要关闭这个URL暴露出来的信息。参考stackoverflow的解决方法:很简单

@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文档。参考其GitHub,Swagger2Markup开源项目主要用来将Swagger自动生成的文档转换成几种流行的格式以便于静态部署和使用:AsciiDoc、Markdown、Confluence。

入门

生成AsciiDoc

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

Java API

<dependency>
    <groupId>io.github.swagger2markup</groupId>
    <artifactId>swagger2markup</artifactId>
</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文档管理系统里。

Swagger 3.0

支持 OpenAPI

OpenAPI(GitHub)规范,即之前的Swagger规范,一种REST API的描述格式,通过既定的规范来描述文档接口,它是业界真正的 API 文档标准,可通过 YAML 或 JSON 来描述,包括如下内容:

  • 接口和每个接口的操作
  • 输入参数和响应内容
  • 认证方法
  • 一些必要的联系信息、license 等。

依赖

以前在使用2.9.2版本时,一般来说可能需要添加两个依赖:

<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>

分别用来生成接口JSON文档,和可视化。

3.0版本一个starter:

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

和SB中的starter 一样,springfox-boot-starter 依赖可以实现零配置以及自动配置支持。

接口地址

3.0中的接口地址也和之前有所不同,在 2.9.2 以前的版本中主要访问两个地址:
文档接口地址:http://localhost:8080/v2/api-docs
文档页面地址:http://localhost:8080/swagger-ui.html

3.0中:
文档接口地址:http://localhost:8080/v3/api-docs
文档页面地址:http://localhost:8080/swagger-ui/index.html

注解

旧的注解还可以继续使用,部分注解的包路径有所变更,3.0新增注解。
可用 @EnableOpenApi 代替以前旧版本中的 @EnableSwagger2。@EnableOpenApi 注解主要功能是为了导入 OpenApiDocumentationConfiguration 配置类:

@Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
@Target(value = {java.lang.annotation.ElementType.TYPE})
@Documented
@Import(OpenApiDocumentationConfiguration.class)
public @interface EnableOpenApi {
}

自动化配置类 OpenApiAutoConfiguration:

@Configuration
@EnableConfigurationProperties(SpringfoxConfigurationProperties.class)
@ConditionalOnProperty(value = "springfox.documentation.enabled", havingValue = "true", matchIfMissing = true)
@Import({
    OpenApiDocumentationConfiguration.class,
    SpringDataRestConfiguration.class,
    BeanValidatorPluginsConfiguration.class,
    Swagger2DocumentationConfiguration.class,
    SwaggerUiWebFluxConfiguration.class,
    SwaggerUiWebMvcConfiguration.class
})
@AutoConfigureAfter({ WebMvcAutoConfiguration.class, JacksonAutoConfiguration.class,
    HttpMessageConvertersAutoConfiguration.class, RepositoryRestMvcAutoConfiguration.class })
public class OpenApiAutoConfiguration {
}

自动化配置类里边也导入 OpenApiDocumentationConfiguration。
在正常情况下,实际上不需要添加 @EnableOpenApi 注解。

根据 OpenApiAutoConfiguration 上的 @ConditionalOnProperty 条件注解中的定义,发现如果在application.properties中设置springfox.documentation.enabled=false,即关闭swagger 功能,此时自动化配置类就不执行,这个时候可以通过 @EnableOpenApi 注解导入 OpenApiDocumentationConfiguration 配置类。技术上来说逻辑是这样,不过应用中暂未发现这样的需求(即在application.properties中关闭 swagger,再通过 @EnableOpenApi 注解开启)。

参考

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/142309.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!