一、前言
Swagger是一个强大的API文档工具,使用Swagger可以轻松的将后端API的请求条件、所需参数、名称等告知前端的开发人员,可以说是前后端进行沟通的桥梁;在本篇博客中就来介绍一下在Springboot中如何集成Swagger2.0,从而来帮助我们更好的进行开发工作。
二、使用前的准备
在Springboot中集成Swagger2.0,就需要准备Swagger2.0的相关依赖,在这里以Maven项目管理工具来介绍相关的使用,首先我们想要到线上Maven仓库中选取相关的依赖,所需要的依赖文件如下:
<!--Swagger版本 2.9.2-->
<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>
三、正式进行开发工作
在项目中引入相关的依赖以后,我们就可以在项目中使用Swagger来对API进行注解说明了,首先我们来创建Swagger的一个配置类,如下所示:
@Configuration
@EnableSwagger2 // 启动Swaggger2的注解
public class commonConfig {
@Value("${swagger.config.basePackage}")
private String basePackage;
@Value("${swagger.config.title}")
private String title;
@Value("${swagger.config.description}")
private String description;
@Value("${swagger.config.version}")
private String version;
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2) //指定API类型为swagger2
.apiInfo(apiInfo()) //用于定义API文档的相关信息
.select()//
.apis(RequestHandlerSelectors.basePackage(basePackage)) //指定controller层包名
.paths(PathSelectors.any()) //应用于所有的controller
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()//
.title(title) //API文档的标题
.description(description) //关于这个文档作用的描述
.version(version) //设置当前API文档的版本号
.build();
}
}
由于我是在SpringBoot的配置文件(application.yml)中,进行了相关参数的配置,具体的配置如下:
swagger:
config:
basePackage: com.learn.controller
title: Wechat Login API Document.
description: Provide wechat login relasted interface.
version: 1.0
完成了以上的工作以后,我们就可以在进行API开发的时候使用了,先来介绍controller层中的使用,直接上controller层的代码:
@RestController
@Api(value = "WechatLoginController", tags = { "微信登录服务API" })
public class WechatLoginController {
@Autowired
private WechatLoginService wechatLoginService;
@Value("${web.backend.redirectUrl}")
private String webCallbackUrl;
@CrossOrigin
@RequestMapping(value = "/wechat/login", method = RequestMethod.GET)
@ApiOperation(value = "构建请求授权URL")
@ApiImplicitParam(name = "redirect_url", value = "发起微信登录的前端URL", required = true, paramType = "query", dataType = "String")
public ResponseEntity<String> weChatLogin(@RequestParam("redirect_url") String redirect_url) {
String takenUrl = wechatLoginService.createWechatAuthorizeUrl(redirect_url);
return ResponseEntity.ok(takenUrl);
}
}
接下来介绍Model层的使用,直接上代码:
@Data
@ApiModel(value="WechatUser",description="微信用户信息实体类")
public class WechatUser implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value="id",required=true)
private String id;
@ApiModelProperty(value="微信用户openId",required=true)
private String openid;
@ApiModelProperty(value="微信用户昵称",required=true)
private String nickname;
@ApiModelProperty(value="微信头像地址",required=true)
private String headimgurl;
@ApiModelProperty(value="用户性别1:男性|2:女性|0:未知",required=true)
private String sex;
@Override
public String toString() {
return "openid=" + openid
+ "&nickname=" + nickname
+ "&headimgurl=" + headimgurl
+ "&sex="+sex;
}
}
经常要用到的注解如下:
@Api---用在类文件上,一般用于controller层
@ApiOperation---用于方法上,一般用于controller层中的API方法
@ApiImplicitParam---用于方法上,用于对API参数进行标注
@ApiImplicitParams---用于方法上,用于对API参数进行标注,适应于多个参数的情况,使用如下:
@ApiImplicitParams({
@ApiImplicitParam(...),
@ApiImplicitParam(...),
@ApiImplicitParam(...)
})
@ApiModel---用于类上,一般用于model层
@ApiModelProperty---用于实体类中的属性上
下面这一组关于注解的详细说明,来源于网络,参考博客:swagger2注解使用教程
@Api:用在请求的类上,表示对类的说明
tags="说明该类的作用,可以在UI界面上看到的注解"
value="该参数没什么意义,在UI界面上也看到,所以不需要配置"
@ApiOperation:用在请求的方法上,说明方法的用途、作用
value="说明方法的用途、作用"
notes="方法的备注说明"
// 在notes中进行换行的方法:
1、springfox-swagger2 中使用:空格+空格+\n
2、swagger-springmvc 中使用:<br/>
如: @ApiOperation(value = "this api",notes = "参数name有三个选择: \n 1... \n2... \n3...")
其他参数:
tags 操作标签,非空时将覆盖value的值
response 响应类型(即返回对象)
responseContainer 声明包装的响应容器(返回对象类型)。有效值为 "List", "Set" or "Map"。
responseReference 指定对响应类型的引用。将覆盖任何指定的response()类
httpMethod 指定HTTP方法,"GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS" and "PATCH"
position 如果配置多个Api 想改变显示的顺序位置,在1.5版本后不再支持
nickname 第三方工具唯一标识,默认为空
produces 设置MIME类型列表(output),例:"application/json, application/xml",默认为空
consumes 设置MIME类型列表(input),例:"application/json, application/xml",默认为空
protocols 设置特定协议,例:http, https, ws, wss。
authorizations 获取授权列表(安全声明),如果未设置,则返回一个空的授权值。
hidden 默认为false, 配置为true 将在文档中隐藏
responseHeaders 响应头列表
code 响应的HTTP状态代码。默认 200
extensions 扩展属性列表数组
@ApiImplicitParams:用在请求的方法上,表示一组参数说明
@ApiImplicitParam:用在@ApiImplicitParams注解中,指定一个请求参数的各个方面
name:参数名
value:参数的汉字说明、解释
required:参数是否必须传
paramType:参数放在哪个地方
· header --> 请求参数的获取:@RequestHeader
· query --> 请求参数的获取:@RequestParam
· path(用于restful接口)--> 请求参数的获取:@PathVariable
· body(不常用)
· form(不常用)
dataType:参数类型,默认String
// 注意:如果dataType设置为Integer,在文档中会显示undefined,如果设置为Int,就可以显示Integer
// 如果输入的为数组类型,则在dataType中设置数组中元素类型,如:String,然后设置allowMultiple=true即可,此时文档中dataType列下显示的类型为Array[string]
defaultValue:参数的默认值
example: 非请求体(body)参数的单个请求示例,注意是非body类型的参数,body类型设置无效
examples:设置body参数请求的示例
// examples=@Example((@ExampleProperty(mediaType="",value="")))
allowableValues:设置参数允许的值,例如:allowableValues="a, b, c"
@ApiResponses:用在请求的方法上,表示一组响应
@ApiResponse:用在@ApiResponses中,一般用于表达一个错误的响应信息
code:数字,例如400
message:信息,例如"请求参数没填好"
response:抛出异常的类
@ApiModel:用于响应类上,表示一个返回响应数据的信息
(这种一般用在post创建的时候,使用@RequestBody这样的场景,
请求参数无法使用@ApiImplicitParam注解进行描述的时候)
@ApiModelProperty:用在属性上,描述响应类的属性
注意:
举例说明:如果使用 @ApiImplicitParam(name = “department”, value = “部门信息”, dataType =“Department”, paramType = “body”, required = true)在API的参数注解中,那么在Department的实体中就不要使用@ApiModel(value = “Department对象”, description = “”),否则在文档中对应的API参数部分就不能显示Department的实体类。也就是上变说的@ApiModel请求参数无法使用@ApiImplicitParam注解进行描述的时候)
启动项目,访问对应的链接,如:http://xxxxx:port/swagger-ui.html,显示如下界面:
四、注意
由上图可以看出,我们虽然在model层的实体类上添加了相应的注解,但是并没有显示,出现这个问题的原因是因为虽然在实体类上进行了注解,但是必须在controller层中使用@requestBody注解或者返回的数据类型中包含注解的实体类才可以显示,由于我写的API中没有满足这样的条件,所以没有显示。
五、全局参数配置以及其他的配置说明
先来上一个已经配置好的配置文件:
@Configuration
@EnableSwagger2
public class SwaggerConfig {
@Bean
public Docket createRestApi() {
Parameter parameter=new ParameterBuilder()//
.name("token")//
.description("token参数")//
.modelRef(new ModelRef("String"))//
.parameterType("query")//
.required(Boolean.FALSE)//
.build();
return new Docket(DocumentationType.SWAGGER_2)//
.protocols(getProtocols())// 设置API的传输协议
.apiInfo(apiInfo())// api元数据信息 【必选】
//.host("127.0.0.1:8089")// 设置提供API的主机地址,不指定时就是当前主机
.produces(getProduces())// 设置响应的数据MIME类型
.globalOperationParameters(Arrays.asList(parameter))// 在每一个方法下添加一个公共的参数
// 设置授权
.securitySchemes(getSecuritySchemes())
.securityContexts(getSecurityContexts())
.select()//
.apis(RequestHandlerSelectors.basePackage(basePackage))// 指定当前包的路径
.paths(PathSelectors.regex("/api/v1/auth.*"))// # 对包中哪些API进行操作,可以进行过滤【必选】
.build();
}
private Set<String> getProtocols(){
Set<String> protocols=new HashSet<>();
protocols.add("http");
protocols.add("https");
return protocols;
}
private Set<String> getProduces(){
Set<String> produces=new HashSet<>();
produces.add("application/json");
return produces;
}
private List<SecurityContext> getSecurityContexts(){
List<SecurityContext> securityContexts=new ArrayList<SecurityContext>();
SecurityContext securityContext= SecurityContext.builder()//
.securityReferences(defaultAuth())//
.forPaths(PathSelectors.regex("/api.*"))// 匹配所以/api开始的API
.forHttpMethods(new Predicate<HttpMethod>() { // 匹配所有的非GET方法
@Override
public boolean apply(HttpMethod input) {
return input.equals(HttpMethod.GET)?false:true;
}
})
.build();
securityContexts.add(securityContext);
return securityContexts;
}
private List<SecurityReference> defaultAuth() {
AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
authorizationScopes[0] = authorizationScope;
List<SecurityReference> securityReferences=new ArrayList<SecurityReference>();
securityReferences.add(new SecurityReference("apiKey", authorizationScopes));
securityReferences.add(new SecurityReference("signature", authorizationScopes));
securityReferences.add(new SecurityReference("timeStamp", authorizationScopes));
return securityReferences;
}
private List<SecurityScheme> getSecuritySchemes(){
List<SecurityScheme> securitySchemes=new ArrayList<SecurityScheme>();
SecurityScheme authorization=new ApiKey("apiKey", "Authorization", "header");
SecurityScheme signature=new ApiKey("signature", "signature", "header");
SecurityScheme timeStamp=new ApiKey("timeStamp", "timeStamp", "header");
securitySchemes.add(authorization);
securitySchemes.add(signature);
securitySchemes.add(timeStamp);
return securitySchemes;
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()//
.title("swagger文档配置")//
.description("提供相关的API")//
.termsOfServiceUrl("http://localhost:8089/a.html") // 指向服务条款的url
.contact(new Contact("联系人", "http://localhost:8089/a.html", "zhangsan@126.com")) // 开放的API的联系人信息
.license("license")// 所开放的API的证书信息
.licenseUrl("http://license.html")//
.version("v1.0.0")//
.build();
}
}
在上述的配置文件中,着重来看 'createRestApi’方法中的一些配置:
.protocols() // 配置传输协议,完成该配置以后就可以看到下图内容
.host("127.0.0.1:8089") // 设置提供API的主机地址,不指定时就是当前主机,一般用于解决swagger文档的部署地址与API服务的地址不在一台机器上
修改以后页面上的Base URL就会修改:
.produces() // 设置响应的数据MIME类型
如上述配置文件中设置为"application/json",则每一个API的返回数据部分就会多一个MIME类型提示:
.globalOperationParameters() // 在每一个方法下添加一个公共的参数
如上述配置中添加了token参数,这里来看一下文档页面:
.securitySchemes()
.securityContexts()
securitySchemes设定接口的安全验证,添加了该项以后,页面上就会出现Authorization的标识,如下图:
但是此时由于没有设定授权的范围,所以每一个需要验证权限的API上还不会出现小锁的标识,当配置了securityContexts属性以后,就会在对应的API上出现小锁的标识。最终的界面效果如下: