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

- 核心配置类:
- 位置:com.zzyl.web.core.config.SwaggerConfig
- 请设计prompt提示词,来阅读以下代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
| 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;
@Configuration public class SwaggerConfig { @Autowired private RuoYiConfig ruoyiConfig;
@Value("${Swagger.enabled}") private boolean enabled;
@Value("${Swagger.pathMapping}") private String pathMapping;
@Bean public Docket createRestApi() { return new Docket(DocumentationType.OAS_30) .enable(enabled) .apiInfo(apiInfo()) .select() .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)) .paths(PathSelectors.any()) .build() .securitySchemes(securitySchemes()) .securityContexts(securityContexts()) .pathMapping(pathMapping); }
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() { return new ApiInfoBuilder() .title("标题:若依管理系统_接口文档") .description("描述:用于管理集团旗下公司的人员信息,具体包括XXX,XXX模块...") .contact(new Contact(ruoyiConfig.getName(), null, null)) .version("版本号:" + ruoyiConfig.getVersion()) .build(); } }
|
访问地址


集成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实体类,咱们可以用上面两个注解在实体类中描述类和属性的含义
如下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
| @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;
@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进行描述
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| @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类的方法上指定返回值类型
返回一个对象
1 2 3 4 5 6 7
| @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类中的方法返回值:
1 2 3 4 5 6 7 8 9 10 11 12
|
@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这个类,咱们需要改造下这个类,让它具备接收泛型的能力
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
|
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() { }
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中分页查询的返回值
1 2 3 4 5 6 7 8 9 10 11 12 13
|
@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); }
|
重启服务,查看分页接口的返回值效果:
