Swagger在线接口文档
在线接口文档
在开发中,如果遇到后端项目开发完毕,但是前端项目还未开发完成,但又需要对后端接口进行测试
先前的解决方式是通过第三方接口测试软件,如postman、apifox等进行测试
但这类测试工具需要清楚的知道接口的路径、请求方式、请求参数,且还需要手动填写对应内容
当与前端对接时,后端还需要提供详细的接口文档,当接口文档编写的不及时或者更新不及时,就会造成信息闭塞,造成不必要的效率降低
Swagger简介
Swagger是一个规范和完整的框架,用于生成、描述、调用和可视化RESTful风格的Web服务
它的主要作用:
- 使得前后端分离开发更加方便,有利于团队协作
- 在线自动生成接口文档,降低后端开发人员编写接口文档的负担
- 功能测试
Spring已经将Swagger纳入自身的标准,建立了Spring-Swagger项目,现在加Springfox。通过在项目中引入Springfox,就可以非常简单快捷的使用Swagger啦
项目中集成
目前若依框架已经集成了Swagger,核心配置有如下几个:
- 关键依赖:

- 核心配置类: - 位置:com.zzyl.web.core.config.SwaggerConfig - 请设计prompt提示词,来阅读以下代码
package com.zzyl.web.core.config;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.zzyl.common.config.RuoYiConfig;
import io.Swagger.annotations.ApiOperation;
import io.Swagger.models.auth.In;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.ApiKey;
import springfox.documentation.service.AuthorizationScope;
import springfox.documentation.service.Contact;
import springfox.documentation.service.SecurityReference;
import springfox.documentation.service.SecurityScheme;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
/**
* Swagger2的接口配置
*
* @author ruoyi
*/
@Configuration
public class SwaggerConfig
{
/** 系统基础配置 */
@Autowired
private RuoYiConfig ruoyiConfig;
/** 是否开启Swagger */
@Value("${Swagger.enabled}")
private boolean enabled;
/** 设置请求的统一前缀 */
@Value("${Swagger.pathMapping}")
private String pathMapping;
/**
* 创建API
*/
@Bean
public Docket createRestApi()
{
return new Docket(DocumentationType.OAS_30)
// 是否启用Swagger
.enable(enabled)
// 用来创建该API的基本信息,展示在文档的页面中(自定义展示的信息)
.apiInfo(apiInfo())
// 设置哪些接口暴露给Swagger展示
.select()
// 扫描所有有注解的api,用这种方式更灵活
.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
// 扫描指定包中的Swagger注解
// .apis(RequestHandlerSelectors.basePackage("com.zzyl.project.tool.Swagger"))
// 扫描所有 .apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any())
.build()
/* 设置安全模式,Swagger可以设置访问token */
.securitySchemes(securitySchemes())
.securityContexts(securityContexts())
.pathMapping(pathMapping);
}
/**
* 安全模式,这里指定token通过Authorization头请求头传递
*/
private List<SecurityScheme> securitySchemes()
{
List<SecurityScheme> apiKeyList = new ArrayList<SecurityScheme>();
apiKeyList.add(new ApiKey("Authorization", "Authorization", In.HEADER.toValue()));
return apiKeyList;
}
/**
* 安全上下文
*/
private List<SecurityContext> securityContexts()
{
List<SecurityContext> securityContexts = new ArrayList<>();
securityContexts.add(
SecurityContext.builder()
.securityReferences(defaultAuth())
.operationSelector(o -> o.requestMappingPattern().matches("/.*"))
.build());
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<>();
securityReferences.add(new SecurityReference("Authorization", authorizationScopes));
return securityReferences;
}
/**
* 添加摘要信息
*/
private ApiInfo apiInfo()
{
// 用ApiInfoBuilder进行定制
return new ApiInfoBuilder()
// 设置标题
.title("标题:若依管理系统_接口文档")
// 描述
.description("描述:用于管理集团旗下公司的人员信息,具体包括XXX,XXX模块...")
// 作者信息
.contact(new Contact(ruoyiConfig.getName(), null, null))
// 版本
.version("版本号:" + ruoyiConfig.getVersion())
.build();
}
}
- 访问地址
- 方式一:系统内部访问

