概述

** 集成ui报404请查看官网解决方案**
我写文档的时候knife4j还没有getaway聚合swagger2相关的文档,后面发现官网也有了,可以优先查看knife4j官网里面的文档避免走弯路。。


2020-10-12:
swagger3.0已经发布,兼容2.0。

项目spring cloud基于 Greenwich.SR2, spring boot基于2.1.6.RELEASE
使用swagger可以生成api文档,让我们不再编写api文档,而且还自带调试功能,当然需要自己添加注解丰富文档的内容,单体服务使用swagger相信对大家来说都是没有问题的,下面将简单介绍单体服务使用swagger,以及使用gateway聚合swagger,由于swagger-ui的界面并不是那么还看,所以ui界面使用swagger-bootstrap-ui,一款界面优美的swagger-ui,现在使用了前后端分离,改名叫:knife4j
文档:https://doc.xiaominfo.com/guide/useful.html
新版本我感觉文档还有待完善,感兴趣的可以去看看,搭建有什么问题也建议先到官方文档中去看,因为可能或因为版本原因出现一些问题。

单个服务使用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.9.5</version>
        </dependency>

添加配置文件,名字随便取:

@Configuration
@EnableSwagger2
@EnableSwaggerBootstrapUI
public class SwaggerConfig {

    @Bean
    public Docket docket() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.withClassAnnotation(Api.class))
                .paths(PathSelectors.any())
                .build();
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("TEST-PROVIDER1")
                .description("服务提供者一")
                .version("1.0")
                .contact(new Contact("xx", "", "xxxx@qq.com"))
                .build();
    }
}

@EnableSwagger2:开启swagger2
@EnableSwaggerBootstrapUI:开启swagger-bootstrap-ui的增强文档,视情况而定,需要就添加不需要就不添加
其他没啥,网上对于这些的解释一大堆,值得注意的一点是扫描包哪里配置的是Api.class,会扫描所有带有api注解的controller,试想当你的扫描包不再一个目录是怎么办,之前在网上找的方法,但那个代码有个方法过时了,然后就自己和同事研究,个人觉得这个挺好的。
然后访问 ip:端口/doc.html就ok

gateway

我们开发不可能就只有一个服务,所以需要聚合所有的服务的文档
同理加配置:

		<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.9.5</version>
        </dependency>

添加配置,因为gate是基于webflux,swagger的资源接口应该是基于web的,所以我们需要自己配置资源接口

@RestController
@RequestMapping("/swagger-resources")
public class SwaggerHandler {

    @Autowired(required = false)
    private SecurityConfiguration securityConfiguration;

    @Autowired(required = false)
    private UiConfiguration uiConfiguration;
    private final SwaggerResourcesProvider swaggerResources;

    @Autowired
    public SwaggerHandler(SwaggerResourcesProvider swaggerResources) {
        this.swaggerResources = swaggerResources;
    }

    @GetMapping("/configuration/security")
    public Mono<ResponseEntity<SecurityConfiguration>> securityConfiguration() {
        return Mono.just(new ResponseEntity<>(
                Optional.ofNullable(securityConfiguration).orElse(SecurityConfigurationBuilder.builder().build()), HttpStatus.OK));
    }

    @GetMapping("/configuration/ui")
    public Mono<ResponseEntity<UiConfiguration>> uiConfiguration() {
        return Mono.just(new ResponseEntity<>(
                Optional.ofNullable(uiConfiguration).orElse(UiConfigurationBuilder.builder().build()), HttpStatus.OK));

    }

    @GetMapping("")
    public Mono<ResponseEntity> swaggerResources() {
        return Mono.just((new ResponseEntity<>(swaggerResources.get(), HttpStatus.OK)));
    }
}

对每个接口不了解的直接布起来后在使用接口访问便知
然后我们需要修改他的路由,取到所有的服务api文档,大概思路是去注册中心取到所有的服务,然后添上文档通用的后缀/v2/api-docs获取文档

@Component
@Primary
public class SwaggerProvider implements SwaggerResourcesProvider {

