Swagger2 隐藏实体中关联的对象
这里提供的是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,准备工作完成了,去使用吧,要隐藏的实体中添加自己定义的注解即可。

重启项目去看看吧 这里就不展示了。

浙公网安备 33010602011771号