在前后端分离项目中,前端人员需要知道我们后端会提供什么数据,根据后端提供的数据来进行前端页面渲染,这个时候,我们就需要编写一个API文档,以便前端人员随时查阅。但是这样的一个文档,我们也不可能单独写一个项目去进行维护,并且随着我们的后端项目不断更新,文档也需要跟随更新,这显然是很麻烦的一件事情,因此,我们就需要用到我们的接口管理Swagger了!
文章目录
什么是Swagger
Swagger 是一个用于生成、描述和调用 RESTful 接口的 Web 服务。通俗的来讲,Swagger 就是将项目中所有(想要暴露的)接口展现在页面上,并且可以进行接口调用和测试的服务。它主要有以下功能:
- 支持 API 自动生成同步的在线文档:使用 Swagger 后可以直接通过代码生成文档,不再需要自己手动编写接口文档了
- 提供 Web 页面在线测试 API:Swagger 生成的文档还支持在线测试。参数和格式都定好了,直接在界面上输入参数对应的值即可在线测试接口。
结合Spring框架(Spring-fox),Swagger可以很轻松地利用注解以及扫描机制,来快速生成在线文档,以实现当我们项目启动之后,前端开发人员就可以打开Swagger提供的前端页面,查看和测试接口
如何使用Swagger
引入依赖
<!-- 引入swagger2 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>3.0.0</version>
</dependency>
<!-- 引入swagger-ui -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>3.0.0</version>
</dependency>
<!-- 引入springfox启动器 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
编写配置类
- 在
config
包下新建SwaggerConfig
@Configuration
@EnableSwagger2 // 开启Swagger2
@EnableWebMvc
public class SwaggerConfig {
}
- SercurityConfig放行
因为我们之前为我们的项目添加了sercurity依赖,因此我们需要对Swagger的访问地址进行放行,故需要在SercurityConfig中添加以下代码放行
@Override
public void configure(WebSecurity web) throws Exception {
//所需要用到的静态资源,允许访问
web.ignoring().antMatchers( "/swagger-ui.html",
"/swagger-ui/*",
"/swagger-resources/**",
"/v2/api-docs",
"/v3/api-docs",
"/webjars/**");
}
- 浏览器访问
http://localhost:8081/swagger-ui/index.html
或者http://localhost:8081/swagger-ui.html
以上就是我们前端页面可以看到的接口信息,接下来我们来试试Swagger文档的在线测试功能,以loginController
为例
可以看到在我们正确输入用户名及密码后,我们的登录状态为200,并且成功显示了登录成功的信息!
扫描接口及开关
以上的SwaggerConfig里面我们好像什么功能都还没配置就已经实现了诸多效果,接下来我们看看Swagger还有什么神奇的功能吧
添加Docket方法
@Configuration
@EnableSwagger2 // 开启Swagger2
@EnableWebMvc
public class SwaggerConfig implements WebMvcConfigurer {
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo()) // 我们可以写一个apiInfo类来配置信息
.select()
.apis(RequestHandlerSelectors
.basePackage("com.pan.controller"))
.paths(PathSelectors.any()) // 进一步过滤,当然我们这里any是把什么都释放了
.build();
}
// 按住ctrl点击ApiInfo可以看到可以配置的信息
private ApiInfo apiInfo() {
// 作者信息
Contact contact = new Contact("不潘", "https://blog.csdn.net/qq_54103767", "123456789@qq.com");
return new ApiInfo("SpringBoot-01的Swagger",
"这是一个SpringBoot的练习项目",
"1.0",
"https://blog.csdn.net/qq_54103767", // 我的博客地址
contact,
"Apache 2.0",
"http://www.apache.org/licenses/LICENSE-2.0",
new ArrayList());
}
}
- select: 选择扫描接口
- RequestHandlerSelectors: 配置要扫描接口的方式
- basePackage:指定要扫描的包
- any:扫描全部
- none: 都不扫描
- withMethodAnnotation: 扫描方法上的注解 withMethodAnnotation(RestMapping.class)
- withClassAnnotation: 扫描类上的注解
- paths: 过滤什么路径
- enable: 是否启动swagger,如果为false,swagger则不能在浏览器访问
这些简单的参数都可以通过按住ctrl
+点击进入源代码观看细节参数
我们来看看加了Docket后页面的样子
提问:要求在测试环境能访问swagger,非测试环境不能访问
我们只需要利用enable()
就可以做到,在Docket
添加参数Environment,获取当前项目启用环境
@Configuration
@EnableSwagger2 // 开启Swagger2
@EnableWebMvc
public class SwaggerConfig implements WebMvcConfigurer {
// 要求在测试环境能访问swagger,非测试环境不能访问
@Bean
public Docket createRestApi(Environment environment) {
// 获取项目的环境(添加参数Environment(org.springframework.core.env) environment )
// 设置要显示的swagger环境
Profiles profiles = Profiles.of("dev","test");
// 通过environment.acceptsProfiles判断是否处在自己设定的环境
boolean flag = environment.acceptsProfiles(profiles);
// 此时就可将 enable(flag) 来判断
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo()) // 我们可以写一个apiInfo类来配置信息
.enable(flag)
.select()
.apis(RequestHandlerSelectors
.basePackage("com.pan.controller"))
.paths(PathSelectors.any()) // 进一步过滤,当然我们这里any是把什么都释放了
.build();
}
// 按住ctrl点击ApiInfo可以看到可以配置的信息
private ApiInfo apiInfo() {
// 作者信息
Contact contact = new Contact("不潘", "https://blog.csdn.net/qq_54103767", "123456789@qq.com");
return new ApiInfo("SpringBoot-01的Swagger",
"这是一个SpringBoot的练习项目",
"1.0",
"https://blog.csdn.net/qq_54103767", // 我的博客地址
contact,
"Apache 2.0",
"http://www.apache.org/licenses/LICENSE-2.0",
new ArrayList());
}
}
配置多个分组
利用.groupName
实现
.groupName("不潘") // 配置多个分组 配置多个docket(A,B,C)
@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");
}
右上角可以看到我们已经有多个分组了
swagger接口注释
注解 | 作用 | 使用位置 |
---|---|---|
@Api | 表示对类的说明常用参数 | 类上面 |
@ApiOperation | 说明方法的用途、作用 | 方法上面 |
@ApiModel | 表示一个返回响应数据的信息 | 响应类 |
@ApiModelProperty | 描述响应类的属性 | 属性 |
@ApiIgnore | 忽略某个字段使之不显示在文档中 | 属性 |
@Api:资源描述
@Api:用在请求的类上,表示对类的说明
参数 | 描述 |
---|---|
tags | 说明该类的作用,非空时将覆盖value的值 |
value | 描述类的作用 |
description | 对api资源的描述,在1.5版本后不再支持 |
basePath | 基本路径可以不配置,在1.5版本后不再支持 |
position | 如果配置多个Api 想改变显示的顺序位置,在1.5版本后不再支持 |
produces | 设置MIME类型列表(output),例:“application/json, application/xml”,默认为空 |
authorizations | 获取授权列表(安全声明),如果未设置,则返回一个空的授权值 |
hidden | 默认为false, 配置为true 将在文档中隐藏 |
代码示例:
@Api(tags="登录请求")
@RestController
public class LoginController {}
@ApiOperation:方法描述
@ApiOperation:用在请求的方法上,说明方法的用途、作用
参数 | 描述 |
---|---|
value | 说明方法的用途、作用 |
notes | 方法的备注说明 |
tags | 操作标签,非空时将覆盖value的值 |
response | 响应类型(即返回对象) |
responseContainer | 声明包装的响应容器(返回对象类型)。有效值为 “List”, “Set” or “Map”。 |
responseReference | 指定对响应类型的引用。将覆盖任何指定的response()类 |
httpMethod | 指定HTTP方法,“GET”, “HEAD”, “POST”, “PUT”, “DELETE”, “OPTIONS” and “PATCH“ |
responseHeaders | 响应头列表 |
code | 响应的HTTP状态代码。默认 200 |
hidden | 默认为false, 配置为true 将在文档中隐藏 |
@PostMapping(value="/login")
@ApiOperation(value = "登录检测", notes="根据用户名、密码判断该用户是否存在")
public UserModel login(@RequestParam(value = "name", required = false) String account,
@RequestParam(value = "pass", required = false) String password){}
@ApiModel
@ApiModel:用于响应类上,表示一个返回响应数据的信息
@ApiModel(value="用户登录信息", description="用于判断用户是否存在")
public class UserModel implements Serializable{
private static final long serialVersionUID = 1L;
@ApiModelProperty(value="用户名")
private String account;
@ApiModelProperty(value="密码")
private String password;
}
@ApiModelProperty
@ApiModelProperty:用在属性上,描述响应类的属性
参数 | 描述 |
---|---|
value | 此属性的简要说明。 |
name | 允许覆盖属性名称 |
allowableValues | 限制参数的可接受值。1.以逗号分隔的列表 2、范围值 3、设置最小值/最大值 |
access | 允许从API文档中过滤属性。 |
notes | 目前尚未使用。 |
dataType | 参数的数据类型。可以是类名或者参数名,会覆盖类的属性名称。 |
required | 参数是否必传,默认为false |
position | 允许在类中对属性进行排序。默认为0 |
hidden | 允许在Swagger模型定义中隐藏该属性。 |
example | 属性的示例。 |
readOnly | 将属性设置为只读 |
reference | 指定对相应类型定义的引用,覆盖指定的任何参数值 |
代码示例:
@ApiModel(value="用户登录信息", description="用于判断用户是否存在")
public class UserModel implements Serializable{
private static final long serialVersionUID = 1L;
@ApiModelProperty(value="用户名")
private String account;
@ApiModelProperty(value="密码")
private String password;
}
@ApiIgnore:资源过滤
@ApiIgnore 忽略某个属性,使之不显示在swagger文档中显示
有些时候我们并不是希望所有的 Rest API 都呈现在文档上,这种情况下 Swagger2 提供给我们了两种方式配置,一种是基于 @ApiIgnore 注解另一种是在 Docket 上增加筛选。两种方式的区别是,Docket 配置的规则,可以对多个接口器过滤作用,而 @ApiIgnore 只能作用于单个接口
@GetMapping(value ="page")
@ApiOperation(value ="分页查询登录⽇志")
public Result page(@ApiIgnore LogVo vo){
return null;
}
@ApiImplicitParam(s):参数描述
参数描述,可用在方法头。
@ApiImplicitParams({
@ApiImplicitParam(name = "id", value = "学生ID")
})
@GetMapping("/{id}")
public Response getStudentsInfo(@PathVariable Integer id) {
return null;
}
参数 | 描述 |
---|---|
name | 字符串;参数名 |
value | 字符串;参数的汉字说明、解释 |
defaultValue | 字符串;参数的默认值 |
allowableValues | 字符串;限制此参数接收的值,可使用的值或值得范围( 表示是大于,) 表示是小于[ 表示是大于等于,] 表示是小于等于infinity 表示无限大,-infinity 表示负无限大 |
allowEmptyValue | true/false;允许参数为空,默认为 false |
required | true/false;参数是否必须传 |
paramType | 字符串;参数放在哪个地方(可以自动识别) |
header | 参数在request headers 里边提交:@RequestHeader path(用于restful接口)–> 参数以地址的形式提交:@PathVariable query --> 直接跟参数完成自动映射赋值:@RequestParam form --> 以form表单的形式提交,仅支持POST:@RequestParam body --> 以流的形式提交,仅支持POST:@RequestBody |
dataType | 字符串;参数类型,参数的数据类型(默认String),可以使用类名或原始数据类型(使用不当汇报类型转换异常) |
dataTypeClass | Class;参数的类,如果提供则覆盖 dataType |
example | 字符串;非请求体(body)参数的单个请求示例 |
examples | Example;参数的举例说明,仅适用于 body 类型。 |
@ApiParam:参数描述
参数描述,用在每个参数前面
@PostMapping("/create")
// 注:这里如果使用 @ApiImplicitParam 会出现无法识别的问题
public Response createStudents(
@ApiParam(name = "request", value = "创建学生请求对象") @RequestBody CreateStudentsRequest request)
参数 | 描述 |
---|---|
name | 字符串;参数名 |
value | 字符串;参数的汉字说明、解释 |
defaultValue | 字符串;参数的默认值 |
allowableValues | 字符串;限制此参数接收的值,可使用的值或值得范围( 表示是大于,) 表示是小于[ 表示是大于等于,] 表示是小于等于infinity 表示无限大,-infinity 表示负无限大 |
allowEmptyValue | true/false;允许参数为空,默认为 false |
required | true/false;参数是否必须传 |
example | 字符串;非请求体(body)参数的单个请求示例 |
examples | Example;参数的举例说明,仅适用于 body 类型。 |
关于 @ApiImplicitParam 和 @ApiParm 它俩都能为方法的请求参数做注释,区别有:
@ApiImplicitParam 可以在方法前使用,而 @ApiParm 只能在参数前使用
@ApiImplicitParam 提供的可设置属性更多,特别是 paramType 很关键
对于 @RequestBody 标识的 Json 字符串,不能使用 @ApiImplicitParam,会出现无法识别的情况
方案一:通过 @ApiParm 对 @RequestBody 的参数进行说明
方案二:直接不对该参数使用注解,将注释的任务交给实体类(@ApiModel)
另外,两者是可以混搭使用的,一般推荐使用 @ApiImplicitParam(s),但是注意 @RequestBody 的情况。
@ApiResponse(s)
@ApiResponses({
@ApiResponse(code = 1, message = "非HTTP状态码,Response code字段值,描述:成功,返回该学生ID"),
@ApiResponse(code = 0, message = "非HTTP状态码,Response code字段值,描述:失败")
})
@PostMapping("/create")
public Response createStudents
参数 | 描述 |
---|---|
code | 整形数;相应的状态码 |
message | 字符串;相应消息,例如"电话号码已存在" |
response | Class;消息有效负载的可选响应类,对应于响应消息对象的 schema 字段;对于使用通用 Response 的情况,该字段很关键 |
responseHeaders | ResponseHeader[];可能响应的 header 列表 |
responseContainer | String;声明响应的容器,有效值为List,Set,Map,任何其他值都将被忽略 |