    /**
     * swagger的api json文档路径
     */
    public static final String API_URI = "/v2/api-docs";
    /**
     * Eureka发现功能的方法的名字,注册的服务会加入这个前缀
     */
    public static final String EUREKA_SUB_PFIX = "CompositeDiscoveryClient_";
    /**
     * 服务发现的路由处理器
     */
    private final DiscoveryClientRouteDefinitionLocator routeLocator;

    public SwaggerProvider(DiscoveryClientRouteDefinitionLocator routeLocator) {
        this.routeLocator = routeLocator;
    }

    @Override
    public List<SwaggerResource> get() {

        List<SwaggerResource> resources = new ArrayList<>();

        List<String> routes = new ArrayList<>();
        //从DiscoveryClientRouteDefinitionLocator 中取出routes,构造成swaggerResource
        routeLocator.getRouteDefinitions().subscribe(routeDefinition -> {
            resources.add(swaggerResource(
                    //获取id(服务注册的id)
                    routeDefinition.getId()
                            //去除CompositeDiscoveryClient_前缀
                            .substring(EUREKA_SUB_PFIX.length()),
                    //获取路由定义信息列表
                    routeDefinition.getPredicates()
                            //获取路径信息PredicateDefinition{name='Path', args={pattern=/byb-provider2/**}}
                            .get(0)
                            .getArgs()
                            //将pattern中的/**替换为服务swagger文档路径
                            .get("pattern")
                            .replace("/**", API_URI)));
        });
        //for是我自己写的过滤没有api文档的代码,自己视情况添加
        for (SwaggerResource swaggerResource : resources) {
            //获取所有服务的文档uri
            String uri = swaggerResource.getUrl();
            //获取服务名
            String serverName = uri.replace(API_URI, "");
            //拼接url
            String url = "http://regist.byb.com:38001/eureka/apps"+serverName;
            //获取RestTemplate实例
            RestTemplate restTemplate = new RestTemplate();
            HttpHeaders httpHeaders = new HttpHeaders();
            //添加请求头
            httpHeaders.add("Content-Type", "application/json");
            httpHeaders.add("Accept", "application/json");
            //请求体
            HttpEntity<String> httpEntity = new HttpEntity<String>(null,httpHeaders);
            //发送请求获取响应
            ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.GET, httpEntity, String.class);
            String response = responseEntity.getBody();
            //解析json
            JSONObject jsonObject;
            jsonObject = JSONObject.parseObject(response);
            String str1 = jsonObject.getString("application");

            jsonObject = JSONObject.parseObject(str1);
            String str2 = jsonObject.getString("instance");

            JSONArray jsonArray = JSONObject.parseArray(str2);
            String str3 = jsonArray.getString(0);

            jsonObject = JSONObject.parseObject(str3);
            String serverUrl = jsonObject.getString("homePageUrl");
            if (null != serverUrl && !"".equals(serverUrl)) {
                //拼接服务api文档的url
                String serverApi = serverUrl + "v2/api-docs";
                //发送请求
                try {
                    URL url1 = new URL(serverApi);
                    HttpURLConnection  httpUrlConn = (HttpURLConnection) url1.openConnection();
                    //设置连接超时时间
                    httpUrlConn.setConnectTimeout(1000);
                    //获取返回码
                    int code = httpUrlConn.getResponseCode();
                    if (code != 200) {
                        resources.remove(swaggerResource);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }


            }
        }
        return resources;
    }

    private SwaggerResource swaggerResource(String name, String location) {

        SwaggerResource swaggerResource = new SwaggerResource();
        swaggerResource.setName(name);
        swaggerResource.setLocation(location);
        swaggerResource.setSwaggerVersion("2.0");
        return swaggerResource;
    }
}

具体信息注释已经写的很完善了,同理访问ip:端口/doc.html即可访问,左上角即可切换项目,for循环是我自己添加的,用于排除没有api文档的微服务,不需要直接删除即可。
在这里插入图片描述
有问题下方沟通,我应该没有写漏东西。。。
附上swagger的详细注解

https://blog.csdn.net/zlhmeng/article/details/100524382

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