Driver_tu 2019-08-20 21:43 采纳率: 100%
浏览 14395
已采纳

springboot中form-data传值,不用@Requestbody修饰入参对象时,swagger-ui该怎么聚合它的属性

1、环境描述:在springboot+swagger v_2.9.2的环境下
前后端分离,restful风格接口。

2、提问原因:前后端约定使用form-data进行数据传递,后台接口入参很多都是:
public String findPage(String pageNo, String pageSize, Batch entity)这样的,

调试好swagger接口文档后发现:如果将参数Batch用@Requestbody修饰,接口文档中的参数parameter就是聚合显示,如果后台没有使用@Requestbody修饰,那么swagger将递归该参数对象Batch的所有属性,包括其中的Page,具体如下图:

(两种接收参数方式对swagger-ui的影响

图片描述:(不知道图片看的清不)

同一个接口,仅仅只是入参对象的修饰语不同,在swagger上居然区别这么大

左边的swagger上看起来是正常的,网络上很多人都是用这种@Requestbody方式,但是我们约定的是form-data,所以不能使用@Requestbody接收参数。而如果不用,那么swagger文档上看到的都是全部铺开的,不是很方便使用。

3、我尝试过的方法

1.我想过两个方向,一个是修改后台swagger处理数据的拼装逻辑,另一个方向是在页面端修改数据的位置和逻辑,也就是修改api-doc接口返回的数据,

==第一个方向:修改后台swagger处理数据的拼装结构,借鉴了(https://blog.csdn.net/u010579482/article/details/79990536) 中的一个思路,重写子类覆盖swagger主要处理参数数据的ModelAttributeParameterExpander,到目前为止还没有解决。

==第二个方向:修改页面端api-doc接口返回的数据,根据图上两种方式的对比,我们可以发现:

被@Requestbody修饰的入参对象,在swagger-ui的definitions中已经有了一个对象的定义或声明:

被@Requestbody修饰
图片说明

而没有被@Requestbody修饰的返回结果,在swagger-ui里返回结果就直接是在path.post.parameters中平铺在一起,也就是不方便所在,如果入参对象里有子对象,那递归出来就是一大片了。如下图:

图片说明

4、现状:到目前为止,还没有解决这个问题,各位大佬有时间的话教育下小弟,小弟在线等着,还望大佬们不吝赐教,[感激][感激][感激]

  • 写回答

7条回答 默认 最新

  • 人菜瘾大老薛 2019-08-21 14:44
    关注

    明白你的意思了,按照你的意思做了一下,篇幅有限,只展示主要代码

    自定义注解

    @Target({ElementType.PARAMETER})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface FormData {
    }
    

    覆盖springfox.documentation.spring.web.readers.operation.OperationParameterReader

    @Component
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public class OperationParameterReaderSub extends OperationParameterReader {
        private final ModelAttributeParameterExpander expander;
        private final EnumTypeDeterminer enumTypeDeterminer;
    
        @Autowired
        private DocumentationPluginsManager pluginsManager;
    
        @Autowired
        public OperationParameterReaderSub(
                ModelAttributeParameterExpander expander,
                EnumTypeDeterminer enumTypeDeterminer,
                ApplicationContext applicationContext) {
            super(expander, enumTypeDeterminer);
            this.expander = expander;
            this.enumTypeDeterminer = enumTypeDeterminer;
            /*
             * 删除父类bean定义
             * DocumentationPluginsManager中使用ParameterBuilderPlugin类型获取bean,而不是OperationParameterReader类型
             * 所以@Primary注解并不能覆盖父类
             */
            DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) applicationContext.getAutowireCapableBeanFactory();
            defaultListableBeanFactory.removeBeanDefinition("operationParameterReader");
        }
    
        private boolean shouldExpand(final ResolvedMethodParameter parameter, ResolvedType resolvedParamType) {
            return !parameter.hasParameterAnnotation(RequestBody.class)
                    && !parameter.hasParameterAnnotation(FormData.class) // 加上自定义的注解
                    && !parameter.hasParameterAnnotation(RequestPart.class)
                    && !parameter.hasParameterAnnotation(RequestParam.class)
                    && !parameter.hasParameterAnnotation(PathVariable.class)
                    && !isBaseType(typeNameFor(resolvedParamType.getErasedType()))
                    && !enumTypeDeterminer.isEnum(resolvedParamType.getErasedType())
                    && !isContainerType(resolvedParamType)
                    && !isMapType(resolvedParamType);
    
        }
    
        // 其他省略,直接从父类复制
    
    }
    

    覆盖springfox.documentation.spring.web.readers.operation.OperationModelsProvider

    @Component
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public class OperationModelsProviderSub extends OperationModelsProvider {
    
        private static final Logger LOG = LoggerFactory.getLogger(OperationModelsProvider.class);
        private final TypeResolver typeResolver;
    
        @Autowired
        public OperationModelsProviderSub(TypeResolver typeResolver, ApplicationContext applicationContext) {
            super(typeResolver);
            this.typeResolver = typeResolver;
            /*
             * 删除父类bean定义
             * DocumentationPluginsManager中使用OperationModelsProviderPlugin类型获取bean,而不是OperationModelsProvider类型
             * 所以@Primary注解并不能覆盖父类
             */
            DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) applicationContext.getAutowireCapableBeanFactory();
            defaultListableBeanFactory.removeBeanDefinition("operationModelsProvider");
        }
    
        private void collectParameters(RequestMappingContext context) {
            LOG.debug("Reading parameters models for handlerMethod |{}|", context.getName());
    
            List<ResolvedMethodParameter> parameterTypes = context.getParameters();
            for (ResolvedMethodParameter parameterType : parameterTypes) {
                if (parameterType.hasParameterAnnotation(RequestBody.class)
                        || parameterType.hasParameterAnnotation(FormData.class) // 加上自定义的注解
                        || parameterType.hasParameterAnnotation(RequestPart.class)) {
                    ResolvedType modelType = context.alternateFor(parameterType.getParameterType());
                    LOG.debug("Adding input parameter of type {}", resolvedTypeSignature(modelType).or("<null>"));
                    context.operationModelsBuilder().addInputParam(modelType);
                }
            }
            LOG.debug("Finished reading parameters models for handlerMethod |{}|", context.getName());
        }
    
        // 其他省略,直接从父类复制
    
    }
    

    示例controller

    像使用RequestBody一样使用FromData,只变文档,没有其他副作用

        @GetMapping
        @ApiOperation(value = "测试")
        public String test(@FormData User user) {
            System.out.println(user);
            return "随便返回点什么";
        }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(6条)

报告相同问题?

悬赏问题

  • ¥30 matlab appdesigner私有函数嵌套整合
  • ¥15 给我一个openharmony跑通webrtc实现视频会议的简单demo项目,sdk为12
  • ¥15 vb6.0使用jmail接收smtp邮件并另存附件到D盘
  • ¥30 vb net 使用 sendMessage 如何输入鼠标坐标
  • ¥15 关于freesurfer使用freeview可视化的问题
  • ¥100 谁能在荣耀自带系统MagicOS版本下,隐藏手机桌面图标?
  • ¥15 求SC-LIWC词典!
  • ¥20 有关esp8266连接阿里云
  • ¥15 C# 调用Bartender打印机打印
  • ¥15 我这个代码哪里有问题 acm 平台上显示错误 90%,我自己运行好像没什么问题