
前后端分离:
前后端分离产生一个问题:
解决方案:
接口文档对于前后端开发人员都十分重要。尤其近几年流行前后端分离后接口文档又变成重中之重。接口文档固然重要,但是由于项目周期等原因后端人员经常出现无法及时更新,导致前端人员抱怨接口文档和实际情况不一致。
很多程序员会抱怨别人写的接口文档不规范,不及时更新。但自己写的时候也觉得烦——太痛苦了。如果接口文档可以实时动态生成就不会出现上面问题。
Swagger可以完美解决上面的问题。
Open API 规范(OpenAPI Specification) 以前叫做 Swagger规范,是 REST API的 API 描述格式。(REST 请求路径传参 /loging/admin/123 GET 描述读 POST描述写(增删改) POST新增 PUT修改 DELETE 删除)
Open API文件允许描述整个API,包括:
Open API 规范可以使用YAML 或 JSON格式进行编写。YAML( 空格 描述 ) 或 JSON( {} [] 描述)格式编写的字符串数据,人和机器都能看懂,这样更利于我们和机器进行阅读。
OpenAPI规范(OAS)为REST API 定义了一个与语言无关的标准接口,允许人和计算机发现和理解服务的功能,而无需访问源代码,文档或通过网络流量检查。正确定以后,消费者可以最有效的实现逻辑来理解远程服务并与之交互。
然后,文档生成工具可以使用OpenAPI定义来显示API,使用各种编程语言生成服务器和客户端的代码生成工具,测试工具以及许多其他用例。
Swagger是一套围绕Open API 规范构建的开源工具,可以帮助设计,构建,记录和使用REST API。
Swagger 工具包括的组件:
使用Swagger,就是把相关信息存储在它定义的描述文件里面(yml和json格式),再通过维护整个描述文件可以去更新接口文档,以及生成各端代码。

使用Swagger时如果碰见版本更新或迭代时,只需要更改Swagger的描述文件即可。但是在频繁的更新项目版本时很多开发人员认为及时修改描述文件(yml或json)也是一定的工作负担,久而久之就又开始修改代码,不去修改描述文件了,这样基于描述文件生成接口文档也失去了意义。
工程师 Marty Pitt 编写了一个基于Spring 的组件 swagger-springmvc ,通过扫描一些自定义的注解完成编写描述文件(yml或json)。Spring-fox就是根据这个组件发展而来的全新项目(该项目不属于Spring旗下项目)。
Spring-fox是根据代码生成接口文档,所以正常的进行更新项目版本,修改代码即可,而不需要跟随修改描述文件。
Spring-fox利用自身AOP特性,把Swagger集成进来,底层还是Swagger。但是使用起来的确方便很多。
所以在实际开发中,都是直接使用spring-fox。
编写SpringBoot项目集成 Swagger,项目中controller中添加注解,测试项目,保证程序可以正确运行:



<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>com.test.swaggergroupId>
<artifactId>swaggerartifactId>
<version>1.0-SNAPSHOTversion>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-dependenciesartifactId>
<version>2.1.6.RELEASEversion>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
<properties>
<maven.compiler.source>8maven.compiler.source>
<maven.compiler.target>8maven.compiler.target>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>io.springfoxgroupId>
<artifactId>springfox-swagger2artifactId>
<version>2.9.2version>
dependency>
<dependency>
<groupId>io.springfoxgroupId>
<artifactId>springfox-swagger-uiartifactId>
<version>2.9.2version>
dependency>
dependencies>
project>
MyController.java
package com.test.controller;
import org.springframework.web.bind.annotation.*;
@RestController
public class MyController {
@PostMapping("/post")
public String post(){
return "post";
}
@GetMapping("/get")
public String get(String a, String b){
return "get";
}
@RequestMapping("/req")
public String req(String m){
return "req";
}
//这里一共3个请求,算上/error 一共四个请求
}
MyApp.java
package com.test;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
/**
* EnableSwagger2 是springfox提供的一个注解,代表swagger2相关技术开启
* 会扫描当前类所在包,及子包中所有的类型中的注解。做swagger文档的定值。
*/
@SpringBootApplication
@EnableSwagger2 // 开启Swagger2
public class MyApp {
public static void main(String[] args) {
SpringApplication.run(MyApp.class,args);
}
}
运行项目:

测试:http://localhost:8080/swagger-ui.html

说明:
Select a spec :选择空间Api Documentation 1.0:Api 文档 版本号 1.0 (Swagger 信息)[ Base URL: localhost:8080/ ] :基础 地址 (Swagger 信息)http://localhost:8080/v2/api-docs :对应api的 Swagger标准描述文档 (Json 或yaml)(Swagger 信息)页面的位置:

其中一个是自己的控制器方法:

访问http://localhost:8080/swagger-ui.html 后可以在页面中看到所有需要生成接口文档的控制器名称,默认扫描的都是控制器注解(Mapping)对应的注解和约束的请求方式。
@RequestMapping(method = {RequestMethod.GET})
// 相当于
@GetMapping
控制器控制那些请求地址:

点击一个方法:

Try it out:测试请求

点击Execule:

Responses:
Curl 命令行发请求 curl -X GET "http://localhost:8080/swagger/test" -H "accept: */*"
Request URL HTTP 发请求 http://localhost:8080/get?a=admin&b=guest
状态码:
可以在项目中创建 SwaggerConfig.java,进行配置文档内容。
根据自己的项目显示:

Docket docket = new Docket(DocumentationType.SWAGGER_2);
//Docket 的DocumentationType可以配置不同框架的信息,这里选框架
// SWAGGER_2 => Swagger2 框架
// SPRING_WEB 框架
// SWAGGER_12 => Swagger1.2 框架

package com.test.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
@Configuration
public class SwaggerConfiguration {
/**
* 创建Docket类型的对象,并使用spring容器管理
* Docket是Swagger中的全局配置对象。
* @Return
*/
@Bean
public Docket docket(){
Docket docket = new Docket(DocumentationType.SWAGGER_2);
//API帮助文档的描述信息 => information
ApiInfo apiInfo = new ApiInfoBuilder()
//配置swagger文档主体内容 文档发布者名称、文档发布者的网站地址,请求路径、文档发布者的email点击可以发邮件
.contact(new Contact(
"Swagger - 学习 ",
"http://localhost:8080/swagger-ui.html",
"test@xxx.com")
)
.title("Swagger 开发帮助文档 ")
.description("Swagger 框架学习帮助文档详细描述:Swagger是一套围绕Open API 规范构建的开源工具,可以帮助设计,构建,记录和使用REST API...")
.version("1.1")
.build();
//给docket上下文配置api描述信息
docket.apiInfo(apiInfo);
return docket;
}
}

