此文书写排版逻辑如下
一: 在老旧项目中,如直接返回 Map<>,List<>,Object 未明确指定返回体,导致Swagger浏览不友好,附解决办法
二:在一个严谨的项目中,合格的返回体定义,和Swagger说明
三: 自定义实现ModelPropertyBuilderPlugin适配处理,使用一些高级功能
写作使用的Swagger 版本在 1.8 到 2.8之间,2.9运行会有一个不影响使用的Exception
文中示例,代码总览: https://github.com/hkdijia/for-swagger
PS:本文适合已有开发经验人员,且了解Swagger基础知识,进行食用,篇幅原因,无法从头讲述Swagger由来~~
Swagger 常用的 api
数据模型注解: @ApiModel,实体描述;@ApiModelProperty,实体属性描述
接口注解: @ApiOperation,接口描述;@ApiIgnore,忽略此接口
控制器注解: @Api,控制器描述
输入参数注解: @ApiImplicitParams,接口多个参数;
@ApiImplicitParam,单个参数;@ApiParam,单个参数描述
响应数据注解: @ResponseHeader,响应值header;
@ApiResponses,响应值集;
@ApiResponse,单个响应值
在一般的接口约定中,(古老的 Jquery 也适用),需要定义清晰的返回体进行前后端交互,
如 HttpEntity 的子类 org.springframework.http.ResponseEntity
/**
public ResponseEntity(HttpStatus statusCode) {
super();
this.statusCode = statusCode;
}
public ResponseEntity(T body, HttpStatus statusCode) {
super(body);
this.statusCode = statusCode;
}
public ResponseEntity(MultiValueMap<String, String> headers, HttpStatus statusCode) {
super(headers);
this.statusCode = statusCode;
}
public ResponseEntity(T body, MultiValueMap<String, String> headers, HttpStatus statusCode) {
super(body, headers);
this.statusCode = statusCode;
}
然而实际操作上,再次进行了一些规约优化,如自定义类 R
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
@ApiModel(description = "返回信息")
public class R<T> implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "状态码")
private int code;
@ApiModelProperty(value = "是否成功")
private boolean success;
@ApiModelProperty("承载数据")
private T data;
@ApiModelProperty(value = "返回消息")
private String msg;
private R(IResultCode resultCode) {
this(resultCode, (Object)null, resultCode.getMessage());
}
private R(IResultCode resultCode, String msg) {
this(resultCode, (Object)null, msg);
}
private R(IResultCode resultCode, T data) {
this(resultCode, data, resultCode.getMessage());
}
private R(IResultCode resultCode, T data, String msg) {
this(resultCode.getCode(), data, msg);
}
private R(int code, T data, String msg) {
this.code = code;
this.data = data;
this.msg = msg;
this.success = ResultCode.SUCCESS.code == code;
}
public R() {
}
/**
get() and set()
**/
}
也可以优化返回给前端,铺垫完成,描述下实际开发中遇到的问题。如下:
@GET
@Path("/test")
@ApiOperation(value = "xxx", notes = "yyy")
public Object getApps(
@QueryParam(value = "zzz") int zzz){
/*
......
some code
......
*/
return Object
}
类似于这些接口,返回值写成了 Object,在 Swagger 上的返回值描述如下:
而当时的作者已经不可考,需在不改变代码的前提下,为 Swagger 文档提供可靠阅读
在这种情况下,我们可以通过 Swagger 注解如:
@ApiResponse(code = 200, message = "查询成功", response = XXX.class)
指定一个类,该类需要实现 Serializable ,并给相关属性添加注解 如 @ApiModelProperty 和 get() 、set() 方法,从而就能在 Swagger 的展示文档中,获得该接口的返回结果
tips:
上面都比较简单,真正麻烦在于,接口返回的数据多变,会根据传参条件的不同,出现不同维度的查询结果,这也是之前的作者,直接将 返回结果 用 Object 来描述的原因。而写这个 Swagger 文档则更需要 理解接口功能,并将返回结果,进行抽象
复杂的返回结果,如 Map<>,List<>,List<Map<>> 翻查资料,大概两种办法,都已上传代码
- 在常用的分页结果查询里面,通过抽象和继承的方式,封装基类,再拓展模型属性
1:如果返回的是 纯 List<>,我们先抽象一个返回类,然后描述为数组即可
@ApiResponse(code = 200, message = "查询成功", response = XXXpojo[].class)2: 分页场景下: 一般5个属性,total、totalPage、pageSize、pageIndex 封装成基类 A,创建 B 类继承 并拓展属性 contents 查询结果集即可,代码示例如下:
public class A implements Serializable {
private static final long serialVersionUID = 3913989539989396280L;
@ApiModelProperty("页码")
private Integer pageIndex;
@ApiModelProperty("页面记录条数")
private Integer pageSize;
@ApiModelProperty("总数")
private Integer total;
@ApiModelProperty("总页数")
private Integer totalPage;
/** get and set **/
@ApiModel(value = "B 接口查询XX列表", description = "")
public class B extends A {
private static final long serialVersionUID = 8621372814118181107L;
@ApiModelProperty("查询结果集")
private List<XXXVO> contents;
/** get and set **/
}
@ApiResponse(code = 200, message = "查询成功", response = B.class)
当然,上述的 XXXVO 需要进行抽象,总结一个实体类啊哈,需要实现 Serializable
有的时候, XXXVO 是一个组合实体类,同样可以再进行拓展增强,基本上适配复杂数据
对了,response = WWW.class 是不能传泛型的,会有泛型擦除情况,所以才会用继承
最后嘛,举个例子 Example Vaule 大概是这样滴, 模型注释就不发了,用了注解就会有
{
"pageIndex": 0,
"pageSize": 0,
"total": 0,
"contents": [
{
"id": "string",
"name": "string",
"managers": [
{}
],
"url": "string",
"tags": [
{
"id": "string",
"name": "string",
"tenant": "string"
}
]
}
],
"totalPage": 0
}
- 基于 Spring,通过 AOP 对 Swagger-UI 进行切面增强
这是我翻阅一个大佬的实现,第一是项目 Swagger 版本不一致,所以并没有安装大佬的思维,进行修改。但大佬的实现还是很厉害的,demo 里面实现了 Map<String,String> 通过自定义注解 和 pojo 完成了 增强
swagger2返回值Map,Json,实体类部分字段注释描述信息说明_Hpluvalbe的博客-CSDN博客_swagger2 字段注释
https://blog.csdn.net/Hpluvalbe/article/details/107102063
附录一个相对工整的 Controller 中 完备的 Swagger 标准答案
@RestController
@Path("aip/xxx")
@Api(tags = "kkk")
@ApiResponses({
@ApiResponse(code = 400, message = "错误的请求参数", response = Error.class),
@ApiResponse(code = 404, message = "操作失败,资源未找到", response = Error.class),
@ApiResponse(code = 500, message = "系统内部错误", response = Error.class)})
public class C{
@Path("/yyy")
@ApiOperation(value = "查询XXX", tags = {""}, notes = "查询XX")
@ApiResponses({
@ApiResponse(code = 200, message = "查询成功", response = C.class)})
public Object query(
@ApiParam("资源名称,模糊查询") @QueryParam("name") String name,
@ApiParam("资源类型") @QueryParam("type") List<String> types
/**业务代码**/
}