文章目录
Swagger
学习目标:
- 了解 Swagger 的概念以及作用
- 了解前后端分离
- 在 SpringBoot 中集成 Swagger
1、前后端分离
1.1 未分离时期
早期前后端未分离时期,通常都是使用传统的 MVC 架构,通过 JSP 和 Servlet 来实现
所有的请求都被发送给作为控制器的 Servlet,它接受请求,并根据请求信息将它们分发给适当的 JSP 来响应。同时,Servlet 还根据 JSP 的需求生成 JavaBeans 的实例并输出给 JSP 环境。JSP 可以通过直接调用方法或使用 UseBean 的自定义标签得到 JAVABeans 中的数据。需要说明的是,这个 View 还可以采用 Velocity、Freemaker 等模板引擎。使用了这些模板引擎,可以使得开发过程中的人员分工更加明确,还能提高开发效率。
那么,在这个时期,开发方式有如下两种:
方式一
:
方式二
:
方式二已经逐渐淘汰。主要原因有两点:
- 前端在开发过程中严重依赖后端,在后端没有完成的情况下,前端根本无法干活。
- 由于趋势问题,会JSP,懂velocity,freemarker的前端越来越少。
因此,方式二逐渐不被采用。然而,不得不说一点,方式一,其实很多小型传统软件公司至今还在使用。那么,方式一和方式二具有哪些共同的缺点呢?
-
前端无法单独调试
在项目上线后,遇到一些问题。比如样式出问题了,由于前端不具备项目开发环境,那么就有可能出现如下对话
前端 :“我这里没问题啊。后端,你那里正常么?”
后端 :“我这里不正常啊。要不你过来看一下吧?”
前端 :“一时我也看不出问题,我也没环境,怎么办?”
后端 :“你没环境,坐我这边调吧。”
然后,前端就满脸不爽的在你那调代码了。更有些情商低的后端就直接在旁边开摁手机,实在是。。。。。总结,因为前端无法单独调试。一方面开发效率降低。另一方面,还有可能引发公司内部人员上的矛盾。
-
前端不可避免会遇到后台代码
比如前端可能碰到如下结构的代码
<body> <% request.setCharacterEncoding("utf-8"); String name=request.getParameter("username"); out.print(name); %> </body>
身为前端,在页面里看到了后台代码,必然内心是十分不快的,这种方式
耦合性太强
。那么,就算你用了 freemarker 等模板引擎,不能写 JAVA 代码。那前端也不可避免的要去重新学习该模板引擎的模板语法,无谓增加了前端的学习成本。
正如我们后端开发不想写前端一样,你想想如果你的后台代码里嵌入前端代码,你是什么感受?因此,这种方式十分不妥。 -
JSP本身所导致的一些其他问题
比如,JSP 第一次运行的时候比较缓慢,因为里头包含一个翻译为 Servlet 的步骤。再比如因为同步加载的原因,在 jsp 中有很多内容的情况下,页面响应会很慢。
1.2 半分离时期
前后端半分离,前端负责开发页面,通过接口(Ajax)获取数据,采用 dom 操作对页面进行数据绑定,最终是由前端把页面渲染出来。这也就是其他博客里说的,Ajax 与 SPA 应用(单页应用)结合的方式。其结构图如下:
步骤如下:
- 浏览器请求,cdn 返回 html 页面
- html 中的 js 代码以 ajax 方式请求后台的 restful 接口
- 接口返回 json 数据,页面解析 json 数据,通过 dom 操作渲染页面
为什么说是半分离的?
因为不是所有页面都是单页面应用,在多页面应用的情况下,前端因为没有掌握 controller 层,前端需要跟后端讨论,我们这个页面是要同步输出呢,还是异步 json 渲染呢?因此,在这一阶段,只能算半分离。
这种方式的优缺点有哪些呢?
首先,这种方式的优点是很明显的。前端不会嵌入任何后台代码,前端专注于 html、css、js 的开发,不依赖于后端。自己还能够模拟 json 数据来渲染页面。发现 bug,也能迅速定位出是谁的问题,不会出现互相推脱的现象。
然而,在这种架构下,还是存在明显的弊端的。最明显的有如下几点:
- js 存在大量冗余,在业务复杂的情况下,页面的渲染部分的代码,非常复杂。
- 在 json 返回的数据比较大的情况下,渲染的十分缓慢,会出现页面卡顿的情况
- seo 非常不方便,由于搜索引擎的爬虫无法爬下js异步渲染的数据,导致这样的页面,SEO 会存在一定的问题。
- 资源消耗严重,在业务复杂的情况下,一个页面可能要发起多次 http 请求才能将页面渲染完毕。可能有人不服,觉得 pc 端建立多次 http 请求也没啥。那你考虑过移动端么,知道移动端建立一次 http 请求需要消耗多少资源么?
正是因为如上缺点,真正的前后端分离架构诞生了
1.3 分离时期
在这一时期,扩展了前端的范围。认为 controller 层也属于前端的一部分。在这一时期
-
前端:负责 View(视图层) 和 Controller 层(前端控制层)。
-
可以伪造后端数据(Json)
-
-
后端:只负责后端控制层,服务层,数据访问层。
-
前后端通过 API 进行交互
-
前后端相对独立,松耦合
-
前后端可以部署到不同的服务器上
前后端分离产生的问题
:
-
前后端集成联调,前端人员和后端人员无法做到
及时协商,建造解决
,最终导致问题的集中爆发
解决方案
:
- 要制定好 schema(计划提纲),实时更新最新的 API,降低集成的风险
- 前端测试后端接口:postman 等等
- 后端提供接口,需要实时更新最新的消息以及改动
前后端分离的窘境从而孕育了一个框架的出现,Swagger!
2、Swagger 简介
Swagger 号称为世界上最为流行的 API 框架
Swagger 是一个规范且完整的框架,用于生成、描述、调用和可视化 RestFul 风格的 Web 服务。
Swagger 的目标是对 Rest API 定义一个标准且和语言无关的接口,可以让人和计算机拥有无须访问源码、文档或网络流量监测就可以发现和理解服务的能力。当通过 Swagger 进行正确定义,用户可以理解远程服务并使用最少实现逻辑与远程服务进行交互。与为底层编程所实现的接口类似,Swagger 消除了调用服务时可能会有的猜测。
Swagger 的优势
:
- 流行的 API 框架
- RestFul API 文档在线自动生成工具(支持 API 自动生成同步的在线文档,API 文档与 API 定义同步更新)
- 提供 Web 页面在线测试 API(参数和格式都定好了,直接在界面上输入参数对应的值即可在线测试接口)
- 支持多种语言:Java、Php 等等
3、SpringBoot 集成 Swagger
Swagger 官网:
https://swagger.io
使用 Swagger 需要:
- springfox
- swagger2
- ui
集成 Swagger 步骤
:
-
新建一个 SpringBoot 项目(Web 项目)
-
编写一个 hello 程序,测试一下
-
导入相关依赖
-
swagger2
<dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.9.2</version> </dependency>
-
swagger-ui
<dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.9.2</version> </dependency>
-
-
配置 Swagger 的配置文件(SwaggerConfig)
-
最简洁的 SwaggerConfig 配置文件
@Configuration // 等价于 Component @EnableSwagger2 // 开启 Swagger2 public class SwaggerConfig { }
看上去什么都没配置,其实有很多默认的配置
-
-
测试运行,访问
http://localhost:8080/swagger-ui.html
4、配置 Swagger
在 Swagger 配置文件中,配置 Swagger 的 Docket 的 bean 实例,通过源码可知,同时可以配置 apiInfo等等的信息,如下:
// 默认配置
public Docket(DocumentationType documentationType) {
this.apiInfo = ApiInfo.DEFAULT;
this.groupName = "default";
this.enabled = true;
this.genericsNamingStrategy = new DefaultGenericTypeNamingStrategy();
this.applyDefaultResponseMessages = true;
this.host = "";
this.pathMapping = Optional.absent();
this.apiSelector = ApiSelector.DEFAULT;
this.enableUrlTemplating = false;
this.vendorExtensions = Lists.newArrayList();
this.documentationType = documentationType;
}
手动配置
package com.aze.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.util.ArrayList;
@Configuration // 等价于 Component
@EnableSwagger2 // 开启 Swagger2
public class SwaggerConfig {
// 配置 Swagger 的 Docket 的 bean 实例
@Bean
public Docket docket(){
return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo());
}
// 配置 Swagger 信息:apiInfo
private ApiInfo apiInfo(){
// 作者信息
Contact contact = new Contact("开完喜", "https://blog.csdn.net/qq_34172440?spm=1001.2014.3001.5343", "aze1031952566@163.com");
return new ApiInfo("阿泽的 Swagger API 文档"
, "卟卟车"
, "v1.0"
, "https://blog.csdn.net/qq_34172440?spm=1001.2014.3001.5343"
, contact
, "Apache 2.0"
, "http://www.apache.org/licenses/LICENSE-2.0"
, new ArrayList());
}
}
配置完成后,访问
http://localhost:8080/swagger-ui.html
进行测试
5、Swagger 配置扫描接口
docket.select().apis().paths().build()
- se;ect().build():这是一套东西,apis 以及 paths 都只能在其中间添加
-
apis():配置扫描的方式
-
RequestHandlerSelectors:配置要扫描接口的方式
- basePackage:指定要扫描的包
- any():扫描所有
- none():都 不扫描
-
withClassAnnotation():扫描类上的注解,需要指定参数,参数是一个注解的反射对象,例如:
RestController.class
- withMethodAnnotation():扫描方法上的注解,也是需要指定方法上注解的反射对象
-
RequestHandlerSelectors:配置要扫描接口的方式
-
paths():配置过滤的方式
-
PathSelectors:配置过滤路径的方式
- ant():指定路径
- any():过滤所有
- none():都不过滤
-
PathSelectors:配置过滤路径的方式
// 配置 Swagger 的 Docket 的 bean 实例
@Bean
public Docket docket(){
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.aze.controller"))
.paths(PathSelectors.ant("/aze/**"))
.build();
}
6、配置是否启动 Swagger
enable()
:是否启动 Swagger,如果为 false 则不能在浏览器中访问 Swagger
// 配置 Swagger 的 Docket 的 bean 实例
@Bean
public Docket docket(){
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
// enable():是否启动 Swagger,如果为 false 则不能在浏览器中访问 Swagger
.enable(false)
.select()
.apis(RequestHandlerSelectors.basePackage("com.aze.controller"))
//.paths(PathSelectors.ant("/aze/**"))
.build();
}
开发过程问题:怎样使 Swagger 在生产环境中使用,在发布的时候不使用?
-
判断是否是生产环境
-
注入 enable(flag)
步骤:
-
在 resource 目录下,修改并添加配置文件
-
application-dev.yaml(生产环境)
server: port: 8081
-
application-pro.yaml(发布环境)
server: port: 8082
-
application.yaml
# 选择环境 spring: profiles: active: dev
-
-
修改 Swagger 的配置文件
// 配置 Swagger 的 Docket 的 bean 实例 @Bean public Docket docket(Environment environment){ // 设置需要显示 Swagger 的环境 Profiles profiles = Profiles.of("dev"); // 通过 boolean flag = environment.acceptsProfiles(profiles); return new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo()) // enable():是否启动 Swagger,如果为 false 则不能在浏览器中访问 Swagger .enable(flag) .select() .apis(RequestHandlerSelectors.basePackage("com.aze.controller")) //.paths(PathSelectors.ant("/aze/**")) .build(); }
-
测试
-
7、配置 API 文档的分组
groupName(“组名”)
.groupName("aze")
问题:协同开发中,如何配置多个分组?
-
配置多个 Docket 实例,放入 Bean 容器中即可
@Bean public Docket docket1(){ return new Docket(DocumentationType.SWAGGER_2).groupName("开发人员A"); } @Bean public Docket docket2(){ return new Docket(DocumentationType.SWAGGER_2).groupName("开发人员B"); } ...
8、配置注释
配置实体类注释
- @Api(“注释”)
- @ApiModel(“xxx实体类”):作用于类上
- @ApiModelProperty(“xxx”):作用于属性
配置 controller 注释:
- ApiOperation(“xxx控制类”):作用于方法上
Swagger的所有注解定义在io.swagger.annotations包下
下面列一些经常用到的,未列举出来的可以另行查阅说明:
Swagger注解 | 简单说明 |
---|---|
@Api(tags = “xxx模块说明”) | 作用在模块类上 |
@ApiOperation(“xxx接口说明”) | 作用在接口方法上 |
@ApiModel(“xxxPOJO说明”) | 作用在模型类上:如VO、BO |
@ApiModelProperty(value = “xxx属性说明”,hidden = true) | 作用在类方法和属性上,hidden设置为true可以隐藏该属性 |
@ApiParam(“xxx参数说明”) | 作用在参数、方法和字段上,类似@ApiModelProperty |
拓展:不同的 UI 界面
我们可以导入不同的包实现不同的皮肤定义:
-
默认的
访问
http://localhost:8080/swagger-ui.html
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
-
bootstrap-ui
访问
http://localhost:8080/doc.html
<!-- 引入swagger-bootstrap-ui包 /doc.html-->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>swagger-bootstrap-ui</artifactId>
<version>1.9.1</version>
</dependency>
-
Layui-ui
访问
http://localhost:8080/docs.html
<!-- 引入swagger-ui-layer包 /docs.html-->
<dependency>
<groupId>com.github.caspar-chen</groupId>
<artifactId>swagger-ui-layer</artifactId>
<version>1.1.3</version>
</dependency>
-
mg-ui
访问
http://localhost:8080/document.html
<!-- 引入swagger-ui-layer包 /document.html-->
<dependency>
<groupId>com.zyplayer</groupId>
<artifactId>swagger-mg-ui</artifactId>
<version>1.0.6</version>
</dependency>