文章目录
一Swagger简介
1. 前后端分离
后端时代:前端只用管理静态页面;html等静态资源交给后端通过模板引擎进行渲染
前后端分离时代:
-
后端:控制层controller、服务层service、数据访问层dao
-
前端:前端控制层、视图层
-
前后端交互:通过API接口
-
前后端相对独立,松耦合,甚至可以部署在不同的服务器上
随之产生的问题:前后端联调,前端人员和后端人员无法做到及时协商,尽早解决
解决方案:
-
首先指定
schema
,实时更新最新的API,降低集成风险 -
早些年:指定word计划文档
-
前后端分离:
- 前端测试后端接口数据是否正确:postman
- 后端提供接口,需要实时更新最新的消息和改动
于是Swagger应运而生
2.Swagger引入
- 号称历史上最流行的api框架
- RestFul Api文档在线生成工具=》Api文档与Api定义同步更新
- 直接运行,可以在线测试Api接口
- 支持多种语言
官网:https://swagger.io/
二、SpringBoot集成Swagger
1. 导入Swagger依赖
springfox-swagger2
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
springfox-swagger-ui
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
2. 编写Swagger配置类
在主程序同级目录下新建
config
包,其中新建SwaggerConfig
配置类
- 记住用
@Configuration
注解注明这是配置类- 同时用
@EnableSwagger2
注解开启Swagger2
@Configuration
@EnableSwagger2//开启Swagger2
public class SwaggerConfig {
}
3.遇到一个错误
Failed to start bean ‘documentationPluginsBootstrapper’; nested exception is java.lang.NullPointerException
springboot 集成Swagger2报错
这里使用的Swagger版本是2.9.2
、springboot 版本是2.6.4
发现是springboot版本太高,缺少swagger运行所需要的环境,具体缺少什么还没研究出来,所以只能回退到之前的版本
把springboot回退到2.5.6
就能正常启动
4.测试进入Sawgger页面
重启主程序,访问
localhost:8080/swagger-ui.html
这个界面是Swagger为我们提供的ui界面,我们可以在源码中找到它
5.配置Swagger API信息
在Swagger提供的ui界面,其中的
Swagger
信息模块我们可以自定义信息内容我们只需要在Swagger配置类
SwaggerConfig
中实例化Docket
类队对象的bean实例,通过配置ApiInfo
类的信息然后传入Docket的bean实例即可
@Configuration
@EnableSwagger2 //开启Swagger2
public class SwaggerConfig {
//配置了Swagger的Docket的bean实例
@Bean
public Docket docket(Environment environment){
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo());
}
//配置Swagger信息=apiInfo
private ApiInfo apiInfo(){
Contact contact = new Contact("艾孜", "https://blog.csdn.net/weixin_49133806?spm=1018.2226.3001.5343", "2271427740@qq.com");
return new ApiInfo(
"Aize.swaggerAPI文档",
"我的API文档",
"V1.0",
"https://blog.csdn.net/weixin_49133806?spm=1018.2226.3001.5343",
contact,
"Apache 2.0",
"https://www.apache.org/licenses/LICENSE-2.0",
new ArrayList<>()
);
}
}
重启主程序测试,可以看到Swagger信息已经变更成我们定义的信息
6. 配置Swagger自定义扫描接口
我们在这个ui界面中,可以看到扫描了两个controller接口;
一个是默认的/error
请求,也就是我们启动springboot主程序未加配置默认访问8080端口的默认controller
另一个是我们自己写的/hello
请求,对应着HelloController
,由于我们用的@RequsetMapping
注解,所以请求的方式有以上的六种
接下来我们自己配置以下要扫描的接口
@Bean
public Docket docket() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())//配置Swagger信息
.select()
/**
* apis():指定扫描的接口
* RequestHandlerSelectors:配置要扫描接口的方式
* basePackage:指定要扫描的包
* any:扫面全部
* none:不扫描
* withClassAnnotation:扫描类上的注解(参数是类上注解的class对象)
* withMethodAnnotation:扫描方法上的注解(参数是方法上的注解的class对象)
*/
.apis(RequestHandlerSelectors.basePackage("com.example.swagger.controller"))
/**
* paths():过滤路径
* PathSelectors:配置过滤的路径
* any:过滤全部路径
* none:不过滤路径
* ant:过滤指定路径:按照按照Spring的AntPathMatcher提供的match方法进行匹配
* regex:过滤指定路径:按照String的matches方法进行匹配
*/
.paths(PathSelectors.ant("/example/**"))
.build();
}
其中.select().apis.paths.build
是一套组合进行使用
然后我们启动主程序访问localhost:8080/swagger-ui.html
进行测试
可以发现No opertations defined in spec
,这是因为我们过滤了/example
下的所有controller
我们将过滤条件更改为过滤全部路径
.paths(PathSelectors.any())
7. 配置是否启动Swagger
我么通过
Docket
对象的.enable
方法来配置swagger是否启动
@Bean
public Docket docket() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())//配置Swagger信息
.enable(false)//配置是否启动swagger,默认为true
.select()
.apis(RequestHandlerSelectors.basePackage("com.example.swagger.controller"))
.paths(PathSelectors.ant("/example/**"))
.build();
}
更改为false后启动测试一下,查看控制台,无法进入到swagger页面
如果我们有这样一个需求:希望Swagger在开发环境中,在正式环境时不能使用
- 首先要判断是不是开发环境,可以设置一个flag表示用来表示:flag=1即表示生产环境
- 然后将flag的值传给
enable(flag)
首先在resources
目录下新建两种springboot配置文件:
-
开发环境:
application-dev.properties
server.port=8081
-
正式环境:
application-pro.properties
server.port=8082
然后在主配置文件application.properties
中激活开发环境
spring.profiles.active=dev
然后我们到SwaggerConfig
中的docket()
方法中添加代码:
-
首先给该方法传一个参数
Environment
的实例Environment environment
-
首先设置药配置的Swagger环境:这里可以添加多个环境
Profiles profiles = Profiles.of("dev", "test");
-
然后通过
environment.acceptsProfiles
方法判断是否处在上一步设定的dev/test
环境中,返回一个boolean
的值,我们用flag
接收boolean flag = environment.acceptsProfiles(profiles);
-
然后修改
enable
中的参数为flag
,即通过flag来判断是否开启Swagger
.enable(flag)//通过flag判断是否开启
完整代码:
@Configuration
@EnableSwagger2//开启Swagger2
public class SwaggerConfig {
//配置Swagger的Docket的bean实例
@Bean
public Docket docket(Environment environment) {
//设置要配置的Swagger环境
Profiles profiles = Profiles.of("dev", "test");
//通过environment.acceptsProfiles判断是否处在自己设定的环境中
boolean flag = environment.acceptsProfiles(profiles);
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())//配置Swagger信息
.enable(flag)//通过flag判断是否开启
.select()
.apis(RequestHandlerSelectors.basePackage("com.example.swagger.controller"))
.paths(PathSelectors.ant("/example/**"))
.build();
}
//配置Swagger信息=apiInfo
private ApiInfo apiInfo(){
Contact contact = new Contact("艾孜", "https://blog.csdn.net/weixin_49133806?spm=1018.2226.3001.5343", "2271427740@qq.com");
return new ApiInfo(
"Aize.swaggerAPI文档",
"我的API文档",
"V1.0",
"https://blog.csdn.net/weixin_49133806?spm=1018.2226.3001.5343",
contact,
"Apache 2.0",
"https://www.apache.org/licenses/LICENSE-2.0",
new ArrayList<>()
);
}
}
然后启动主程序测试:由于激活了dev
开发环境,所以访问localhost:8081/swagger-ui.html
成功开启swagger,如果我们修改主配置文件,激活pro
正式发布环境
spring.profiles.active=pro
8. 配置API文档分组
我们可以在docket
通过.groupName
中设置组名
public Docket docket(Environment environment) {
//设置要配置的Swagger环境
Profiles profiles = Profiles.of("dev", "test");
//通过environment.acceptsProfiles判断是否处在自己设定的环境中
boolean flag = environment.acceptsProfiles(profiles);
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())//配置Swagger信息
.groupName("azmat")
.enable(true)//配置是否启动swagger,默认为true
.select()
.apis(RequestHandlerSelectors.basePackage("com.example.swagger.controller"))
.paths(PathSelectors.any())
.build();
}
1. 配置多个组
上述我们成功修改了组名,但是只有一个组,如果我们想要多个组呢?
观察代码可以知道,一个
Docket
实例就对应着一个组,因此我们配置多个docket就对应着多个组
我们新增两个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");
}
再次重启测试,就可以看到多个组并选择
9. 配置Model实体类
1.新建实体类
在主程序同级目录下新建
pojo
包,其中新建User
实体类
public class User {
public String username;
public String password;
}
2. 编写对应请求接口
@GetMapping("/getUser")
public User getUser() {
return new User();
}
3. 常用注解
我们可以在实体类上和其属性上添加注解来添加对应的注释
@ApiModel
为类添加注释@ApiModelProperty
为类属性添加注释
@ApiModel("用户实体类")
public class User {
@ApiModelProperty("用户名")
public String username;
@ApiModelProperty("用户密码")
public String password;
}
重启测试,即可以看到注释信息
我们同样可以在
Controller
类和其中的方法上添加相应的注解
@Api(tags = "Hello控制类")
@RestController
public class HelloController {
@RequestMapping("/hello")
public String hello(@ApiParam("用户名") String username) {
return "hello" + username;
}
//只要我们的接口中,返回值中存在实体类,他就会被扫描到Swagger中
@ApiOperation("Hello方法")
@GetMapping("/getUser")
public User user() {
return new User();
}
}
重启即可看到对应的注解
10. 测试Swagger的使用
1. 测试传参
我们在
HelloController
中新增一个方法,参数为username
,可以用@ApiParam
给该参数添加注解
@GetMapping("/username")
public String getUserName(@ApiParam("用户名") String username) {
return username;
}
重启测试,可以看到我们添加的注释
我们可以简单测试一下,点击Try it out
;然后以json的格式输入用户名,然后点击Execute
执行
可以看到报错了,这是因为我们是使用的是Get
方式:是通过URL的方式传递的,而不是通过请求体单独传参
我们将代码修改一下,将GetMapping
改为PostMapping
@PostMapping("/username")
public String getUserName(@ApiParam("用户名") String username) {
return username;
}
再次以json的格式输入参数username,可以看到成功了
2. 测试错误
我们在
HelloController
中新增一个方法,参数为User
,可以用@ApiParam
给该参数添加注解
@PostMapping("/getUser")
public User getUser(@ApiParam("用户名") User User) {
return User;
}
找到对应的controller,点击Try it out
测试,输入用户名和密码然后点击Excute
可以看到我们请求的URL
完全正确,但是Response body
相应体中用户名和密码都为空,这是因为我们的实体类没有添加对应的GET和SET方法
,我们添加上去
@ApiModel("用户实体类")
public class User {
@ApiModelProperty("用户名")
public String username;
@ApiModelProperty("用户密码")
public String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
再次启动测试,成功!