springboot2集成swagger2 参数map集合
- 引入 pom依赖
<!-- 添加swagger2相关功能 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<!-- 添加swagger-ui相关功能 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
<!-- 引入swagger-bootstrap-ui包 -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>swagger-bootstrap-ui</artifactId>
<version>1.9.2</version>
</dependency>
- swagger配置
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.util.List;
import java.util.Map;
@Configuration // 告诉Spring容器,这个类是一个配置类
@EnableSwagger2 // 启用Swagger2功能
public class Swagger2Config {
/**
* 配置Swagger2相关的bean
*/
@Bean
public Docket createH5RestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com"))// com包下所有API都交给Swagger2管理
.paths(PathSelectors.any()).build();
}
/**
* 此处主要是API文档页面显示信息
*/
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("演示项目API") // 标题
.description("学习Swagger2的演示项目") // 描述
.termsOfServiceUrl("http://go3d.com") // 服务网址,一般写公司地址
.version("1.0") // 版本
.build();
}
}
- 针对map集合参数
(1) 创建接口ApiJsonObject
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.PARAMETER, ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ApiJsonObject {
ApiJsonProperty[] value(); //对象属性值
String name(); //对象名称
String paramType();//请求类型
}
(2) 创建接口ApiJsonProperty
public @interface ApiJsonProperty {
String key(); //key
String example() default "";
String type() default "string"; //支持string 和 int
String description() default "";
boolean required() default false;
String paramType() default "";
}
(3) 创建类MapApiReader并实现ParameterBuilderPlugin
import com.fasterxml.classmate.TypeResolver;
import com.google.common.base.Optional;
import org.apache.ibatis.javassist.*;
import org.apache.ibatis.javassist.bytecode.AnnotationsAttribute;
import org.apache.ibatis.javassist.bytecode.ConstPool;
import org.apache.ibatis.javassist.bytecode.annotation.Annotation;
import org.apache.ibatis.javassist.bytecode.annotation.BooleanMemberValue;
import org.apache.ibatis.javassist.bytecode.annotation.IntegerMemberValue;
import org.apache.ibatis.javassist.bytecode.annotation.StringMemberValue;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.ResolvedMethodParameter;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.ParameterBuilderPlugin;
import springfox.documentation.spi.service.contexts.ParameterContext;
import java.util.Map;
@Component
@Order
public class MapApiReader implements ParameterBuilderPlugin {
@Autowired
private TypeResolver typeResolver;
@Override
public void apply(ParameterContext parameterContext) {
ResolvedMethodParameter methodParameter = parameterContext.resolvedMethodParameter();
if (methodParameter.getParameterType().canCreateSubtype(Map.class) || methodParameter.getParameterType().canCreateSubtype(String.class)) { //判断是否需要修改对象ModelRef,这里我判断的是Map类型和String类型需要重新修改ModelRef对象
Optional<ApiJsonObject> optional = methodParameter.findAnnotation(ApiJsonObject.class); //根据参数上的ApiJsonObject注解中的参数动态生成Class
if (optional.isPresent()) {
String name = optional.get().name(); //model 名称
String paramType = optional.get().paramType();
ApiJsonProperty[] properties = optional.get().value();
parameterContext.getDocumentationContext().getAdditionalModels().add(typeResolver.resolve(createRefModel(properties, name))); //像documentContext的Models中添加我们新生成的Class
parameterContext.parameterBuilder() //修改Map参数的ModelRef为我们动态生成的class
.parameterType(paramType)
.modelRef(new ModelRef(name)).description("参数对象")
.name(name);
}
}
}
private final static String basePackage = "com.xxx.xxx.model."; //动态生成的Class名
/**
* 根据propertys中的值动态生成含有Swagger注解的javaBeen
*/
private Class createRefModel(ApiJsonProperty[] propertys, String name) {
ClassPool pool = ClassPool.getDefault();
CtClass ctClass = pool.makeClass(name);
try {
for (ApiJsonProperty property : propertys) {
ctClass.addField(createField(property, ctClass));
}
return ctClass.toClass();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 根据property的值生成含有swagger apiModelProperty注解的属性
*/
private CtField createField(ApiJsonProperty property, CtClass ctClass) throws NotFoundException, CannotCompileException {
CtField ctField = new CtField(getFieldType(property.type()), property.key(), ctClass);
ctField.setModifiers(Modifier.PUBLIC);
ConstPool constPool = ctClass.getClassFile().getConstPool();
AnnotationsAttribute attr = new AnnotationsAttribute(constPool, AnnotationsAttribute.visibleTag);
Annotation ann = new Annotation("io.swagger.annotations.ApiModelProperty", constPool);
ann.addMemberValue("value", new StringMemberValue(property.description(), constPool));
ann.addMemberValue("required",new BooleanMemberValue(property.required(),constPool));
ann.addMemberValue("paramType",new StringMemberValue(property.paramType(),constPool));
ann.addMemberValue("type",new StringMemberValue(property.type(),constPool));
if (ctField.getType().subclassOf(ClassPool.getDefault().get(String.class.getName()))) {
ann.addMemberValue("example", new StringMemberValue(property.example(), constPool));
}
if (ctField.getType().subclassOf(ClassPool.getDefault().get(int.class.getName()))) {
Integer integerExample = Integer.parseInt(property.example());
ann.addMemberValue("example", new IntegerMemberValue(constPool,integerExample));
}
attr.addAnnotation(ann);
ctField.getFieldInfo().addAttribute(attr);
return ctField;
}
private CtClass getFieldType(String type) throws NotFoundException {
CtClass fileType = null;
switch (type) {
case "string":
fileType = ClassPool.getDefault().get(String.class.getName());
break;
case "int":
fileType = ClassPool.getDefault().get(int.class.getName());
break;
}
return fileType;
}
@Override
public boolean supports(DocumentationType delimiter) {
return true;
}
}
- 控制器
@ApiOperation(value = "登录",notes = "用户登录",response = ResponseInfo.class)
@ApiResponses({
@ApiResponse(code = 200,message = "操作成功"),
@ApiResponse(code = 505,message = "操作失败")
})
public Object login(@RequestBody @ApiJsonObject(name = "map1",paramType = "body",value = {
@ApiJsonProperty(key = "phone", example = "18614242538", description = "手机号",required = true),
@ApiJsonProperty(key = "password", example = "123456", description = "密码")}) Map map) {
//手机号
String phone = (String) map.get("phone");
//密码
String password = (String) map.get("password");
if (status == null) {
return new ResponseInfo(505, "登录状态不能为空");
}
...
逻辑处理
...
ResponseInfo info = null;
return info;
}
return null;
}
注:整个工程中ApiJsonObject种的name值不能相同,否则会报错