Swagger对无@RequestBody描述的参数也显示Model

Swagger优化

当没有@RequestBody描述参数的时候如何让Swagger显示Model

开始时以为在SwaggerConfig中配置即可,后来发现Swagger没有对应的可配置项。

开始在网上搜索解决方案,最终搜索到:

https://blog.csdn.net/Driver_tu/article/details/100031407

但上面的解决方案是用另一个注解去描述对应的参数,我就在想可不可以不用任何注解,有无@RequestBody,Swagger的都是按Model默认展示的

我找到了关于springfox的源码解析

https://www.xiaominfo.com/2019/05/20/springfox-0/

我结合了上面两篇文章中的内容做出了修改。

1、OperationModelsProvider类重写

OperationModelsProvider的作用是收集参数Model

原来的类代码:

private void collectParameters(RequestMappingContext context) {
		... 
    for (ResolvedMethodParameter parameterType : parameterTypes) {
        if (parameterType.hasParameterAnnotation(RequestBody.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);
        }
    }
  	...
  }

可以看到只有RequestBody和RequestPart描述的参数的type被加入context的model中。

修改后:

for (ResolvedMethodParameter parameterType : parameterTypes) {
            // 添加判断无RequestBody注解不会被拦下
            if (parameterType.hasParameterAnnotation(RequestBody.class)
                    || !parameterType.hasParameterAnnotation(RequestBody.class)
                    || parameterType.hasParameterAnnotation(RequestPart.class)) {
                ResolvedType modelType = context.alternateFor(parameterType.getParameterType());
                LOG.info("Adding input parameter of type {}", resolvedTypeSignature(modelType).or("<null>"));
                context.operationModelsBuilder().addInputParam(modelType);
            }
        }

无RequestBody注解的参数也可以添加到model中

2、OperationParameterReader类重写

原来的代码:

private List<Parameter> readParameters(final OperationContext context) {
  ...
    if (shouldExpand(methodParameter, alternate)) {
                    parameters.addAll(
                            expander.expand(
                                    new ExpansionContext("", alternate, context.getDocumentationContext())));
                } else {
                    parameters.add(pluginsManager.parameter(parameterContext));
                }
  ...
}
 private boolean shouldExpand(final ResolvedMethodParameter parameter, ResolvedType resolvedParamType) {
        return !parameter.hasParameterAnnotation(RequestBody.class)
                && !parameter.hasParameterAnnotation(RequestParam.class)
                && !parameter.hasParameterAnnotation(PathVariable.class)
                && !isBaseType(typeNameFor(resolvedParamType.getErasedType()))
                && !enumTypeDeterminer.isEnum(resolvedParamType.getErasedType())
                && !isContainerType(resolvedParamType)
                && !isMapType(resolvedParamType);

    }

在第一段代码的判断中如果下面的判断为true就会把参数创建一个ExpansionContext对象并加入,但是一般含有@RequestBody注解是不会走true这段,而是下面的pluginsManager.parameter(),所以我们将不带有RequestBody注解的参数也添加判断走false

修改后的代码(仅修改shouldExpand判断)

private boolean shouldExpand(final ResolvedMethodParameter parameter, ResolvedType resolvedParamType) {
        // 有无RequestBody注解都返回false
        return !parameter.hasParameterAnnotation(RequestBody.class)
                && parameter.hasParameterAnnotation(RequestBody.class)
                && !parameter.hasParameterAnnotation(RequestParam.class)
                && !parameter.hasParameterAnnotation(PathVariable.class)
                && !isBaseType(typeNameFor(resolvedParamType.getErasedType()))
                && !enumTypeDeterminer.isEnum(resolvedParamType.getErasedType())
                && !isContainerType(resolvedParamType)
                && !isMapType(resolvedParamType);
    }

3、重写ParameterTypeReader类

从上面的代码可以知道,我们让参数走了pluginsManager.parameter()方法,找到这个方法他使用ParameterBuilderPlugin来处理,这个就是针对parameter的处理插件。

找到ParameterBuilderPlugin的实现类ParameterTypeReader,他主要来处理参数的类型,找到其中的处理方法findParameterType()

