swagger2 同一个实体用在多个不同的controller接口展示不同的字段 POST请求body

一、自定义注解。

    一个用于排除,一个用于需要。

 
  1. package com.yx.common.swagger;

  2. import java.lang.annotation.ElementType;

  3. import java.lang.annotation.Retention;

  4. import java.lang.annotation.RetentionPolicy;

  5. import java.lang.annotation.Target;

  6. /**

  7. * 自定义aop注解 支持swagger的动态属性 排除属性

  8. * @author cc

  9. */

  10. @Target({ElementType.PARAMETER, ElementType.FIELD, ElementType.METHOD})

  11. @Retention(RetentionPolicy.RUNTIME)

  12. public @interface ApiIgp {

  13. String[] value(); //对象属性值

  14. }

 
  1. package com.yx.common.swagger;

  2. import java.lang.annotation.ElementType;

  3. import java.lang.annotation.Retention;

  4. import java.lang.annotation.RetentionPolicy;

  5. import java.lang.annotation.Target;

  6. /**

  7. * 自定义aop注解 支持swagger的动态属性 (只)需要属性

  8. * @author cc

  9. */

  10. @Target({ElementType.PARAMETER, ElementType.FIELD, ElementType.METHOD})

  11. @Retention(RetentionPolicy.RUNTIME)

  12. public @interface ApiNeed {

  13. //对象属性值

  14. String[] value();

  15. }

二、重写 swagger2 的 ParameterBuilderPlugin 支持自定义白名单黑名单注解

