|
@@ -0,0 +1,119 @@
|
|
|
+package com.qmth.teachcloud.report.business.config;
|
|
|
+
|
|
|
+import com.fasterxml.classmate.TypeResolver;
|
|
|
+import com.google.common.base.Optional;
|
|
|
+import com.qmth.teachcloud.common.annotation.ApiJsonObject;
|
|
|
+import com.qmth.teachcloud.common.annotation.ApiJsonProperty;
|
|
|
+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.StringMemberValue;
|
|
|
+import org.slf4j.Logger;
|
|
|
+import org.slf4j.LoggerFactory;
|
|
|
+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;
|
|
|
+
|
|
|
+/**
|
|
|
+ * @Description: swagger2 map参数说明插件
|
|
|
+ * @Param:
|
|
|
+ * @return:
|
|
|
+ * @Author: wangliang
|
|
|
+ * @Date: 2020/4/23
|
|
|
+ */
|
|
|
+@Component
|
|
|
+@Order //plugin加载顺序,默认是最后加载
|
|
|
+public class MapApiReader implements ParameterBuilderPlugin {
|
|
|
+ private final static Logger log = LoggerFactory.getLogger(MapApiReader.class);
|
|
|
+
|
|
|
+ @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 名称
|
|
|
+ ApiJsonProperty[] properties = optional.get().value();
|
|
|
+ parameterContext.getDocumentationContext().getAdditionalModels().add(typeResolver.resolve(createRefModel(properties, name))); //像documentContext的Models中添加我们新生成的Class
|
|
|
+ parameterContext.parameterBuilder() //修改Map参数的ModelRef为我们动态生成的class
|
|
|
+ .parameterType("body")
|
|
|
+ .modelRef(new ModelRef(name))
|
|
|
+ .name(name);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private final static String basePackage = "com.qmth.teachcloud.report.business.entity."; //动态生成的Class名
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据propertys中的值动态生成含有Swagger注解的javaBeen
|
|
|
+ */
|
|
|
+ private Class createRefModel(ApiJsonProperty[] propertys, String name) {
|
|
|
+ ClassPool pool = ClassPool.getDefault();
|
|
|
+ CtClass ctClass = pool.makeClass(basePackage + name);
|
|
|
+ try {
|
|
|
+ for (ApiJsonProperty property : propertys) {
|
|
|
+ ctClass.addField(createField(property, ctClass));
|
|
|
+ }
|
|
|
+ return ctClass.toClass();
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("请求出错", e);
|
|
|
+ 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));
|
|
|
+ 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(Integer.class.getName());
|
|
|
+ break;
|
|
|
+ case "long":
|
|
|
+ fileType = ClassPool.getDefault().get(Long.class.getName());
|
|
|
+ break;
|
|
|
+ case "boolean":
|
|
|
+ fileType = ClassPool.getDefault().get(Boolean.class.getName());
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ return fileType;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public boolean supports(DocumentationType delimiter) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+}
|