目录
一、Swagger简介
1.1 Swagger是什么?
1.2 为什么要用Swagger
1.3 Swagger注解
二、Spring集成Swagger
三、测试环境配置
一、Swagger简介
1.1 Swagger是什么?
Swagger是一款RESTFUL接口的文档在线自动生成+功能测试功能软件。Swagger是一个规范和完整的框架,用于生成、描述、调用和可视化RESTful风格的Web服务。目标是使客户端和文件系统作为服务器以同样的速度来更新文件的方法,参数和模型紧密集成到服务器。
1.2 为什么要用Swagger
1.2.1:对于后端开发人员来说
- 不用再手写WiKi接口拼大量的参数,避免手写错误
- 对代码侵入性低,采用全注解的方式,开发简单
- 方法参数名修改、增加、减少参数都可以直接生效,不用手动维护
- 缺点:增加了开发成本,写接口还得再写一套参数配置
1.2.2:对于前端开发来说
- 后端只需要定义好接口,会自动生成文档,接口功能、参数一目了然
- 联调方便,如果出问题,直接测试接口,实时检查参数和返回值,就可以快速定位是前端还是后端的问题
1.2.3:对于测试
- 对于某些没有前端界面UI的功能,可以用它来测试接口
- 操作简单,不用了解具体代码就可以操作
- 操作简单,不用了解具体代码就可以操作
1.3 Swagger注解
@Api注解 用在类上,说明该类的作用。可以标记一个Controller类做为swagger文档资源。
属性 | 说明 |
---|---|
value | url的路径值 |
tags | 如果设置这个值、value的值会被覆盖 |
produces | 返回的格式类型例如:"application/json, application/xml" |
consumes | 接收请求参数的类型例如:"application/json, application/xml" |
protocols | Possible values: http, https, ws, wss. |
authorizations | 高级特性认证时配置 |
@ApiOperation注解 用在方法上,说明方法的作用,每一个url资源的定义。
属性 | 说明 |
---|---|
value | url的路径值 |
tags | 如果设置这个值、value的值会被覆盖 |
produces | 返回的格式类型例如:"application/json, application/xml" |
consumes | 接收请求参数的类型例如:"application/json, application/xml" |
hidden | 是否在文档中显示 |
notes | 注释说明 |
response | 返回的对象 |
responseContainer | 这些对象是有效的 "List", "Set" or "Map".,其他无效 |
responseReference | 指定对响应类型的引用。指定的引用可以是本地的,也可以是远程的*将按原样使用,并覆盖任何指定的response()类 |
responseHeaders | 响应旁边提供的可能标题列表 |
httpMethod | "GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS" and "PATCH" |
code | http的状态码 默认 200 |
@ApilmplicitParam 注解用来描述一个参数,可以配置参数的中文含义,也可以给参数设置默认值,这样在接口测试的时候可以避免手动输入;
属性 | 说明 |
---|---|
paramType | 参数放在哪个地方 |
name | 参数名称 |
value | 参数代表的含义 |
dataType | 参数类型 |
dataTypeClass | 参数类型 |
required | 是否必要 |
defaultValue | 参数的默认值 |
paramType参数:
类型 作用 path 以地址的形式提交数据,用于restful接口。请求参数采用@PathVariable获取 query 直接跟参数完成自动映射赋值。请求参数可采用@RequestParam获取 body 以流的形式提交,仅支持POST。请求参数采用@RequestBody获取 header 参数在request headers里边提交。请求参数采用@RequestHeader获取 form 以form表单的形式提交,仅支持POST。
@ApiModel注解:描述一个Model的信息(这种一般用在post创建的时候,使用@RequestBody这样的场景,请求参数无法使用 @ApiImplicitParam注解进行描述的时候;
@ApiModelProperty注解描述一个model的属性。
属性 | 说明 |
---|---|
value | 字段说明 |
name | 参数名称 |
dataType | 参数类型 |
hidden | 在文档中隐藏 |
required | 是否必要 |
example | 举例说明 |
notes | 注释说明 |
@ApiParam注解 作用在方法的参数上,用来描述接口的参数信息(一个参设置一个)
@ApiParam`必须与`@RequestParam`、`@PathVariable`和`@RequestHeader`一起使用。
属性 | 说明 |
---|---|
name | 参数名称 |
value | 参数简单描述 |
defaultValue | 描述参数默认值 |
required | 是否为必传参数, false:非必传; true:必传 |
allowMultiple | 指定参数是否可以通过多次出现来接收多个值 |
hidden | 隐藏参数列表中的参数 |
example | 非请求体(body)类型的单个参数示例 |
examples | @Example(value = @ExampleProperty(mediaType = “”, value = “”)) 参数示例,仅适用于请求体类型的请求 |
二、Spring集成Swagger
1、导入依赖
<!--swager2-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<!--swagger2模版样式-->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>swagger-bootstrap-ui</artifactId>
<version>1.9.6</version>
</dependency>
新版(3.0)的直接加入启动器
<dependency> <groupId>io.springfox</groupId> <artifactId>springfox-boot-starter</artifactId> <version>3.0.0</version> </dependency>
3.0版本后不需要在加入@enableopenapi,和@enableswagger2这两个注解
2、创建Swagger2配置类
package com.ycxw.boot.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@Configuration
@EnableSwagger2
@Profile({"dev", "test"}) //dev(开发)、test(测试)、prod(生产)
public class Swagger2Configuration extends WebMvcConfigurationSupport {
/**
* 创建该API的基本信息 http://项目实际地址/doc.html
*/
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("SpringBoot集成Swagger2")
.description("测试系统")
.termsOfServiceUrl("ycxw320.blog.csdn.net")
.version("1.0.0")
.build();
}
/**
* 创建API应用
* apis接口包扫描路径
* apiInfo() 增加API相关信息
* 通过select()函数返回一个ApiSelectorBuilder实例,用来控制哪些接口暴露给Swagger来展现,
* 本例采用指定扫描的包路径来定义指定要建立API的目录。
*/
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.ycxw.boot.controller"))
.paths(PathSelectors.any())
.build();
}
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
}
}
3、接着通过mybatis生成代码...
4、Swagger类与属性注释
package com.ycxw.boot.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
* <p>
* 书本信息表
* </p>
*
* @author 云村小威
* @since 2023-12-20
*/
@Data
@Accessors(chain = true)
@TableName("t_book")
@ApiModel("书籍对象")
public class Book implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 书本编号
*/
@TableId("id")
@ApiModelProperty("书籍编号")
private String id;
/**
* 书本名称
*/
@TableField("bookname")
@ApiModelProperty("书籍名称")
private String bookname;
/**
* 书本价格
*/
@TableField("price")
@ApiModelProperty("书籍价格")
private Float price;
/**
* 书本类型
*/
@TableField("booktype")
@ApiModelProperty("书籍类型")
private String booktype;
/*逻辑删除(隐藏)*/
@TableField("status")
@ApiModelProperty(hidden = true)
private Integer status;
/*乐观锁(隐藏)*/
@TableField("version")
@ApiModelProperty(hidden = true)
private Integer version;
}
5、Controller与接口方法注释
package com.ycxw.boot.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ycxw.boot.entity.Book;
import com.ycxw.boot.service.IBookService;
import com.ycxw.boot.tools.JsonResponseBody;
import com.ycxw.boot.tools.JsonResponseStatus;
import io.swagger.annotations.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Objects;
/**
* <p>
* 书本信息表 前端控制器
* </p>
*
* @author 云村小威
* @since 2023-12-20
*/
@RestController
@RequestMapping("/book")
@Api(value = "书籍管理")
public class BookController {
@Autowired
private IBookService bookService;
@GetMapping("/list")
@ApiOperation(value = "书籍查询所有")
public JsonResponseBody<List<Book>> list() {
List<Book> list = bookService.list();
if (!list.isEmpty()) {
return JsonResponseBody.other(JsonResponseStatus.OK);
} else {
return JsonResponseBody.other(JsonResponseStatus.RESULT_EMPTY);
}
}
@PostMapping("/save")
@ApiOperation(value = "新增书籍")
public JsonResponseBody<Boolean> save(Book book) {
boolean save = bookService.save(book);
return JsonResponseBody.success(save);
}
@GetMapping("/likeName")
@ApiOperation(value = "获取商品集合,模糊查询")
public JsonResponseBody<List<Book>> list(Book goods) {
QueryWrapper<Book> wrapper = new QueryWrapper<>();
wrapper.like(StringUtils.isNotEmpty(goods.getBookname()), "bookname", goods.getBookname());
List<Book> list = bookService.list(wrapper);
return JsonResponseBody.success(list);
}
@GetMapping("/show")
@ApiOperation(value = "获取商品集合,模糊查询+大于查询")
@ApiImplicitParams({
@ApiImplicitParam(name = "price", paramType = "query", value = "价格", required = true),
@ApiImplicitParam(name = "bookname", paramType = "query", value = "名称", required = true)
})
public JsonResponseBody<List<Book>> listByNameAndPrice(Double price, String bookname) {
QueryWrapper<Book> wrapper = new QueryWrapper<>();
wrapper.like(StringUtils.isNotEmpty(bookname), "bookname", bookname);
wrapper.gt(Objects.nonNull(price), "price", price);
List<Book> list = bookService.list(wrapper);
return JsonResponseBody.success(list);
}
@GetMapping("/page")
@ApiOperation(value = "获取商品集合,分页查询+模糊查询")
public JsonResponseBody<List<Book>> listPage(
@ApiParam(name = "bookname", value = "模糊查询关键字")
@RequestParam("bookname")
String bookname
) {
QueryWrapper<Book> wrapper = new QueryWrapper<>();
wrapper.like(StringUtils.isNotEmpty(bookname), "bookname", bookname);
Page<Book> page = new Page<>();
Page<Book> res = bookService.page(page, wrapper);
return JsonResponseBody.success(res.getRecords(), res.getTotal());
}
}
6、访问本地链接
启动项目访问:http://localhost:8080/doc.html
通过Swagger视图可以看到该项目的一些信息,还有每个controller层的接口方法,点击接口可以查看该接口的一些信息,包括请求方式、地址、响应参数以及结果...
三、测试环境配置
在swagger配置类中我添加了一个这样的注解:
@Profile({"dev", "test"}) //dev(开发)、test(测试)、prod(生产)
因为需要配置该测试文档只能在项目开发和测试阶段才能使用,在yml配置中是这样配置的:
spring:
profiles:
active: test
当然这样定死显然是不好的,所以去掉这个配置,将项目直接打成jar包,通过指令设置测试环境运行。
1、设置开发环境中打开swagger测试文档
2、设置生成环境打开文档
可以看到在生成环境中不可查看接口文档
处于安全考虑,我们在发布的时候需要关闭Swagger,或者利用security授权登录才可查看接口文档
作为开发者,养成良好的文档规范习惯是非常重要的,无论使用Swagger还是其他文档工具,编写清晰、详尽的API文档都应该是我们的素养之一。