注意如下代码要保证生成的名称,不可重复。此处以UUID进行生成。

 代码如下

 
  1. package com.yx.user.config;

  2. import com.fasterxml.classmate.TypeResolver;

  3. import com.google.common.base.Optional;

  4. import com.yx.common.swagger.ApiIgp;

  5. import com.yx.common.swagger.ApiNeed;

  6. import io.swagger.annotations.ApiModelProperty;

  7. import lombok.extern.slf4j.Slf4j;

  8. import org.apache.commons.lang3.StringUtils;

  9. import org.apache.ibatis.javassist.*;

  10. import org.apache.ibatis.javassist.bytecode.AnnotationsAttribute;

  11. import org.apache.ibatis.javassist.bytecode.ConstPool;

  12. import org.apache.ibatis.javassist.bytecode.annotation.Annotation;

  13. import org.apache.ibatis.javassist.bytecode.annotation.StringMemberValue;

  14. import org.springframework.beans.factory.annotation.Autowired;

  15. import org.springframework.core.annotation.Order;

  16. import org.springframework.stereotype.Component;

  17. import springfox.documentation.schema.ModelRef;

  18. import springfox.documentation.service.ResolvedMethodParameter;

  19. import springfox.documentation.spi.DocumentationType;

  20. import springfox.documentation.spi.service.ParameterBuilderPlugin;

  21. import springfox.documentation.spi.service.contexts.ParameterContext;

  22. import java.lang.reflect.Field;

  23. import java.lang.reflect.Modifier;

  24. import java.util.Arrays;

  25. import java.util.List;

  26. import java.util.Random;

  27. import java.util.UUID;

  28. import java.util.stream.Collectors;

  29. /**

  30. * 重写 swagger2 的 ParameterBuilderPlugin 支持自定义白名单黑名单注解

  31. * @author xudaz

  32. * @date 2021/6/12

  33. */

  34. @Component

  35. @Order

  36. @Slf4j

  37. class MyParameterBuilderPlugin implements ParameterBuilderPlugin {

  38. @Autowired

  39. private TypeResolver typeResolver;

  40. @Override

  41. public void apply(ParameterContext parameterContext) {

  42. ResolvedMethodParameter methodParameter = parameterContext.resolvedMethodParameter();

  43. Class<?> originClass = parameterContext.resolvedMethodParameter().getParameterType().getErasedType();

  44. // 排除属性

  45. ApiIgp igpOptional = null;

  46. @SuppressWarnings("Guava")

  47. Optional<ApiIgp> apiIgpOptional = methodParameter.findAnnotation(ApiIgp.class);

  48. if ( apiIgpOptional.isPresent() ) {

  49. igpOptional = apiIgpOptional.get();

  50. }

  51. // 需要属性

  52. ApiNeed needOptional = null;

  53. @SuppressWarnings("Guava")

  54. Optional<ApiNeed> apiNeedOptional = methodParameter.findAnnotation(ApiNeed.class);

  55. if ( apiNeedOptional.isPresent() ) {

  56. needOptional = apiNeedOptional.get();

  57. }

  58. if (null != igpOptional || null != needOptional ) {

  59. Random random = new Random();

  60. //model 名称

  61. // String name = originClass.getSimpleName() + "YX" + random.nextInt(100000);

  62. String name = originClass.getSimpleName() + "_" + UUID.randomUUID().toString().replace("-", "");

  63. try {

  64. // 排除 (黑名单)

  65. if ( null != igpOptional ) {

  66. String[] properties = igpOptional.value();

  67. parameterContext.getDocumentationContext()

  68. .getAdditionalModels()

  69. //向documentContext的Models中添加我们新生成的Class

  70. .add(typeResolver.resolve(createRefModelIgp(properties, originClass.getPackage()+"."+name, originClass)));

  71. }

  72. // 需要 (白名单)

  73. if ( null != needOptional ) {

  74. String[] properties = needOptional.value();

  75. parameterContext.getDocumentationContext()

  76. .getAdditionalModels()

  77. //向documentContext的Models中添加我们新生成的Class

  78. .add(typeResolver.resolve(createRefModelNeed(properties, originClass.getPackage()+"."+name, originClass)));

  79. }

  80. } catch (Exception e) {

  81. log.error("swagger切面异常", e);

  82. }

  83. //修改Map参数的ModelRef为我们动态生成的class

  84. parameterContext.parameterBuilder()

  85. .parameterType("body")

  86. .modelRef(new ModelRef(name))

  87. .name(name);

  88. }

  89. }

  90. /**

  91. * 创建自定义mode给swagger2 排除参数

  92. * @param properties 需要排除的参数

  93. * @param name model 名称

  94. * @param origin originClass

  95. * @return r

  96. */

  97. private Class<?> createRefModelIgp(String[] properties, String name, Class<?> origin) {

  98. ClassPool pool = ClassPool.getDefault();

  99. // 动态创建一个class

  100. CtClass ctClass = pool.makeClass( name);

  101. try {

  102. Field[] fields = origin.getDeclaredFields();

  103. List<Field> fieldList = Arrays.asList(fields);

  104. List<String> ignoreProperties = Arrays.asList(properties);

  105. // 过滤掉 properties 的参数

  106. List<Field> dealFields = fieldList.stream().filter(s -> !ignoreProperties.contains(s.getName())).collect(Collectors.toList());

  107. addField2CtClass(dealFields, origin, ctClass);

  108. return ctClass.toClass();

  109. } catch (Exception e) {

  110. log.error("swagger切面异常", e);

  111. return null;

  112. }

  113. }

  114. /**

  115. * 创建自定义mode给swagger2 需要参数

  116. * @param properties 需要排除的参数

  117. * @param name model 名称

  118. * @param origin originClass

  119. * @return r

  120. */

  121. private Class<?> createRefModelNeed(String[] properties, String name, Class<?> origin) {

  122. ClassPool pool = ClassPool.getDefault();

  123. CtClass ctClass = pool.makeClass( name);

  124. try {

  125. Field[] fields = origin.getDeclaredFields();

  126. List<Field> fieldList = Arrays.asList(fields);

  127. List<String> ignoreProperties = Arrays.asList(properties);

  128. // 过滤掉 非 properties 的参数

  129. List<Field> dealFields = fieldList.stream().filter(s -> ignoreProperties.contains(s.getName())).collect(Collectors.toList());

  130. addField2CtClass(dealFields, origin, ctClass);

  131. return ctClass.toClass();

  132. } catch (Exception e) {

  133. log.error("swagger切面异常", e);

  134. return null;

  135. }

  136. }

  137. private void addField2CtClass(List<Field> dealFields, Class<?> origin, CtClass ctClass ) throws NoSuchFieldException, NotFoundException, CannotCompileException {

  138. // 倒序遍历

  139. for (int i = dealFields.size() - 1; i >= 0; i--) {

  140. Field field = dealFields.get(i);

  141. CtField ctField = new CtField(ClassPool.getDefault().get(field.getType().getName()), field.getName(), ctClass);

  142. ctField.setModifiers(Modifier.PUBLIC);

  143. ApiModelProperty ampAnno = origin.getDeclaredField(field.getName()).getAnnotation(ApiModelProperty.class);

  144. String attributes = java.util.Optional.ofNullable(ampAnno).map(ApiModelProperty::value).orElse("");

  145. //添加model属性说明

  146. if (StringUtils.isNotBlank(attributes) ){

  147. ConstPool constPool = ctClass.getClassFile().getConstPool();

  148. AnnotationsAttribute attr = new AnnotationsAttribute(constPool, AnnotationsAttribute.visibleTag);

  149. Annotation ann = new Annotation(ApiModelProperty.class.getName(), constPool);

  150. ann.addMemberValue("value", new StringMemberValue(attributes, constPool));

  151. attr.addAnnotation(ann);

  152. ctField.getFieldInfo().addAttribute(attr);

  153. }

  154. ctClass.addField(ctField);

  155. }

  156. }

  157. @Override

  158. public boolean supports(DocumentationType documentationType) {

  159. return true;

  160. }

  161. }

 三、使用实例

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值