此文书写排版逻辑如下
一: 在老旧项目中,如直接返回 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,不仅可以返回 json 结果,还可以定义返回的 HttpHeaders 和 HttpStatus

/**

	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 上的返回值描述如下:

QQ截图20200716150947.png

而当时的作者已经不可考,需在不改变代码的前提下,为 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

	/**业务代码**/	
}