swagger2 接口排序

      最近在使用swagger2作用在线文档工具,完成后发现在页面上模块和接口的顺序是混乱的。

     swagger 使用的版本信息

<dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
        </dependency>
        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>swagger-bootstrap-ui</artifactId>
            <version>1.8.9</version>
        </dependency>

     理想的顺序是,模块是开发、二次开发、测试,接口是开始、暂停、继续、结束。项目启动后,接口的显示没有和预计的一样。

      经过分析发现,接口信息的数据中通过http://127.0.0.1:8080/v2/api-docs接口获取的。在返回数据中,tags对应的是目录节点,paths对应的是各个接口,通过里面的tags里的。如果要进行排序,则返回结里tags和paths都是按照指定的顺序返回的。

      接下来分析源码

springfox.documentation.swagger2.mappers.ServiceModelToSwagger2MapperImpl的mapDocumentation方法:

  public Swagger mapDocumentation(Documentation from) {
        if (from == null) {
            return null;
        } else {
            Swagger swagger = new Swagger();
            swagger.setVendorExtensions(this.vendorExtensionsMapper.mapExtensions(from.getVendorExtensions()));
            swagger.setSchemes(this.mapSchemes(from.getSchemes()));
            // path属性设置
            swagger.setPaths(this.mapApiListings(from.getApiListings()));
            swagger.setHost(from.getHost());
            swagger.setDefinitions(this.modelMapper.modelsFromApiListings(from.getApiListings()));
        
 swagger.setSecurityDefinitions(this.securityMapper.toSecuritySchemeDefinitions(from.getResourceListing()));
            ApiInfo info = this.fromResourceListingInfo(from);
            if (info != null) {
                swagger.setInfo(this.mapApiInfo(info));
            }

            swagger.setBasePath(from.getBasePath());
             // tags 属性设置
            swagger.setTags(this.tagSetToTagList(from.getTags()));
....

 

springfox.documentation.swagger2.mappers.ServiceModelToSwagger2Mapper

//  paths 属性封闭实现方法 
protected Map<String, Path> mapApiListings(Multimap<String, ApiListing> apiListings) {
        Map<String, Path> paths = Maps.newTreeMap();
        Iterator var3 = apiListings.values().iterator();

        while(var3.hasNext()) {
            ApiListing each = (ApiListing)var3.next();
            Iterator var5 = each.getApis().iterator();

            while(var5.hasNext()) {
                ApiDescription api = (ApiDescription)var5.next();
                paths.put(api.getPath(), this.mapOperations(api, Optional.fromNullable(paths.get(api.getPath()))));
            }
        }

        return paths;
    }

//  tags 属性的封装实现方法
   protected List<Tag> tagSetToTagList(Set<springfox.documentation.service.Tag> set) {
        if (set == null) {
            return null;
        } else {
            List<Tag> list = new ArrayList(set.size());
            Iterator var3 = set.iterator();

            while(var3.hasNext()) {
                springfox.documentation.service.Tag tag = (springfox.documentation.service.Tag)var3.next();
                list.add(this.mapTag(tag));
            }

            return list;
        }
    }

经过代码跟踪分析,总结如下:

1. 模块的排序是依据tag 的名称进行的,虽然@Api里保留有position属性,但是已经完全弃用。

2.接口的排序也是依据@ApiOperation里value的值进行的,position属性虽然废弃,但是仍可以进行设置取值。

解决方案为依据排序设计规则,重写相应的方法。规则如下:

1.模块的排序,使用tag名称排序,在名称前加上前缀0X-,即在名称就加上"01-"、"02-"。但为了页面展示效果,在排序后把前缀进行处理;

2.接口的排序,使用@ApiOperation的position实现。

 代码实现  

@Api(tags = "01-开发")
@RestController
@RequestMapping("/b")
public class Test3Contoller {


    @ApiOperation(value = "开始",position = 1)
   @ApiImplicitParam(name = "platformNo", value = "平台编号", required = true, dataType = "String", defaultValue = "34020000001320000001")
    @GetMapping(value = "/start")
    public RespData queryCatalog(String platformNo) {
        return RespData.success();
    }
package com.ferry.configer;

import com.google.common.base.Optional;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import io.swagger.models.Operation;
import io.swagger.models.Path;
import io.swagger.models.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import springfox.documentation.builders.BuilderDefaults;
import springfox.documentation.service.ApiDescription;
import springfox.documentation.service.ApiListing;
import springfox.documentation.swagger2.mappers.ServiceModelToSwagger2MapperImpl;
import springfox.documentation.swagger2.mappers.VendorExtensionsMapper;

import java.util.*;


@Primary //同一个接口,可能会有几种不同的实现类,而默认只会采取其中一种的情况下
@Component("ServiceModelToSwagger2Mapper")
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CustomModelToSwaggerMapper extends ServiceModelToSwagger2MapperImpl {
    @Autowired
    private VendorExtensionsMapper vendorExtensionsMapper;


    protected Map<String, Path> mapApiListings(Multimap<String, ApiListing> apiListings) {
        Map<String, Path> paths = Maps.newTreeMap();
        Iterator var3 = apiListings.values().iterator();

        while (var3.hasNext()) {
            ApiListing each = (ApiListing) var3.next();
            List<ApiDescription> list = each.getApis();
            Iterator var5 = each.getApis().iterator();

            while (var5.hasNext()) {
                ApiDescription api = (ApiDescription) var5.next();
                paths.put(api.getOperations().get(0).getPosition() + "-" + api.getPath(), this.mapOperations(api, Optional.fromNullable(paths.get(api.getPath()))));
            }
        }
        Map<String, Path> paths2 = new LinkedHashMap<>();
        for (String key : paths.keySet()) {
            paths2.put(key.substring(key.indexOf("-") + 1), paths.get(key));
        }
        return paths2;
    }

    private Path mapOperations(ApiDescription api, Optional<Path> existingPath) {
        Path path = (Path) existingPath.or(new Path());
        Iterator var4 = BuilderDefaults.nullToEmptyList(api.getOperations()).iterator();

        while (var4.hasNext()) {
            springfox.documentation.service.Operation each = (springfox.documentation.service.Operation) var4.next();
            Operation operation = this.mapOperation(each);
            path.set(each.getMethod().toString().toLowerCase(), operation);
        }

        return path;
    }


    protected Operation mapOperation(springfox.documentation.service.Operation from) {
        if (from == null) {
            return null;
        } else {
            Operation operation = new Operation();
            operation.setSecurity(this.mapAuthorizations(from.getSecurityReferences()));
            operation.setVendorExtensions(this.vendorExtensionsMapper.mapExtensions(from.getVendorExtensions()));
            operation.setDescription(from.getNotes());
            operation.setOperationId(from.getPosition() + from.getUniqueId());
            operation.setResponses(this.mapResponseMessages(from.getResponseMessages()));
            operation.setSchemes(this.stringSetToSchemeList(from.getProtocol()));
            Set<String> set = from.getTags();
            if (set != null) {
                Iterator<String> it= set.iterator();
                Set<String> rset= new HashSet<>();
                while (it.hasNext()){
                    String tagName= it.next();
                    rset.add(tagName.substring(tagName.indexOf("-")+1));
                }
                operation.setTags(new ArrayList(rset));
            } else {
                operation.setTags((List) null);
            }

            operation.setSummary(from.getSummary());
            Set<String> set1 = from.getConsumes();
            if (set1 != null) {
                operation.setConsumes(new ArrayList(set1));
            } else {
                operation.setConsumes((List) null);
            }

            Set<String> set2 = from.getProduces();
            if (set2 != null) {
                operation.setProduces(new ArrayList(set2));
            } else {
                operation.setProduces((List) null);
            }

            operation.setParameters(this.parameterListToParameterList(from.getParameters()));
            if (from.getDeprecated() != null) {
                operation.setDeprecated(Boolean.parseBoolean(from.getDeprecated()));
            }

            return operation;
        }
    }

    @Override
    protected List<Tag> tagSetToTagList(Set<springfox.documentation.service.Tag> set) {
        List<Tag> tlist = super.tagSetToTagList(set);
        List<Tag> result = new LinkedList<>();
        Iterator<Tag> it = tlist.iterator();
        while (it.hasNext()) {
            Tag tag = it.next();
            Tag tt = new Tag();
            tt.setName(tag.getName().substring(tag.getName().indexOf("-") + 1));
            tt.setDescription(tag.getDescription());
            result.add(tt);
        }
        return result;
    }
}

     重新运行的效果:

                                      

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值