这里提供的是swagger2版本2.8.0 的解决方案
看了网上的一些自定义的,但是有些不全面。
通过阅读源码找到了展开参数的类springfox.documentation.spring.web.readers.parameter.ModelAttributeParameterExpander
,笔者通过继承这个类,并添加@Primary注解覆盖了源码中的逻辑,修改了getBeanPropertyNames
方法,其他不变
@Primary:自动装配时当出现多个Bean候选者时,被注解为@Primary的Bean将作为首选者,否则将抛出异常
这里引用网上的一张截图,本来dept是做映射关联的,不想给掉接口的人看到,但是Swagger没有隐藏这个关联对象的注解。
整理了一下网上的不足。
这三个类是在网上找的,组合起来就完全解决了实体中关联对象的隐藏问题
先上图片说明一下,CustomizeModelAttributeParameterExpander中使用到对应上面的IgnoreSwaggerParameter注解类和FiedUtil类
上代码:
CustomizeModelAttributeParameterExpander类
package com.xxx.test.Swaggerconfig; import com.fasterxml.classmate.ResolvedType; import com.fasterxml.classmate.members.ResolvedField; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Function; import com.google.common.base.Optional; import com.google.common.base.Predicate; import com.google.common.collect.FluentIterable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Primary; import org.springframework.stereotype.Component; import org.springframework.util.ClassUtils; import springfox.documentation.builders.ParameterBuilder; import springfox.documentation.schema.Maps; import springfox.documentation.schema.Types; import springfox.documentation.schema.property.field.FieldProvider; import springfox.documentation.service.Parameter; import springfox.documentation.spi.schema.AlternateTypeProvider; import springfox.documentation.spi.schema.EnumTypeDeterminer; import springfox.documentation.spi.service.contexts.DocumentationContext; import springfox.documentation.spi.service.contexts.ParameterExpansionContext; import springfox.documentation.spring.web.readers.parameter.ExpansionContext; import springfox.documentation.spring.web.readers.parameter.ModelAttributeField; import springfox.documentation.spring.web.readers.parameter.ModelAttributeParameterExpander; import java.beans.BeanInfo; import java.beans.IntrospectionException; import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.lang.reflect.Field; import java.util.HashSet; import java.util.List; import java.util.Set; import static com.google.common.base.Objects.equal; import static com.google.common.base.Predicates.*; import static com.google.common.base.Strings.isNullOrEmpty; import static com.google.common.collect.FluentIterable.from; import static com.google.common.collect.Lists.newArrayList; import static com.google.common.collect.Sets.newHashSet; import static springfox.documentation.schema.Collections.collectionElementType; import static springfox.documentation.schema.Collections.isContainerType; import static springfox.documentation.schema.Types.typeNameFor; /** * @author: 皓月心<+>星辰吻 * @date: 2019-11-27 20:19 * @description: */ @Component @Primary public class CustomizeModelAttributeParameterExpander extends ModelAttributeParameterExpander { private static final Logger LOG = LoggerFactory.getLogger(CustomizeModelAttributeParameterExpander.class); private final FieldProvider fieldProvider; private final EnumTypeDeterminer enumTypeDeterminer; @Autowired public CustomizeModelAttributeParameterExpander(FieldProvider fields, EnumTypeDeterminer enumTypeDeterminer) { super(fields, enumTypeDeterminer); this.fieldProvider = fields; this.enumTypeDeterminer = enumTypeDeterminer; } @Override public List<Parameter> expand(ExpansionContext context) { List<Parameter> parameters = newArrayList(); Set<String> beanPropNames = getBeanPropertyNames(context.getParamType().getErasedType()); Iterable<ResolvedField> fields = FluentIterable.from(fieldProvider.in(context.getParamType())) .filter(onlyBeanProperties(beanPropNames)); LOG.debug("Expanding parameter type: {}", context.getParamType()); AlternateTypeProvider alternateTypeProvider = context.getDocumentationContext().getAlternateTypeProvider(); FluentIterable<ModelAttributeField> modelAttributes = from(fields) .transform(toModelAttributeField(alternateTypeProvider)); FluentIterable<ModelAttributeField> expendables = modelAttributes .filter(not(simpleType())) .filter(not(recursiveType(context))); for (ModelAttributeField each : expendables) { LOG.debug("Attempting to expand expandable field: {}", each.getField()); parameters.addAll( expand( context.childContext( nestedParentName(context.getParentName(), each.getField()), each.getFieldType(), context.getDocumentationContext()))); } FluentIterable<ModelAttributeField> collectionTypes = modelAttributes .filter(and(isCollection(), not(recursiveCollectionItemType(context.getParamType())))); for (ModelAttributeField each : collectionTypes) { LOG.debug("Attempting to expand collection/array field: {}", each.getField()); ResolvedType itemType = collectionElementType(each.getFieldType()); if (Types.isBaseType(itemType) || enumTypeDeterminer.isEnum(itemType.getErasedType())) { parameters.add(simpleFields(context.getParentName(), context.getDocumentationContext(), each)); } else { parameters.addAll( expand( context.childContext( nestedParentName(context.getParentName(), each.getField()), itemType, context.getDocumentationContext()))); } } FluentIterable<ModelAttributeField> simpleFields = modelAttributes.filter(simpleType()); for (ModelAttributeField each : simpleFields) { parameters.add(simpleFields(context.getParentName(), context.getDocumentationContext(), each)); } return FluentIterable.from(parameters).filter(not(hiddenParameters())).toList(); } private Predicate<ModelAttributeField> recursiveCollectionItemType(final ResolvedType paramType) { return new Predicate<ModelAttributeField>() { @Override public boolean apply(ModelAttributeField input) { return equal(collectionElementType(input.getFieldType()), paramType); } }; } private Predicate<Parameter> hiddenParameters() { return new Predicate<Parameter>() { @Override public boolean apply(Parameter input) { return input.isHidden(); } }; } private Parameter simpleFields( String parentName, DocumentationContext documentationContext, ModelAttributeField each) { LOG.debug("Attempting to expand field: {}", each); String dataTypeName = Optional.fromNullable(typeNameFor(each.getFieldType().getErasedType())) .or(each.getFieldType().getErasedType().getSimpleName()); LOG.debug("Building parameter for field: {}, with type: ", each, each.getFieldType()); ParameterExpansionContext parameterExpansionContext = new ParameterExpansionContext( dataTypeName, parentName, each.getField(), documentationContext.getDocumentationType(), new ParameterBuilder()); return pluginsManager.expandParameter(parameterExpansionContext); } private Predicate<ModelAttributeField> recursiveType(final ExpansionContext context) { return new Predicate<ModelAttributeField>() { @Override public boolean apply(ModelAttributeField input) { return context.hasSeenType(input.getFieldType()); } }; } private Predicate<ModelAttributeField> simpleType() { return and(not(isCollection()), not(isMap()), or( belongsToJavaPackage(), isBaseType(), isEnum())); } private Predicate<ModelAttributeField> isCollection() { return new Predicate<ModelAttributeField>() { @Override public boolean apply(ModelAttributeField input) { return isContainerType(input.getFieldType()); } }; } private Predicate<ModelAttributeField> isMap() { return new Predicate<ModelAttributeField>() { @Override public boolean apply(ModelAttributeField input) { return Maps.isMapType(input.getFieldType()); } }; } private Predicate<ModelAttributeField> isEnum() { return new Predicate<ModelAttributeField>() { @Override public boolean apply(ModelAttributeField input) { return enumTypeDeterminer.isEnum(input.getFieldType().getErasedType()); } }; } private Predicate<ModelAttributeField> belongsToJavaPackage() { return new Predicate<ModelAttributeField>() { @Override public boolean apply(ModelAttributeField input) { return ClassUtils.getPackageName(input.getFieldType().getErasedType()).startsWith("java.lang"); } }; } private Predicate<ModelAttributeField> isBaseType() { return new Predicate<ModelAttributeField>() { @Override public boolean apply(ModelAttributeField input) { return Types.isBaseType(input.getFieldType()) || input.getField().getType().isPrimitive(); } }; } private Function<ResolvedField, ModelAttributeField> toModelAttributeField( final AlternateTypeProvider alternateTypeProvider) { return new Function<ResolvedField, ModelAttributeField>() { @Override public ModelAttributeField apply(ResolvedField input) { return new ModelAttributeField(fieldType(alternateTypeProvider, input), input); } }; } private Predicate<ResolvedField> onlyBeanProperties(final Set<String> beanPropNames) { return new Predicate<ResolvedField>() { @Override public boolean apply(ResolvedField input) { return beanPropNames.contains(input.getName()); } }; } private String nestedParentName(String parentName, ResolvedField field) { String name = field.getName(); ResolvedType fieldType = field.getType(); if (isContainerType(fieldType) && !Types.isBaseType(collectionElementType(fieldType))) { name += "[0]"; } if (isNullOrEmpty(parentName)) { return name; } return String.format("%s.%s", parentName, name); } private ResolvedType fieldType(AlternateTypeProvider alternateTypeProvider, ResolvedField field) { return alternateTypeProvider.alternateFor(field.getType()); } private Set<String> getBeanPropertyNames(final Class<?> clazz) { try { Set<String> beanProps = new HashSet<String>(); PropertyDescriptor[] propDescriptors = getBeanInfo(clazz).getPropertyDescriptors(); for (PropertyDescriptor propDescriptor : propDescriptors) { // 增加逻辑,忽略@IgnoreSwaggerParameter注解的字段 Field field = FieldUtil.getDeclaredField(clazz,propDescriptor.getName()); if (field!=null) { field.setAccessible(true); IgnoreSwaggerParameter ignoreSwaggerParameter = field.getDeclaredAnnotation(IgnoreSwaggerParameter.class); if (ignoreSwaggerParameter != null) { continue; } } // 增加结束 if (propDescriptor.getReadMethod() != null) { beanProps.add(propDescriptor.getName()); } } return beanProps; } catch (Exception e) { LOG.warn(String.format("Failed to get bean properties on (%s)", clazz), e); } return newHashSet(); } @VisibleForTesting BeanInfo getBeanInfo(Class<?> clazz) throws IntrospectionException { return Introspector.getBeanInfo(clazz); } }
IgnoreSwaggerParameter类
package com.xxx.test.Swaggerconfig; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * @author: 皓月心<+>星辰吻 * @date: 2019-11-27 20:26 * @description: */ @Target({ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) public @interface IgnoreSwaggerParameter { }
FieldUtil类
package com.kysd.kywy.server.common.Swaggerconfig; import java.lang.reflect.Field; /** * @author: 皓月心<+>星辰吻 * @date: 2019-11-28 11:10 * @description: */ public class FieldUtil { public FieldUtil() { } public static Field getDeclaredField(Class<?> cls, String name) { Field field = null; try { if (cls == null) { return null; } field = cls.getDeclaredField(name); } catch (NoSuchFieldException var4) { field = getDeclaredField(cls.getSuperclass(), name); } catch (SecurityException var5) { var5.printStackTrace(); } return field; } }
OK,准备工作完成了,去使用吧,要隐藏的实体中添加自己定义的注解即可。
重启项目去看看吧 这里就不展示了。