一、需求
由于我的controller是全部通用的,其他controller都会继承一些基础的接口,因此需要根据泛型动态生成参数描述,swagger又不支持map参数描述,需要进行扩展
我的controller是这样的
将reqObj与reqReplaceMap隐藏掉,把reqObj一一映射到query参数中去,在swagger管理页面中是下图这样的。红框中的是映射出来的参数
二、实现
maven用的是:
<dependency>
<groupId>com.battcn</groupId>
<artifactId>swagger-spring-boot-starter</artifactId>
<version>2.1.5-RELEASE</version>
</dependency>
swagger有很多插件,在工程启动的时候回去加载实现这些插件的类一层一层去做处理,进而对接口实现管理,这里实现OperationBuilderPlugin
接口,字段描述默认读取的是类字段的@ApiModelProperty
注解:
package com.zx.utils.config;
import com.fasterxml.classmate.ResolvedType;
import com.fasterxml.classmate.TypeResolver;
import com.google.common.base.Optional;
import com.zx.utils.constant.Constants;
import com.zx.utils.util.ListUtil;
import io.swagger.annotations.ApiModelProperty;
import org.springframework.beans.factory.annotation.Autowired;
import springfox.documentation.builders.OperationBuilder;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.Parameter;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.OperationBuilderPlugin;
import springfox.documentation.spi.service.contexts.OperationContext;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
/**
* @author ZhaoXu
* @date 2022/7/24 12:55
*/
public class ExpandApiPlugin implements OperationBuilderPlugin {
@Autowired
private TypeResolver typeResolver;
@Override
public boolean supports(DocumentationType documentationType) {
return true;
}
@Override
public void apply(OperationContext operationContext) {
List<Parameter> newParameters = new ArrayList<>();
OperationBuilder operationBuilder = operationContext.operationBuilder();
try {
Field parameterField = operationBuilder.getClass().getDeclaredField("parameters");
parameterField.setAccessible(true);
List<Parameter> parameters = (List<Parameter>) parameterField.get(operationBuilder);
for (int i = 0; i < parameters.size(); i++) {
Parameter parameter = parameters.get(i);
String name = parameter.getName();
// reqReplaceMap用来替代参数接入
if ("reqReplaceMap".equals(name)) {
continue;
}
// reqObj展开解析
if (Constants.REQ_OBJ.equals(name)) {
ResolvedType resolvedType = parameter.getType().get();
Class<?> aClass = Class.forName(resolvedType.getTypeName());
Field[] declaredFields = aClass.getDeclaredFields();
// 所有属性,除了serialVersionUID
for (int i1 = 0; i1 < declaredFields.length; i1++) {
Field declaredField = declaredFields[i1];
String fieldName = declaredField.getName();
if (!"serialVersionUID".equals(fieldName)) {
String description = fieldName;
ApiModelProperty apiModelProperty = declaredField.getAnnotation(ApiModelProperty.class);
// 默认字段名作为描述
if (apiModelProperty != null) {
description = apiModelProperty.value();
}
Parameter query = new Parameter(fieldName, description, "", false, true, new ModelRef("string"), Optional.of(typeResolver.resolve(declaredField.getType())), null, "query",
"", false, "", "", new ArrayList<>());
newParameters.add(query);
}
}
continue;
}
newParameters.add(parameter);
}
if (!ListUtil.isEmpty(newParameters)) {
// 反射替换新的参数
Field buildParameterField = operationBuilder.getClass().getDeclaredField("parameters");
buildParameterField.setAccessible(true);
buildParameterField.set(operationBuilder, newParameters);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
调试起来也方便多了: