springfox 源码分析(十二) 遍历接口获取ApiDescription集合

2019/05/28 springfox 浏览

ApiDescription是springfox提供的接口描述信息类,在springfox 源码分析(十) 遍历接口获取Model对象中我们拿到了接口的类型Model集合信息,但除了Model信息,接口还有更多的信息

基础信息

主要包括:接口路径、consumes、produces、参数、请求类型、描述、说明、响应状态码、是否过时、扩展信息、分组

因为我们的接口可以运行多个请求类型的存在,所以以上信息在springfox是通过Operation来声明的

先来看ApiDescription的源码

public class ApiDescription {
  //分组名称
  private final String groupName;
  //路径
  private final String path;
  //描述
  private final String description;
  //操作信息集合
  //一个接口有可能存在多个请求方法类型,即:GET、POST、PUT、DELETE等,所以这里也是1:N的映射关系
  private final List<Operation> operations;
  //是否隐藏
  private final Boolean hidden;
    //getter and setters....
}

在代码注释中,我也做了说明

因为一个接口有可能存在多个请求方法类型,即:GET、POST、PUT、DELETE等,所以这里也是1:N的映射关系,即存在多个Operation集合

Operation的属性

public class Operation {
  //请求接口
  private final HttpMethod method;
  //接口名称
  private final String summary;
  //接口描述信息
  private final String notes;
  private final ModelReference responseModel;
  //唯一id
  private final String uniqueId;
  private final int position;
  //tags
  private final Set<String> tags;
  private final Set<String> produces;
  private final Set<String> consumes;
  private final Set<String> protocol;
  //是否隐藏
  private final boolean isHidden;
  private final Map<String, List<AuthorizationScope>> securityReferences;
  //参数
  private final List<Parameter> parameters;
  //状态码
  private final Set<ResponseMessage> responseMessages;
  //是否过时
  private final String deprecated;
  //扩展信息
  private final List<VendorExtension> vendorExtensions;

  //setter and getter..   
}

在Operation中声明的属性中就是我们上面介绍的接口相关信息.

初始化

我们知道了接口的介绍信息,此时,来看springfox如何处理,将接口的上下文信息最终初始化转换为ApiDescription

ApiDescriptionReader.read方法

/***
 * 获取ApiDescription接口集合信息
 * @param outerContext
 * @return
 */
public List<ApiDescription> read(RequestMappingContext outerContext) {
  PatternsRequestCondition patternsCondition = outerContext.getPatternsCondition();
  ApiSelector selector = outerContext.getDocumentationContext().getApiSelector();

  List<ApiDescription> apiDescriptionList = newArrayList();
  for (String path : matchingPaths(selector, patternsCondition)) {
    String methodName = outerContext.getName();
    try {
      RequestMappingContext operationContext = outerContext.copyPatternUsing(path);
	//根据接口上下文获取Operation集合
      List<Operation> operations = operationReader.read(operationContext);
      if (operations.size() > 0) {
        operationContext.apiDescriptionBuilder()
            .groupName(outerContext.getGroupName())
            .operations(operations)
            .pathDecorator(pluginsManager.decorator(new PathContext(outerContext, from(operations).first())))
            .path(path)
            .description(methodName)
            .hidden(false);
        ApiDescription apiDescription = operationContext.apiDescriptionBuilder().build();
        lookup.add(outerContext.key(), apiDescription);
        apiDescriptionList.add(apiDescription);
      }
    } catch (Error e) {
      String contentMsg = "Skipping process path[" + path + "], method[" + methodName + "] as it has an error.";
      log.error(contentMsg, e);
    }
  }
  return apiDescriptionList;
}

核心操作是通过operationReader.read操作,获取Operation集合

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);
		//调用OperationPlugin插件,构造Operation对象
      Operation operation = pluginsManager.operation(operationContext);
        //添加
      if (!operation.isHidden()) {
        operations.add(operation);
        currentCount++;
      }
    }
    Collections.sort(operations, outerContext.operationOrdering());

    return operations;
  }

主要的逻辑如下:

  • 获取当前支持的接口类型,包括GET POST、PUT、DELETE等
  • 通过调用OperationPlugin的插件对Operation中的每个属性进行赋值操作,包括参数类型、描述、响应状态码等等信息

OperationPlugin插件包含了多个实现类型,这个可以参考前面介绍的springfox 源码分析(五) web配置类Plugin插件的使用

既然Operation提供了扩展参数,那么我们后面是可以进行添加自定义扩展的

下一篇会介绍如何添加springfox的接口扩展字段.

站内搜索

    Table of Contents