這里提供的是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,准備工作完成了,去使用吧,要隱藏的實體中添加自己定義的注解即可。
重啟項目去看看吧 這里就不展示了。