- 方式二:服务地址+/Swagger-ui/index.html — > http://localhost:8080/swagger-ui/index.html

集成knife4j
如果不习惯使用swagger可以使用前端UI的增强解决方案knife4j,对比swagger相比有以下优势:
- 友好界面
- 离线文档
- 接口排序
- 安全控制
- 在线调试
- 文档清晰
- 注解增强
- 容易上手。
目前,企业项目中一般都使用knife4j框架
若依文档中有相关介绍:插件集成 | RuoYi
实现后的效果:

- 可以下载离线文档:

Swagger使用
常见注解
通过注解可以控制生成的接口文档,使接口文档拥有更好的可读性,常用注解如下:
| 注解 | 说明 |
|---|---|
| @Api | 用在Controller类上,描述Controller类的作用 |
| @ApiOperation | 用在Controller类中的方法上,说明方法的用途、作用 |
| @ApiParam | 用在方法的参数上,描述单个形参的含义,适用于简单场景 |
| @ApiImplicitParam | 用在Controller类中的方法上方,描述单个形参的含义,适用于参数复杂或者需要详细描述参数的场景 |
| @ApiModel | 用在实体类上,描述用来接收参数或者响应结果的实体类的含义 |
| @ApiModelProperty | 用在实体类的属性上,用来描述实体类中属性的含义 |
请求体参数
一般的形参,如:id,status等这些,在controller的方法可以使用@ApiParam或者@ApiImplicitParam注解进行描述
如果接口是post、put请求,可能接收的是一个对象作为请求体参数,上面两个注解并不能很好的描述对象中的每一个属性,这个时候需要使用新的注解:@ApiModel和@ApiModelProperty
比如,在新增护理项目的时候,接收的参数为NursingProject实体类,咱们可以用上面两个注解在实体类中描述类和属性的含义
如下代码:
@ApiModel(value = "NursingProject" , description = "护理项目对象")
public class NursingProject extends BaseEntity
{
private static final long serialVersionUID = 1L;
/** 编号 */
@ApiModelProperty("编号")
private Long id;
/** 名称 */
@ApiModelProperty("名称")
@Excel(name = "名称")
private String name;
/** 排序号 */
@ApiModelProperty("排序号")
@Excel(name = "排序号")
private Integer orderNo;
/** 单位 */
@ApiModelProperty("单位")
@Excel(name = "单位")
private String unit;
/** 价格 */
@ApiModelProperty("价格")
@Excel(name = "价格")
private BigDecimal price;
/** 图片 */
@ApiModelProperty("图片")
@Excel(name = "图片")
private String image;
/** 护理要求 */
@ApiModelProperty("护理要求")
@Excel(name = "护理要求")
private String nursingRequirement;
/** 状态(0:禁用,1:启用) */
@ApiModelProperty("状态(0:禁用,1:启用)")
@Excel(name = "状态", readConverterExp = "0=:禁用,1:启用")
private Integer status;
public void setId(Long id)
{
this.id = id;
}
public Long getId()
{
return id;
}
public void setName(String name)
{
this.name = name;
}
public String getName()
{
return name;
}
public void setOrderNo(Integer orderNo)
{
this.orderNo = orderNo;
}
public Integer getOrderNo()
{
return orderNo;
}
public void setUnit(String unit)
{
this.unit = unit;
}
public String getUnit()
{
return unit;
}
public void setPrice(BigDecimal price)
{
this.price = price;
}
public BigDecimal getPrice()
{
return price;
}
public void setImage(String image)
{
this.image = image;
}
public String getImage()
{
return image;
}
public void setNursingRequirement(String nursingRequirement)
{
this.nursingRequirement = nursingRequirement;
}
public String getNursingRequirement()
{
return nursingRequirement;
}
public void setStatus(Integer status)
{
this.status = status;
}
public Integer getStatus()
{
return status;
}
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId())
.append("name", getName())
.append("orderNo", getOrderNo())
.append("unit", getUnit())
.append("price", getPrice())
.append("image", getImage())
.append("nursingRequirement", getNursingRequirement())
.append("status", getStatus())
.append("createBy", getCreateBy())
.append("updateBy", getUpdateBy())
.append("remark", getRemark())
.append("createTime", getCreateTime())
.append("updateTime", getUpdateTime())
.toString();
}
}
由于这个类继承了BaseEntity,还需要使用上面两个注解对BaseEntity进行描述
@ApiModel(value = "BaseEntity",description = "Entity基类")
public class BaseEntity implements Serializable
{
private static final long serialVersionUID = 1L;
/** 搜索值 */
@JsonIgnore
private String searchValue;
/** 创建者 */
@ApiModelProperty(value = "创建者")
private String createBy;
/** 创建时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@ApiModelProperty(value = "创建时间")
private Date createTime;
/** 更新者 */
@ApiModelProperty(value = "更新者")
private String updateBy;
/** 更新时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@ApiModelProperty(value = "更新时间")
private Date updateTime;
/** 备注 */
@ApiModelProperty(value = "备注")
private String remark;
/** 请求参数 */
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@ApiModelProperty(value = "请求参数")
private Map<String, Object> params;
}
响应体数据
当查询护理项目的时候,并不能展示详细的返回结果,如下图

