Swagger
导语:
相信无论是前端还是后端开发,都或多或少地被接口文档折磨过。前端经常抱怨后端给的接口文档与实际情况不一致。后端又觉得编写及维护接口文档会耗费不少精力,经常来不及更新。其实无论是前端调用后端,还是后端调用后端,都期望有一个好的接口文档。但是这个接口文档对于程序员来说,就跟注释一样,经常会抱怨别人写的代码没有写注释,然而自己写起代码起来,最讨厌的,也是写注释。所以仅仅只通过强制来规范大家是不够的,随着时间推移,版本迭代,接口文档往往很容易就跟不上代码,等等等的问题。
为了解决以上API接口问题,就出现了Swagger!说白了就是为了解决前后端分离开发带来的对接问题
Swagger是什么?
Swagger是一款让你更好地书写API文档的框架。
Swagger是一个功能强大且易于使用的API开发人员工具套件,适用于团队和个人,可在整个API生命周期(从设计和文档到测试和部署)中进行开发。
Swagger怎么用?
本文使用的是Springboot构建项目!项目使用Swagger2!
- Swagger需要的组件
Swagger需要使用到Springfox
- Swagger2
- ui
先看看Swagger-ui界面
- 创建springboot项目
创建的是web项目,这里不讲如何创建。
- 到Maven查找组件
把依赖导入pom文件
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<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>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
- 编写一个HelloController工程
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@RequestMapping("/hello.do")
public String hello(){
return "hello swagger";
}
}
启动Springboot,访问controller,没有出错就继续往下走。
- 编写Swagger配置类
import org.springframework.context.annotation.Configuration;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@Configuration // 定义为配置类
@EnableSwagger2 // 开启Swagger2
public class SwaggerConfig {
}
- 访问
看看我们导入的依赖,可以找到一个swagger-ui.html页面
访问http://localhost:8080/swagger-ui.html
第一个简单的swagger页面就弄好了!
配置Swagger
Swagger的bean实例 Docket
@Configuration // 定义为配置类
@EnableSwagger2 // 开启Swagger2
public class SwaggerConfig {
// 配置Swagger的Docket的bean实例
@Bean
public Docket docket(){
return new Docket(DocumentationType.SWAGGER_2);
}
}
点进Docket构造器里面,ApiInfo使用默认的配置,此时我们可以为ApiInfo设值
public Docket(DocumentationType documentationType) {
this.apiInfo = ApiInfo.DEFAULT; //api信息
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;
}
点进ApiInfo类中,查看默认配置DEFAULT
static {
DEFAULT = new ApiInfo("Api Documentation", "Api Documentation", "1.0", "urn:tos", DEFAULT_CONTACT, "Apache 2.0", "http://www.apache.org/licenses/LICENSE-2.0", new ArrayList());
}
自定义ApiInfo信息
@Configuration // 定义为配置类
@EnableSwagger2 // 开启Swagger2
public class SwaggerConfig {
// 配置Swagger的Docket的bean实例
@Bean
public Docket docket() {
return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo());
}
// 配置swagger的ApiInfo信息
public ApiInfo apiInfo() {
// 作者信息
Contact contact = new Contact("hao","https://blog.csdn.net/weixin_44151739/article/details/109183587","xxx@qq.com");
return new ApiInfo(
"hao的Swagger API文档",
"今天怎么过,明天就怎么过!",
"V1.0",
"https://blog.csdn.net/weixin_44151739/article/details/109183587",
contact,
"Apache 2.0",
"http://www.apache.org/licenses/LICENSE-2.0",
new ArrayList()
);
}
}
启动服务器访问
配置扫描接口及配置
默认的不管,我们看自定义的controller,存在多种方式访问,因为我们代码中使用的是@RequestMapping("/hello.do"),没有设置具体访问方式
接下来我们讲Swagger如何扫描到我们controller的
Docket的select()方法
- 指定扫描包
// 配置Swagger的Docket的bean实例
@Bean
public Docket docket() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
// RequestHandlerSelectors 配置要扫描接口的方式
// basePackage 指定要扫描的包
.apis(RequestHandlerSelectors.basePackage("com.hao.swagger.controller"))
.build();
}
重启服务器,访问,你会发现默认的那个不见了,只剩下我们指定包中的controller
点进RequestHandlerSelectors类中,具体内容省略,查看一下扫描方法
public class RequestHandlerSelectors {
// 扫描所有
public static Predicate<RequestHandler> any() {
}
// 不扫描
public static Predicate<RequestHandler> none() {
}
// 通过方法的注解去扫描
public static Predicate<RequestHandler> withMethodAnnotation(final Class<? extends Annotation> annotation) {
}
// 通过类的注解去扫描
public static Predicate<RequestHandler> withClassAnnotation(final Class<? extends Annotation> annotation) {
}
private static Function<Class<?>, Boolean> annotationPresent(final Class<? extends Annotation> annotation) {
}
private static Function<Class<?>, Boolean> handlerPackage(final String basePackage) {
}
// 扫描指定包
public static Predicate<RequestHandler> basePackage(final String basePackage) {
}
private static Optional<? extends Class<?>> declaringClass(RequestHandler input) {
}
}
- 过滤指定路径
// 配置Swagger的Docket的bean实例
@Bean
public Docket docket() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
// RequestHandlerSelectors 配置要扫描接口的方式
// basePackage 指定要扫描的包
.apis(RequestHandlerSelectors.basePackage("com.hao.swagger.controller"))
// paths 过滤路径
// ant 过滤指定名称
.paths(PathSelectors.ant("/hao/**"))
.build();
}
重启服务器,访问,没有接口了,我们自定义就一个接口,路径为/hello.do,此时要扫描的是/hao开头的
点进PathSelectors类中,具体内容省略,查看一下过滤方法
public class PathSelectors {
// 过滤全部
public static Predicate<String> any() {
}
// 不过滤
public static Predicate<String> none() {
}
// 正则
public static Predicate<String> regex(final String pathRegex) {
}
// 指定过滤
public static Predicate<String> ant(final String antPattern) {
}
}
- 配置是否启动Swagger
// 配置Swagger的Docket的bean实例
@Bean
public Docket docket() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
// 是否开启Swagger,默认为true(开启),现在设置为false
.enable(false)
.select()
// RequestHandlerSelectors 配置要扫描接口的方式
// basePackage 指定要扫描的包
.apis(RequestHandlerSelectors.basePackage("com.hao.swagger.controller"))
// paths 过滤路径
// ant 过滤指定名称
.paths(PathSelectors.ant("/hao/**"))
.build();
}
重启服务器,访问,Swagger被禁用
案例
我只希望Swagger在生产环境中使用,在发布的时候不使用
修改enable的参数
创建两个配置类
-
application-dev.properties:开发环境
-
application-pro.properties:上线环境
#application.properties
spring.profiles.active=dev
#application-dev.properties
server.port=8081
#application-pro.properties
server.port=8082
这里我们使用dev(开发)环境,如何修改controller类的docket方法,注意修改enable的变量
// 配置Swagger的Docket的bean实例
@Bean
public Docket docket(Environment environment) {
// 设置要显式的Swagger环境,of为可变参数
Profiles profiles = Profiles.of("dev", "test");
// 通过environment.acceptsProfiles判断是否处在自己设定的环境当中
boolean b = environment.acceptsProfiles(profiles);
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
// 这里使用变量b
.enable(b)
.select()
.apis(RequestHandlerSelectors.basePackage("com.hao.swagger.controller"))
.paths(PathSelectors.ant("/hao/**"))
.build();
}
重启服务器,访问的端口为8081,记得修改端口
然后我们再测试一下上线版
#application.properties
spring.profiles.active=pro
重启服务器,访问的端口为8082,记得修改端口
配置API文档的分组
在之前写的代码中为组设置名称
@Bean
public Docket docket(Environment environment) {
Profiles profiles = Profiles.of("dev", "test");
boolean b = environment.acceptsProfiles(profiles);
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
// 为分组设置名称
.groupName("hao")
.enable(b)
.select()
.apis(RequestHandlerSelectors.basePackage("com.hao.swagger.controller"))
.paths(PathSelectors.ant("/hao/**"))
.build();
}
把环境设置回dev,然后访问,记得端口是8081
#application.properties
spring.profiles.active=dev
可以看到当前的组名被改为hao
可以理解为,一个Docket对象就是一个组
-
讲分组之前,我们需要清空之前SwaggerConfig配置类中配置的代码
-
环境也不需要设置了,清空就好(application.properties配置文件的内容清掉)
-
编写3个Docket对象
@Configuration // 定义为配置类
@EnableSwagger2 // 开启Swagger2
public class SwaggerConfig {
@Bean
public Docket docket1(){
return new Docket(DocumentationType.SWAGGER_2).groupName("A");
}
@Bean
public Docket docket2(){
return new Docket(DocumentationType.SWAGGER_2).groupName("B");
}
@Bean
public Docket docket3(){
return new Docket(DocumentationType.SWAGGER_2).groupName("C");
}
}
- 访问服务器,记得端口改回8080,此时就可以看到有3个分组了
每个开发者有自己的Docket对象(自己的组),独立开发,最终把模块合并在一起,也能明显知道谁开发的功能。
实体类配置
- 添加一个实体类User
public class User {
private String name;
private Integer age;
public String getName() {
return name;
}
public Integer getAge() {
return age;
}
}
- 修改controller
@RestController
public class HelloController {
@GetMapping("/hello.do")
public String hello(){
return "hello swagger";
}
// 只要我们的接口中,返回值中存在实体类,他就会被扫描到Swagger中
@GetMapping("/user.do")
public User user(){
return new User();
}
}
- 启动服务器,访问
给实体类起名字
实体类用上以下注解
@ApiModel(“用户实体类”)
@ApiModelProperty(“用户名”)
@ApiModelProperty(“年龄”)
@ApiModel("用户实体类")
public class User {
@ApiModelProperty("用户名")
private String name;
@ApiModelProperty("年龄")
private Integer age;
public String getName() {
return name;
}
public Integer getAge() {
return age;
}
}
给controller起名字
@ApiOperation(“Hello控制类”)
@ApiParam(“名字”)
@RestController
public class HelloController {
@ApiOperation("Hello控制类")
@GetMapping("/hello.do")
public String hello(@ApiParam("名字") String name){
return "hello swagger";
}
// 只要我们的接口中,返回值中存在实体类,他就会被扫描到Swagger中
@GetMapping("/user.do")
public User user(){
return new User();
}
}
测试功能
@ApiOperation("Hello控制类")
@GetMapping("/hello.do")
public String hello(@ApiParam("名字") String name){
return "hello swagger";
}
点击Trt it out,因为需要参数,所以可以输入参数
按Execute提交请求,下面就可以观察请求后返回的结果
这里我们演示无参那个请求
因为返回User对象的属性没有设值,所以为null
可以的话,给个三连,谢谢!