zoukankan      html  css  js  c++  java
  • 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,准备工作完成了,去使用吧,要隐藏的实体中添加自己定义的注解即可。

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

  • 相关阅读:
    【队列应用一】随机迷宫|随机起点终点*最短路径算法
    【堆栈应用二】迷宫算法,可直接动态运行
    【堆栈应用一】一个数divided=几个最小质因数的乘积(时间复杂度On)
    MyEclipse2014中Java类右键Run as没有JUnit Test
    C++中break/Continue,exit/return的理解
    windows下用C++修改本机IP地址
    windows下注册表的操作
    详解Java的Spring框架中的注解的用法
    什么是Java Bean
    JS windows对象的top属性
  • 原文地址:https://www.cnblogs.com/BigPig-Winnie/p/11949917.html
Copyright © 2011-2022 走看看