public static String findParameterType(ParameterContext parameterContext) {
    ResolvedMethodParameter resolvedMethodParameter = parameterContext.resolvedMethodParameter();
    ResolvedType parameterType = resolvedMethodParameter.getParameterType();
    parameterType = parameterContext.alternateFor(parameterType);

    //Multi-part file trumps any other annotations
    if (isFileType(parameterType) || isListOfFiles(parameterType)) {
      return "form";
    }
    if (resolvedMethodParameter.hasParameterAnnotation(PathVariable.class)) {
      return "path";
    } else if (resolvedMethodParameter.hasParameterAnnotation(RequestBody.class)) {
      return "body";
    } else if (resolvedMethodParameter.hasParameterAnnotation(RequestPart.class)) {
      return "formData";
    } else if (resolvedMethodParameter.hasParameterAnnotation(RequestParam.class)) {
      return queryOrForm(parameterContext.getOperationContext());
    } else if (resolvedMethodParameter.hasParameterAnnotation(RequestHeader.class)) {
      return "header";
    } else if (resolvedMethodParameter.hasParameterAnnotation(ModelAttribute.class)) {
      LOGGER.warn("@ModelAttribute annotated parameters should have already been expanded via "
          + "the ExpandedParameterBuilderPlugin");
    }
    if (!resolvedMethodParameter.hasParameterAnnotations()) {
      return queryOrForm(parameterContext.getOperationContext());
    }
    return "body";
  }

在swagger展示页面中我们可以看到显示model的参数其parameter in都是body

在这里插入图片描述

结合上面的代码,我们可以看到没有注解描述的参数,最后都进入了这里面

if (!resolvedMethodParameter.hasParameterAnnotations()) {
            return queryOrForm(parameterContext.getOperationContext());
        }

该函数最后只会返回form和query两种类型

private static String queryOrForm(OperationContext context) {
        if (context.consumes().contains(MediaType.APPLICATION_FORM_URLENCODED) && context.httpMethod() == HttpMethod
                .POST) {
            return "form";
        }
        return "query";
    }

所以我们修改代码:

public static String findParameterType(ParameterContext parameterContext) {
			...
        }  else if (!resolvedMethodParameter.hasParameterAnnotation(RequestBody.class) && httpMethod.matches("POST")) {
            // 对Post方法并且没有@RequestBody描述的方法返回Body
            return "body";
        }
			..
    }

在其中添加一个else if 判断,对无RequestBody描述的参数也可以让它返回body

到这里我们就完成了对无@RequestBody注解的参数让其swagger也显示model模型


@RequestMapping描述方法时如何让swagger只展示post方法

许多使用@RequestMapping描述的方法在swagger中展示都会展示很多个方法,只是不同的请求类型。如何让他们只展示Post方法?

修改ApiOperationReader方法

原来的代码:

  public List<Operation> read(RequestMappingContext outerContext) {

    List<Operation> operations = newArrayList();

    Set<RequestMethod> requestMethods = outerContext.getMethodsCondition();
    Set<RequestMethod> supportedMethods = supportedMethods(requestMethods);

    //Setup response message list
    Integer currentCount = 0;
    for (RequestMethod httpRequestMethod : supportedMethods) {
      OperationContext operationContext = new OperationContext(new OperationBuilder(nameGenerator),
          httpRequestMethod,
          outerContext,
          currentCount);

      Operation operation = pluginsManager.operation(operationContext);
      if (!operation.isHidden()) {
        operations.add(operation);
        currentCount++;
      }
    }
    Collections.sort(operations, outerContext.operationOrdering());

    return operations;
  }

  private Set<RequestMethod> supportedMethods(Set<RequestMethod> requestMethods) {
    return requestMethods == null || requestMethods.isEmpty()
           ? allRequestMethods
           : requestMethods;
  }

注意

  private Set<RequestMethod> supportedMethods(Set<RequestMethod> requestMethods) {
    return requestMethods == null || requestMethods.isEmpty()
           ? allRequestMethods
           : requestMethods;
  }

该方法返回了allRequestMethods,这里面包括了

GET,
HEAD,
POST,
PUT,
PATCH,
DELETE,
OPTIONS,
TRACE;

这8种类型的Method,在上面循环的时候就会创建8个OperationContext,导致我们最终生成8个方法,找到该方法以后修改就比较简单了。

    private Set<RequestMethod> supportedMethods(Set<RequestMethod> requestMethods) {
        // 修改默认只显示Post方法
        return requestMethods == null || requestMethods.isEmpty()
                ? Sets.newHashSet(RequestMethod.POST)
                : requestMethods;
    }

我们让它只返回Post方法。


我上面的内容是基于https://blog.csdn.net/Driver_tu/article/details/100031407该链接的扩展,具体怎么把上面的代码在项目中应用,可以查看该博客

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值