由于默认的导出模板形式不符合公司文档格式要求,最典型的就是要求增加每个字段的长度,因此
在官方文档中找到knife4j-vue,进行定制开发,
主要更改文件涉及到Knife4jAsync.js(为字段长度进行赋值)及wordTransform.js(定义输出文档格式)
swagger默认调用后端的接口
Request URL:
http://192.168.1.6:8080/v2/api-docs?group=1.0
接口返回报文格式如下,可以看到很多注解字段后端并没有返回给前端,意味着前端不能用到这些字段,得找到一个字段用于表示数据长度,
{
"swagger": "2.0",
"info": {
"description": "# swagger-bootstrap-ui-demo RESTful APIs",
"version": "1.0",
"title": "Survey RESTful APIs",
"termsOfService": "http://localhost:8080/"
},
"host": "192.168.1.6:8080",
"basePath": "/",
"tags": [{
"name": "UserController_2",
"x-author": "wy",
"x-order": "2147483647"
}],
"paths": {
"/user/saveUser": {
"post": {
"tags": ["UserController_2"],
"summary": "保存测试接口",
"description": "保存测试接口222",
"operationId": "saveUserUsingPOST",
"consumes": ["application/json"],
"produces": ["*/*"],
"parameters": [{
"in": "body",
"name": "user",
"description": "user",
"required": true,
"schema": {
"originalRef": "User",
"$ref": "#/definitions/User"
}
}],
"responses": {
"200": {
"description": "OK",
"schema": {
"originalRef": "响应信息主体«UserResponse»",
"$ref": "#/definitions/响应信息主体«UserResponse»"
}
},
"201": {
"description": "Created"
},
"401": {
"description": "Unauthorized"
},
"403": {
"description": "Forbidden"
},
"404": {
"description": "Not Found"
}
},
"deprecated": false,
"x-order": "2147483647"
}
}
},
"definitions": {
"User": {
"type": "object",
"required": ["message"],
"properties": {
"message": {
"type": "string",
"example": 96,
"description": "入参信息"
},
"id": {
"type": "string",
"example": 1,
"description": "主键",
"enum": ["32"]
}
},
"title": "User"
},
"UserResponse": {
"type": "object",
"required": ["message", "name"],
"properties": {
"message": {
"type": "string",
"example": 9600,
"description": "入参信息"
},
"name": {
"type": "string",
"example": 1200,
"description": "用户名"
}
},
"title": "UserResponse"
},
"响应信息主体«UserResponse»": {
"type": "object",
"required": ["code", "data"],
"properties": {
"code": {
"type": "integer",
"format": "int32",
"example": 200,
"description": "返回标记:成功标记=200,失败标记=-1"
},
"data": {
"example": "null",
"description": "返回数据",
"originalRef": "UserResponse",
"$ref": "#/definitions/UserResponse"
},
"msg": {
"type": "string",
"example": "请求成功",
"description": "返回信息"
}
},
"title": "响应信息主体«UserResponse»"
}
},
"x-openapi": {
"x-markdownFiles": [{
"name": "项目文档",
"children": [{
"title": "剑指 Offer 16. 数值的整数次方(快速幂).md",
"content": "#### [剑指 Offer 16. 数值的整数次方](https://leetcode-cn.com/problems/shu-zhi-de-zheng-shu-ci-fang-lcof/)(快速幂)\n\n![image-20210918141143858](C:\\Users\\WY\\AppData\\Roaming\\Typora\\typora-user-images\\image-20210918141143858.png)\n\n哪个位是1,就乘对应的权重值\n\n```java\nclass Solution {\n public double myPow(double x, int n) {\n if(x == 0) return 0;\n long b = n;\n double res = 1.0;\n if(b < 0) {\n x = 1 / x;\n b = -b;\n }\n while(b > 0) {\n if((b & 1) == 1) res *= x;\n x *= x;\n b >>= 1;\n }\n return res;\n }\n}\n```\n\n**递归解法(用这个):**\n\n```java\nclass Solution {\n public double myPow(double x, int n) {\n if(n<0){\n n = -n;\n x = 1.0/x;\n }\n return qsm(x,n);\n }\n\n double qsm(double x, int n){\n if(x==0){\n return 0;\n }else if(n==0){\n return 1;\n }\n double ans = qsm(x,n/2);\n return n%2==0?ans*ans:ans*ans*x;\n }\n}\n```\n\n"
}]
}],
"x-setting": {
"language": "zh-CN",
"enableSwaggerModels": true,
"swaggerModelName": "Swagger Models",
"enableReloadCacheParameter": false,
"enableAfterScript": true,
"enableDocumentManage": true,
"enableVersion": false,
"enableRequestCache": true,
"enableFilterMultipartApis": false,
"enableFilterMultipartApiMethodType": "POST",
"enableHost": true,
"enableHostText": ""
}
}
}
首先要知道@ApiModelProperty是swagger的注解,它的作用是添加和操作属性模块的数据,下面是它内部的常用属性:
1、value()
源码:String value() default "";
1
参数类型为String,作用为此属性的简要描述。
2、name()
源码: String name() default "";
1
参数类型为String,作用为允许重写属性的名称。
3、allowableValues()
源码:String allowableValues() default "";
参数类型为String,作用为限制此参数存储的长度。
4、access()
源码:String access() default "";
参数类型为String,作用为允许从API文档中过滤属性
5、notes()
源码: String notes() default "";
参数类型为String,作用为该字段的注释说明
6、dataType()
源码: String dataType() default "";
参数类型为String,作用为参数的数据类型。
7、required()
源码:boolean required() default false;
参数类型为String,作用为指定参数是否可以为空,默认为false
8、 position()
源码:int position() default 0;
参数类型为int,作用为允许显式地对模型中的属性排序。
9、hidden()
源码:boolean hidden() default false;
参数类型为boolean,作用为是否允许模型属性隐藏在Swagger模型定义中,默认为false。
10、example()
源码:String example() default "";
参数为String类型,作用为属性的示例值。
11、readOnly()
源码:boolean readOnly() default false;
参数类型为boolean,作用为是否允许将属性指定为只读,默认为false。
12、reference()
源码: String reference() default "";
参数类型为String,作用为指定对对应类型定义的引用,重写指定的任何其他数据名称。
13、allowEmptyValue()
源码:boolean allowEmptyValue() default false;
参数类型为boolean,作用为是否允许传递空值,默认为false
示例:
@Data
public class User {
@ApiModelProperty(value = "主键",name = "id",
allowableValues = "32",
access = "1",
notes = "用户的id",
dataType = "int",
required = false,
position = 1,
hidden = false,
example = "1",
readOnly = false,
reference = "id",
allowEmptyValue = false)
private String id;
@ApiModelProperty(required = true, notes = "入参信息", example = "96")
private String message;
}
后端代码用例 knife4j-example: knife4j的小demo
knife4j UI包是把前端文件打成webJar包,在项目中以jar包形式引用形式,
最终改好的前端打webJar包,然后在项目中去除旧包依赖,加上新UI打成的本地JAR包即可解决定制问题,下图中是增加利用了自定义文档功能,主要用户附录,修改记录之类的说明
一:如何解决泛型多个不同类型结果
@ApiResponses说明方法多个返回值,注意在创建swagger版本要指定版本为
return new Docket(DocumentationType.SWAGGER_2),sawgger3 jar包是支持向下兼容的,不需要降低swagger版本,如果一个接口既有swagger2也有OAS_30版本 就会出现2个分组,如果你创建OAS_30版本,注释用swagger2注解比如ApiResponse,就不会产生多态效果,这是一个springfox BUG,官网2年没更新了。
可同时说明多个错误码的响应内容
@ApiResponses({
@ApiResponse(code = 200, message = "SUCCESS", response = ResultListGenericity.class),
@ApiResponse(code = 400, message = "未授权"),
@ApiResponse(code = 401, message = "授权过期")
})
PS:response返回的内容一般是 Void.class ,为了返回泛型类或List<T> ,需要创建一个新类去继承要返回的类,然后response中返回新类即可。
如:
@ApiResponse(code = 200, message = "SUCCESS", response = ResultGenericity.class)
public Result detail(@PathVariable Integer id) {
return ResultGenerator.genSuccessResult(new User());
}
private static class ResultGenericity extends Result<User> {
}
使用泛型时,如果只存在一种格式的返回,可以在返回结果写死类型,如果存在多个不同格式,需要使用@ApiResponses用于标记不同的返回结果样式
同时在前端修改,吧默认的响应状态码改为我们想要的返回结果
@ApiOperation(value = "保存测试接口", notes = "保存测试接口notes",position=2)
@PostMapping("saveUser")
@ApiOperationSupport(order=2,author = "{\n" +
" \"data\": zsasasa,\n" +
" \"message\": zssssss,\n" +
" \"id\": 1\n" +
"}")
@ApiResponses({
@ApiResponse(code = 200, message = "盘点", response = Demo1.class),
@ApiResponse(code = 400, message = "理货",response = Demo2.class),
})
public <T> R<UserResponse> saveUser(@RequestBody User<T> user){
logger.info("传入的user对象为:{}", user);
ResultBO results = new ResultBO();
results.setCode(200);
results.setContent(user);
results.setMsg("调用测试接口成功!");
results.setSucceed(true);
logger.info("调用测试接口成功");
return R.ok(new UserResponse());
}
function createWordApiResponseParameters(apiInfo, markdownCollections) {
//判断是否多个schema
if (apiInfo.multipartResponseSchema) {
var multipartData = apiInfo.multipCodeDatas;
if (KUtils.arrNotEmpty(multipartData)) {
multipartData.forEach(function (resp) {
console.log("返回结果"+resp)
wordLines(markdownCollections);
markdownCollections.push('<div class="knife4j-word-title">返回结果-'+KUtils.toString(resp.description, '')+'</div>');
//markdownCollections.push('**响应状态码-' + KUtils.toString(resp.code, '') + '**:');原先文档输出
createWordApiResponseSingleParam(resp, markdownCollections);
})
}
} else {
//单个
createWordApiResponseSingleParam(apiInfo.multipData, markdownCollections);
}
}
但是如果面对请求参数带泛型的,我的处理方式是利用扩展注解中author字段,先在里面写上描述文字,然后稍微改一下前端文件即可
/* if(KUtils.strNotBlank(apiInfo.author)){
markdownCollections.push('<div class="knife4j-word-title">开发者</div>');
markdownCollections.push('<div class="knife4j-word-content">'+KUtils.toString(apiInfo.author, '暂无')+'</div>');
}*/
//判断是否有请求示例
if (KUtils.checkUndefined(apiInfo.requestValue)) {
//如果存在多态,则用扩展字段author代替
if(KUtils.strNotBlank(apiInfo.author)){
apiInfo.requestValue=apiInfo.author;
}
二:knife4j 3.0.3 swagger2 自定义增强文档不生效
这是bug,目前可以修改源码以让其支持swagger2版本的自定义文档,源码是全部都按data['x-openapi'];情况进行判断了,没有考虑向下兼容
SwaggerBootstrapUi.prototype.openDocuments=function(data){
var that=this;
debugger
//判断是否包含x-openapi的增强
var openapi=data['x-openapi'];
var mkdFiles;
if(KUtils.checkUndefined(openapi)) {
mkdFiles=openapi['x-markdownFiles'];
}else{
mkdFiles=data['x-markdownFiles'];
}
var currentInstanceMarkdownFileMap={};
mkdFiles.forEach(mdTag=>{
在改造过程中,也会存在一些问题,比如默认的swagger注解不够用的问题,默认的swagger后端并不会返回的注解属性内容,如果后面再增加一项说明,就需要考虑改后端swagger框架,
参考官网资料:knife4j