docket
.select() //获取Docket中的选择器 返回ApiSelectBuilder。构建选择器。如:扫描什么包的注解。
//设定扫描哪个包(包含子包)中的注解 提高请求雄安率 定位准确度
.apis(RequestHandlerSelectors.basePackage("com.test.controller"));
//RequestHandlerSelectors 配置要扫描接口的方式
//basePackage("com.xx.xx"):指定要扫描的包 (最常用)
//ang():扫描全部
//none():不扫描
//withClassAnnotation(xxx.class) 扫描类上的注解 括号里的参数是一个注解类型的返回对象
//withMethodAnnotation(xxx.class) 扫描方法上的注解,括号里的参数是一个注解类型的返回对象 GetMapping
创建com.test.swagger.anno.MyAnnotationSwagger.java 自定义注解
package com.test.anno;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @Target - 描述当前的注解可以定义在什么资源上
* 属性 value
* - 定义具体的资源。包括:(常用)
* - ElementType.METHOD 可以定义在方法上
* - ElementType.TYPE 可以定义在类型上
* - ElementType.FIELD 可以定义在属性上
* - ElementType.PARAMETER 可以定义在方法参数上
* - ElementType.CONSTRUCTOR 可以定义在构造方法上
* - ElementType.LOCAL_VARIABLE 可以定义在局部变量上
* - ElementType.ANNOTATION_TYPE 可以定义在注解上
* - ElementType.PACKAGE 可以定义在包描述上
* - ElementType.TYPE_PARAMETER 可以定义在参数类型描述上
* - ElementType.TYPE_USE 可以定义在使用类型上
*
*
* @Retention - 当前注解在什么时候有效
* 属性 value
* - 定义具体的生效标记
* - RetentionPolicy.RUNTIME - 运行时有效
* - RetentionPolicy.SOURCE - 源码中有效
* - RetentionPolicy.CLASS - 字节码中有效
*
*/
@Target(value = {ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotationSwagger { //当前类是一个注解,注解名称随意
// 自定义注解中的属性,相当于@MyAnnotationSwagger(value="")
String value() default "";
}
通过 public Api SelectorBuilder apis(Predicate可以设置生成规则
package com.test.controller;
import com.test.anno.MyAnnotationSwagger;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/swagger")
public class MyController {
@PostMapping("/post")
public String post(){
return "post";
}
@GetMapping("/get")
public String get(String a, String b){
return "get";
}
@MyAnnotationSwagger //此时看不到该方法
@RequestMapping("/req")
public String req(String m){
return "req";
}
}
修改 SwaggerConfiguration.java
package com.test.config;
import com.test.anno.MyAnnotationSwagger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import com.google.common.base.Predicates;
@Configuration
public class SwaggerConfiguration {
/**
* 创建Docket类型的对象,并使用spring容器管理
* Docket是Swagger中的全局配置对象。
* @Return
*/
@Bean
public Docket docket(){
Docket docket = new Docket(DocumentationType.SWAGGER_2);
//API帮助文档的描述信息 => information
ApiInfo apiInfo = new ApiInfoBuilder()
//配置swagger文档主体内容 文档发布者名称、 文档发布者的网站地址,请求路径 、 文档发布者的email 点击可以发邮件
.contact(new Contact(
"Swagger - 学习 ",
"http://localhost:8080/swagger-ui.html",
"test@xxx.com")
)
.title("Swagger 开发帮助文档 ")
.description("Swagger 框架学习帮助文档详细描述:Swagger是一套围绕Open API 规范构建的开源工具,可以帮助设计,构建,记录和使用REST API...")
.version("1.1")
.build();
//给docket上下文配置api描述信息
docket.apiInfo(apiInfo);
docket
.select() //获取Docket中的选择器 返回ApiSelectBuilder。构建选择器。如:扫描什么包的注解。
// 规则匹配器 not 取反
.apis(
Predicates.and(
Predicates.not( //取反 false -> true | true -> false
RequestHandlerSelectors.withMethodAnnotation( //当方法上有注解的时候返回true
MyAnnotationSwagger.class) //当方法上有什么注解的时候返回true
),
// Predicates类似于断言,查哪些包的注解,默认就是启动类所有包以及子包的注解。
//设定扫描哪个包(包含子包)中的注解 提高请求雄安率 定位准确度
RequestHandlerSelectors.basePackage("com.test.controller")
)
)
.build();//重新构建Docket对象
return docket;
}
}

package com.test.config;
import com.test.anno.MyAnnotationSwagger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import com.google.common.base.Predicates;
@Configuration
public class SwaggerConfiguration {
/**
* 创建Docket类型的对象,并使用spring容器管理
* Docket是Swagger中的全局配置对象。
* @Return
*/
@Bean
public Docket docket(){
Docket docket = new Docket(DocumentationType.SWAGGER_2);
//上一行代码之后还可以加一个.enable(true) 是否启用swagger,默认为true设置成false就不启用Swagger
//当遇到生产环境时
//API帮助文档的描述信息 => information
ApiInfo apiInfo = new ApiInfoBuilder()
//配置swagger文档主体内容 文档发布者名称、 文档发布者的网站地址,请求路径 、 文档发布者的email 点击可以发邮件
.contact(new Contact(
"Swagger - 学习 ",
"http://localhost:8080/swagger-ui.html",
"test@xxx.com")
)
.title("Swagger 开发帮助文档 ")
.description("Swagger 框架学习帮助文档详细描述:Swagger是一套围绕Open API 规范构建的开源工具,可以帮助设计,构建,记录和使用REST API...")
.version("1.1")
.build();
//给docket上下文配置api描述信息
docket.apiInfo(apiInfo);
docket
.select()//获取Docket中的选择器 返回ApiSelectBuilder。构建选择器。如:扫描什么包的注解。
// 规则匹配器 not 取反
.apis(
Predicates.and(
Predicates.not( //取反 false -> true | true -> false
RequestHandlerSelectors.withMethodAnnotation( //当方法上有注解的时候返回true
MyAnnotationSwagger.class) //当方法上有什么注解的时候返回true
),
// Predicates类似于断言,查哪些包的注解,默认就是启动类所有包以及子包的注解。
//设定扫描哪个包(包含子包)中的注解 提高请求雄安率 定位准确度
RequestHandlerSelectors.basePackage("com.test.controller")
)
)
// .apis(RequestHandlerSelectors.basePackage("com.test.controller"));
// 这么写也是可以的,多个apis
.paths(
//三个条件 或条件 满足一种即可
//多个规则符合任意一个即可通过
Predicates.or(
//使用正则表达式,约束生成API文档的路径地址 * 0-n个任意字符 /swagger/**
PathSelectors.regex("/swagger/.*"),
PathSelectors.regex("/swagger2/.*"),
PathSelectors.regex("/.*")
)
)
.build();//重新构建Docket对象
return docket;
}
}
还需要在需要MyController.java上添加注解:@RequestMapping("/swagger") 才能生效
@RestController
@RequestMapping("/swagger")
public class MyController {
}

没加注解的情况:

多个Docket实例,配置多个分组:
.groupName("分组名")
在SwaggerConfiguration.java中添加多个Docket
@Bean
public Docket docket1(){
return new Docket(DocumentationType.SWAGGER_2).groupName("A");
}
默认是default:

创建application.yml 此时是dev环境激活了
spring:
profiles:
active: dev
创建application-dev.yml 这里通过 8080 端口访问
server:
port: 8080
在SwaggerConfiguration.java中的Docket上添加注解,激活环境
@Bean
@Profile("dev") //激活环境
public Docket docket(){
}
此时就可以访问:http://localhost:8080/swagger-ui.html 进行测试了
这样就保证了,在正式发布时可以 关闭Swagger,节省运行内存 !!!
@Api是类上注解。控制整个类生成接口信息的内容。
tags:类的名称。可以有多个值,多个值表示多个副本。
description:描述,已淘汰,不推荐使用了
package com.test.controller;
import com.test.anno.MyAnnotationSwagger;
import io.swagger.annotations.Api;
import org.springframework.web.bind.annotation.*;
/**
*
* @Api 描述当前类型生成帮助文档的信息
* 属性 -
* - tags:给当前类型定义别名,可以有多个。定义几个别名,在UI视图中就显示几个控制器访问菜单
* - description:给的当前类型生成的帮助文档定义一个描述信息。
*
*/
@RestController
@RequestMapping("/swagger")
@Api(tags = {"MyController","Swagger学习控制器"},description = "测试API类型描述信息")
public class MyController {
@PostMapping("/post")
public String post(){
return "post";
}
@GetMapping("/get")
public String get(String a, String b){
return "get";
}
@MyAnnotationSwagger
@RequestMapping("/req")
public String req(String m){
return "req";
}
}

@PostMapping("/post")
@ApiOperation(value = "post方法,执行数据新增操作",notes = "Swagger学习使用-POST请求的方法") //value必须提供
public String post(){
return "post";
}

@PostMapping("/post")
@ApiOperation(value = "post方法,执行数据新增操作",notes = "Swagger学习使用-POST请求的方法") //value必须提供
public String post(
@ApiParam(name = "参数名:用户名(a)",value = "描述:新增用户时,提供的用户名",required = true) String a,
@ApiParam(name = "参数名:密码(b)",value = "描述:新增用户,提供的密码",required = true)String b
){ //相当于 String a required = true 默认为flase
return "post";
}

//ApiIgnore -忽略.当前注解描述的方法或类型,不生成api帮助文档
@ApiIgnore
@GetMapping("/get")
public String get(String a, String b){
return "get";
}

//唯一参数描述 描述方法的参数
@GetMapping("/test")
@ApiImplicitParam(name = "m",value = "m参数描述",required = false,paramType = "参数类型:字符串类型",dataType = "数据类型:名值对")
public String test(String m, String n){
return "test";
}
//多个参数描述 描述方法的参数
@GetMapping("/test")
//@ApiImplicitParam(name = "m",value = "m参数描述",required = false, paramType = "参数类型:字符串",dataType = "数据类型:名值对")
@ApiImplicitParams(value = {
@ApiImplicitParam(name = "m",value = "m参数描述",required = false, paramType = "参数类型:字符串",dataType = "string"),// 代表请求参数类型为String类型,当然也可以是int,char等;
@ApiImplicitParam(name = "n",value = "n参数描述",required = false, paramType = "参数类型:字符串(String)",dataType = "string")
} )
public String test(String m, String n){
return "test";
}

创建 com.test.entity.MyEntity
package com.test.entity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.io.Serializable;
import java.util.Objects;
/**
*
* @ApiModel 描述一个实体类型,这个实体类型如果成为任何一个生成Api帮助文档方法的返回值类型的时候,此注解被解析
*
*/
@ApiModel(value = "自定义实体-MYEntity",description = "MyEntity存储用户数据")
public class MyEntity implements Serializable {
@ApiModelProperty(value = "主键",name = "主键(id)",required = false,example = "实例:1",hidden = false)
private String id;
// hidden = false 不隐藏
@ApiModelProperty(value = "姓名",name = "姓名(name)",required = true,example = "张三",hidden = false)
private String name;
@ApiModelProperty(value = "密码",name = "密码(password)",required = true,example = "my-password-123",hidden = false)
private String password;
public MyEntity() {
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MyEntity myEntity = (MyEntity) o;
return Objects.equals(id, myEntity.id) && Objects.equals(name, myEntity.name) && Objects.equals(password, myEntity.password);
}
@Override
public int hashCode() {
return Objects.hash(id, name, password);
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
controller中创建方法
@RequestMapping("/testEntity")
public MyEntity testEntity(){
return new MyEntity();
}

