Swagger2简介
官网:https://swagger.io/
参考文档:https://github.com/swagger-api/swagger-core/wiki/Annotations
前言
在现在这个前后端分离的时代,如果你很幸运,进入了一个比较大型的公司,业务分工明确的公司,那么在公司所接触到的大多数的项目都是前后端分离的。(当然不绝对)。
前后端分离就给我们Java程序猿带了很大的方便,就比如说在中小型的公司里,我们的工作可能要自己写HTML,CSS,Vue等前端的页面代码,现在我们只专注后台的业务逻辑即可,但是前后端的时代,最大的障碍就是沟通。
就比如说前端登陆的表单里的name属性传了一个username,password;那么后端在测试接口的时候就要传同样名称的参数,而且有的时候,由于开发人员的开发习惯的问题,字段的命名千奇百怪,层出不穷。所以这个时候就急需要一个接口文档来根据你的代码动态的生成接口文档,提高前后端分离的开发·效率,减少返工。
Swagger的出现就是为了解决文档更新不及时所造成的一些问题而应运而生的。
Open Api是什么
OpenApi规范(Open Api Sepecification)以前也叫做Swagger规范,是Rest API(RestFul传参规范)描述格式
Open Api文件允许描述整个API,包括:
- 每个访问的地址 的类型,POST|GET
- 每个操作的参数,包括输入的参数
- 认证方法
- 连接消息,声明,使用团队和其他信息
Open Api规范可以使用Yaml或者JSON格式进行编号,这样更利于我们与机器进行交互,但是他们都是字符串 与开发语言无关。
特点
swagger特点:
- Restful API 文档 与API 定义同步更新(接口的文档在线自动生成)。
- 开箱即用,在线测试API(功能测试)。
- 支持多种语言 (如:Java,PHP等)
- 可视化 RESTful 风格的 Web 服务,前后端程序员 及时协商,尽早解决。
一、SpringFox
使用Swagger时如果碰见版本更新或迭代时,只需要更改Swagger的描述文件即可。)但是在频繁的更新项目版本时很多开发人员认为即使修改描述文件( yml或json )
也是一定的工作负担。久而久之就直接修改代码,而不去修改描述文件了, 这样基于描述文件生成接口文档也失去了意义。
- Marty Pitt编写了一个基在 Spring的组件swagger-springmvc. Spring-fox 就是根据这个组件发展而来的全新项目。
- Spring-fox是根据代码生成接口文档,所以正常的进行更新项目版本,修改代码即可,而不需要跟随修改描述文件。
- Spring-fox利用自身AOP特性,把Swagger集成进来,底层还是Swagger。但是使
用起来确方便很多。
所以在实际开发中,都是直接使用spring-fox。
二、Swagger2极致用法
2.1 Swagger-UI的使用
2.1.1 创建一个SpringBoot的项目
略
2.2.2 引入依赖
<!--Swagger2-->
<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>
2.3.3 编写一个Controller
这里延续使用MyBatis-Plus的数据库进行测试
@RestController
@RequestMapping("/product")
@Api(tags = "关于产品的接口")
public class ProductController {
@Autowired
private ProductService productService;
@GetMapping("/list")
@ApiOperation(value = "查询所有")
public List<Product> queryAll() {
return productService.list();
}
@PostMapping("/update")
@ApiOperation(value = "修改产品")
public String update(@RequestBody Map<String, Object> params) {
Product product = new Product();
product.setName((String) params.get("name"));
product.setPrice((Integer) params.get("price"));
UpdateWrapper<Product> updateWrapper = new UpdateWrapper<>();
updateWrapper.eq("id", params.get("id"));
boolean is_update = productService.update(product, updateWrapper);
if (is_update) {
return "修改成功";
}
return "修改失败";
}
@PostMapping("/add")
@ApiOperation(value = "新增产品")
public String add(@RequestBody Map<String, Object> params) {
Product product = new Product();
product.setName((String) params.get("name"));
product.setPrice((Integer) params.get("price"));
boolean is_add = productService.save(product);
if (is_add) {
return "新增成功";
}
return "新增失败";
}
@DeleteMapping("/delete/{id}")
@ApiOperation(value = "新增产品")
// 测试 Rest风格的参数需要将paramType=path
@ApiImplicitParam(value = "用户id", name = "id", paramType = "path", dataType = "Long")
public String delete(@PathVariable("id") Long id) {
UpdateWrapper<Product> updateWrapper = new UpdateWrapper<>();
updateWrapper.eq("id", id);
boolean is_delete = productService.remove(updateWrapper);
if (is_delete) {
return "删除成功";
}
return "删除失败";
}
}
登录localhost:8080/swagger-ui/index.html
这时候,我们可以使用Swagger2来进行接口的测试以上的四个CRUD的方法,顺便回顾下MyBati-Plus的相关知识。
2.3.3.1 测试新增方法
大家可以看一下,由于这里使用的是Map传参,也就看作是一个对象参数,所以在Controller使用了@ResponseBody注解,所以在Params
哪里看到地下有个Application/json的格式,在里面输入JSON格式的参数,就是前后端怎么传参,我们就怎们传参。
之前我们使用Ajax或者使用Axios封装的post方法或者是jQuery封装的Post请求也罢,反正都是一个套路
【Vue.axiso传值给后台接口】
var url = "换成你的地址";
var data = {} // 封装的参数对象
axios({
url,
data: qs.stringify(data), // 解析为JSON字串传输
method: 'post',
headers: {
'Content-Type':'application/json'
}
}).then(res => {
console.log(res)
})
同理,其他的方法测试也大同小异,不过不要太纠结于不认识的注解
@Apixxx
,这些Swagger里面的注解,后面会解释,这里如果有聪明的人也猜得八九不离十了。
2.3.3.2 测试修改方法
2.3.3.3 测试查看方法
2.3.3.4 测试删除方法
🔥🔥
注意
:测试RestFul风格的接口的时候,传参需要将@ApiImplicitParam里面的paramType修改为path
2.2 Swagger2配置
2.2.1 Docket
swagger的bean实例为:Docket
public class Docket implements DocumentationPlugin {
//Docket中有一个 ApiInfo 的属性,用来设置Info信息
private ApiInfo apiInfo = ApiInfo.DEFAULT;
//对应设置 ApiInfo 的方法
public Docket apiInfo(ApiInfo apiInfo) {
this.apiInfo = defaultIfAbsent(apiInfo, apiInfo);
return this;
}
}
2.2.2 接口信息设置:
ApiInfo
public class ApiInfo {
//ApiInfo设置了默认的 ApiInfo 值
public static final ApiInfo DEFAULT = new ApiInfo(
//title:标题
"Api Documentation",
//description:API描述
"Api Documentation",
//version:版本
"1.0",
"urn:tos",
//作者信息,是个引用数据类型,要自己new
DEFAULT_CONTACT,
"Apache 2.0",
"http://www.apache.org/licenses/LICENSE-2.0",
new ArrayList<VendorExtension>());
}
【实例代码】
配置Swagger2接口文档的相关配置信息,一般我们都会通过配置一个配置类完成,具体如下:
@Configuration
public class SwaggerConfig {
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
// 扫描Controller包下的类自动生存接口文档(包含子包)
.apis(RequestHandlerSelectors.basePackage("com.wei.controller"))
// 路径使用any风格
.paths(PathSelectors.any())
.build()
// 接口文档的基本信息
.apiInfo(apiInfo());
}
/**
* 接口文档详细信息 API帮助文档的描述信息
*
* @return
*/
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("Swagger2学习项目测试接口")// 标题
.contact(new Contact("@WAT_Y的Swagger学习开发文档", "http://www.weiyongpeng.com", "1655216164@163.com"))
.description("wyp-api文档") // 描述信息
.termsOfServiceUrl("http://www.localhost:8080") // 团队协作的URL
.version("1.0.0") // 版本
.build(); // 构建函数
}
}
2.2.3 配置扫描接口
生成Docket对象时,设置生成API,方法为:
-
.select()
.apis(RequestHandlerselector.配置方式)
.build()
-
apis()内部的 RequestHandlerselectors,配置要扫描接口的方式
-
basePackage("包名"):指定要扫描的包指定扫描方式
-
any():扫描全部
-
none( ):不扫描
-
withclassAnnotation:扫描类上的注解,参数是一个注解的反射对象
-
withMethodAnnotation:扫描方法上的注解
-
-
public class SwaggerConfig {
//配置了Swagger的Docter的bean实例
@Bean
public Docket docket(){
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
//选择接口
.select()
//选择接口
.apis(RequestHandlerSelectors.basePackage("com.wei.controller"))
//build()一般表示工厂设计模式
.build();
}
2.3.4 配置分组
[分组步骤:]
-
创建不同的 Docket 对象
-
使用groupName(组名)方法为不同的Docket组别命名
@Configuration
@EnableSwagger2
public class SwaggerConfig {
//配置了Swagger的Docter的bean实例
@Bean
public Docket docket1(){
return new Docket(DocumentationType.SWAGGER_2)
//为分组命名
.groupName("order-api")
.apiInfo(apiInfo1())
//选择接口
.select()
//选择接口
.apis(RequestHandlerSelectors.basePackage("com.wei.order.controller"))
//build()一般表示工厂设计模式
.build();
}
@Bean
public Docket docket2(){
return new Docket(DocumentationType.SWAGGER_2)
.groupName("product-api")
.apiInfo(apiInfo2())
//选择接口
.select()
//选择接口
.apis(RequestHandlerSelectors.basePackage("com.wei.product.controller"))
//build()一般表示工厂设计模式
.build();
}
private ApiInfo apiInfo1(){
//作者信息
Contact contact = new Contact("OrderBy_WEI","","921506729@qq.com");
return new ApiInfo(
"Order订单API接口文档",
"Swagger2综合练习",
"1.0",
"urn:tos",
contact,
"Apache 2.0",
"http://www.apache.org/licenses/LICENSE-2.0",
new ArrayList<>());
}
private ApiInfo apiInfo2(){
//作者信息
Contact contact = new Contact("ProductBy_LI","","12435@qq.com");
return new ApiInfo(
"Product订单API接口文档",
"Swagger2综合练习",
"1.0",
"urn:tos",
contact,
"Apache 2.0",
"http://www.apache.org/licenses/LICENSE-2.0",
new ArrayList<>());
}
}
2.3.5 自定义注解配置
声明自定义注解
// @Target 这个接口可以标注在什么上 METHOD表示方法
@Target({ElementType.METHOD,ElementType.TYPE})
// @Retention表示在什么时候使用
// RetentionPolicy.RUNTIME 运行时有效
// RetentionPolicy.SOURCE 源码中有效
// RetentionPolicy.CLASS 字节码中有效
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
// 自定义注解中的属性 相当于MyAnnotation(value="")
String value() default "";
}
@Target注解
:表示当前注解可以使用在什么地方@Rentention注解
:表示当前注解可以在什么时候起作用
如果有不会声明自定义注解的伙伴,可以找一个SpringBoot的注解点进去看看
使用自定义注解
@DeleteMapping("/delete/{id}")
@ApiOperation(value = "删除产品")
// 测试 Rest风格的参数需要将paramType=path
@ApiImplicitParam(value = "用户id", name = "id", paramType = "path", dataType = "Long")
@MyAnnotation
// 自定义注解
public String delete(@PathVariable("id") Long id) {
UpdateWrapper<Product> updateWrapper = new UpdateWrapper<>();
updateWrapper.eq("id", id);
boolean is_delete = productService.remove(updateWrapper);
if (is_delete) {
return "删除成功";
}
return "删除失败";
}
这时候提一个需求,让加了自定义注解的方法在Swagger里面不显示
【配置】
.apis(Predicates.not( // not 表示取反
// withMethodAnnotation表示当方法上有注解时执行
RequestHandlerSelectors.withMethodAnnotation(MyAnnotation.class)
))
刷新swagger-ui的页面,发现加了自定义注解的方法果真不显示了
三、Swagger2常用注解
3.1 @Api
@Api是类上的注解,控制整个类生成接口信息的内容
tags:
类上的名称,可以有多个值,定义多个就在UI界面上显示多个接口栏- description:描述信息,已过时
- value:该参数没什么意义,在UI界面上不显示,所以不用配置
@Api(tags = "关于产品的接口",description = "产品CRUD的接口")
public class ProductController {
// 接口定义
}
3.2 @ApiOperation
该注解主要用于方法上,描述一个接口的信息
value:
接口方法的用途和作用notes:
方法的注意事项和备注- tags:说明该方法的作用,参数是个数组,可以填多个。
- 格式:tags={“作用1”,“作用2”} (在这里建议不使用这个参数,会使界面看上去有点乱,前两个常用)
@DeleteMapping("/delete/{id}")
@ApiOperation(value = "删除产品",notes = "使用RestFul风格传参")
public String delete(@PathVariable("id") Long id) {}
3.3 @ApiParam
主要用于方法,参数
,字段说明。 表示对参数的要求和说明
- name=“参数名称”
- value=“参数的简要说明”
- defaultValue=“参数默认值”
- required=“true” 表示属性是否必填,默认为false
注意
这个与@ReuestParam(required=true)是不冲突的,也就是说swagge里的required属性不影响@ReuestParam的required属性
3.4 @ApiIgnore
用于类或者方法上,不被显示在页面上
@ApiIgnore
// 自定义注解
public String delete(@PathVariable("id") Long id) {}
效果和自定义的注解功能一致,所以我们可以完全不用写那个自定义注解
3.5 @ApiImplicitParams
用在请求的方法上,包含多@ApiImplicitParam,通常来与@ApiImplicitParam连用
3.6 @ApiImplicitParam
用于方法,表示单独的请求参数
- name=“参数ming”
- value=“参数说明” descrption
- dataType=“数据类型”
- paramType=“query” 表示参数放在哪里
- header 请求参数的获取:@RequestHeader
- query 请求参数的获取:@RequestParam
- path(用于restful接口) 请求参数的获取:@PathVariable
- body(不常用)
- form(不常用)
- defaultValue=“参数的默认值”
- required=“true” 表示参数是否必须传
3.7 @ApiModel
用于响应实体类上,用于说明实体作用
@ApiModel(value = "产品表")
public class Product {
// xxx
}
3.8 @ApiModelProperty
用在属性上,描述实体类的属性
- value=“用户名” 描述参数的意义
- name=“name” 参数的变量名
- required=true 参数是否必选
@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel(value = "产品表")
public class Product {
@TableId(value = "id", type = IdType.AUTO)
@ApiModelProperty(value = "主键")
private Long id;
@ApiModelProperty(value = "名称")
private String name;
@ApiModelProperty(value = "价格")
private Integer price;
@Version
@ApiModelProperty(value = "版本号")
private Integer version;
}