想要解决这个问题,有两步操作
- 使用@ApiModel和@ApiModelProperty注解对返回值的类型进行说明(已完成)
- 需要在controller类的方法上指定返回值类型
- 返回一个对象
- 返回数据列表(分页或不分页)
返回一个对象
- 在目前的代码中,返回一个对象的接口代码,是根据id查询对应的对象,并返回
- 详细代码如下:
@ApiOperation("获取护理项目详细信息")
@PreAuthorize("@ss.hasPermi('nursing:nursingProject:query')")
@GetMapping(value = "/{id}")
public AjaxResult getInfo(@ApiParam("护理项目ID") @PathVariable("id") Long id)
{
return success(nursingProjectService.selectNursingProjectById(id));
}
这个代码并不能在Swagger中展示详细的返回结果说明,因为目前的返回值是一个AjaxResult,并没有指定泛型
咱们需要使用若依框架中提供的另外一个返回值类型:

在R这个类中也提供了详细的返回值的方法,有成功的,有失败的等等
修改NursingProjectController类中的方法返回值:
/**
* 获取护理项目详细信息
*/
@PreAuthorize("@ss.hasPermi('nursing:project:query')")
@GetMapping(value = "/{id}")
@ApiOperation(value = "获取护理项目详细信息", notes = "根据ID获取护理项目详细信息")
@ApiImplicitParam(name = "id", value = "护理项目ID", required = true, dataType = "Long", paramType = "path")
public R<NursingProject> getInfo(@PathVariable("id") Long id)
{
NursingProject nursingProject = nursingProjectService.selectNursingProjectById(id);
return R.ok(nursingProject);
}
最终的效果如下:

返回分页对象
目前的分页列表查询的返回值是TableDataInfo这个类,咱们需要改造下这个类,让它具备接收泛型的能力
- 定义类中的泛型T
- 把类中的所有问号改为T
/**
* 表格分页数据对象
*
* @author alexis
*/
public class TableDataInfo<T> implements Serializable
{
private static final long serialVersionUID = 1L;
/** 总记录数 */
private long total;
/** 列表数据 */
private List<T> rows;
/** 消息状态码 */
private int code;
/** 消息内容 */
private String msg;
/**
* 表格数据对象
*/
public TableDataInfo()
{
}
/**
* 分页
*
* @param list 列表数据
* @param total 总记录数
*/
public TableDataInfo(List<T> list, int total)
{
this.rows = list;
this.total = total;
}
public List<T> getRows()
{
return rows;
}
public void setRows(List<T> rows)
{
this.rows = rows;
}
//其他代码略...
}
修改controller中分页查询的返回值
/**
* 查询护理项目列表
*/
@PreAuthorize("@ss.hasPermi('nursing:project:list')")
@GetMapping("/list")
@ApiOperation(value = "查询护理项目列表", notes = "根据护理项目条件查询护理项目列表")
public TableDataInfo<List<NursingProject>> list(
@ApiParam(value = "护理项目查询条件", required = false) NursingProject nursingProject)
{
startPage();
List<NursingProject> list = nursingProjectService.selectNursingProjectList(nursingProject);
return getDataTable(list);
}
重启服务,查看分页接口的返回值效果:
