Spring Cloud Alibaba微服务实战十一 - Swagger接口文档聚合

作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO

联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬

学习必须往深处挖,挖的越深,基础越扎实!

阶段1、深入多线程

阶段2、深入多线程设计模式

阶段3、深入juc源码解析


阶段4、深入jdk其余源码解析


阶段5、深入jvm源码解析

码哥源码部分

码哥讲源码-原理源码篇【2024年最新大厂关于线程池使用的场景题】

码哥讲源码【炸雷啦!炸雷啦!黄光头他终于跑路啦!】

码哥讲源码-【jvm课程前置知识及c/c++调试环境搭建】

​​​​​​码哥讲源码-原理源码篇【揭秘join方法的唤醒本质上决定于jvm的底层析构函数】

码哥源码-原理源码篇【Doug Lea为什么要将成员变量赋值给局部变量后再操作?】

码哥讲源码【你水不是你的错,但是你胡说八道就是你不对了!】

码哥讲源码【谁再说Spring不支持多线程事务,你给我抽他!】

终结B站没人能讲清楚红黑树的历史,不服等你来踢馆!

打脸系列【020-3小时讲解MESI协议和volatile之间的关系,那些将x86下的验证结果当作最终结果的水货们请闭嘴】

导读:在SpringCloud体系架构中,我们需要的每个服务都需要对外输出接口文档,本篇内容主要是给我们的微服务配上Swagger的接口文档,并在网关层完成接口聚合。

Swagger2简介

在当下很多项目都会采用前后端分离的模式,前端和后端的工作由不同的开发人员完成。在这种开发模式下,我们需要维护一份及时更新且完整的Rest API接口文档。传统意义上的文档都是后端人员在开发相关接口后手动更新到接口文档上,但是这种方式很难保证文档的及时性,而且由于一些原因后端开发人员可能会忘记更新,这样就会导致随着开发的进行接口文档会失去他本身的参考意义,反而会增加沟通成本。而 Swagger 给我们提供了一个全新的维护 API 文档的方式,他有以下几个作用:

  • 只需要后端开发人员给接口加上几个注解,Swagger就可以根据代码自动生成API文档,节省编写接口文档的工作量,而且对接口修改时只需要修改相应的注解,能保证接口的及时性;
  • SwaggerUI展现出来的是一份可交互式的API文档,我们可以直接在接口页面对功能测试,省去了大量接口联调的时间;

Swagger2有以下几个常见注解,大家在使用过程中会经常用到。

@Api

此注解可以用来标记 Controller 的功能,如:

    @Api(tags = "product模块")
    public class ProductController implements ProductFeign {
    	
    }

@ApiOperation

此注解用来标记一个方法的作用

    @ApiOperation(value = "根据产品编码查找对应的产品")
    public ResultData<ProductDTO> getByCode(@PathVariable String productCode){
    	...
    }

@ApilmplicitParam@ApilmplicitParams

这组注解用来对参数进行描述,@ApilmplicitParam 有几个重要的参数:name:参数名value:参数的汉字说明、解释required:参数是否必须传paramType:参数放在哪个地方(header:对应@RequestHeader的参数;query :对应@RequestParam的参数;path :对应@PathVariable的参数;body:对应 @RequestBody 的参数;form(普通表单提交) )

    @ApiImplicitParam(name = "productCode",value = "产品编码", required = true,paramType = "path")
    public ResultData<ProductDTO> getByCode(@PathVariable String productCode){
    	...
    }
    @ApiImplicitParam(name = "productCode" , value = "产品编码",required = true, paramType = "query")
    public ResultData<String> delete(@RequestParam String productCode){
    	...
    }

如果有多个参数,则需要使用@ApilmplicitParams 注解。

@ApiModel ,@ApiModelProperty

如果参数是一个对象,则需要在对象所在的类上加上此注解。这种一般用在post创建的时候,使用 @RequestBody 这样的场景,请求参数无法使用 @ApiImplicitParam 注解进行描述的时候 。在具体字段上则使用@ApiModelProperty注解。如:

    @Data
    @ApiModel(value = "产品封装类ProductDTO",description = "产品相关信息封装,用于接口传参")
    public class ProductDTO {
        @ApiModelProperty(value = "产品主键")
        private Integer id;
        @ApiModelProperty(value = "产品编码")
        private String productCode;
        @ApiModelProperty(value = "产品名称")
        private String productName;
        @ApiModelProperty(value = "数量")
        private Integer count;
        @ApiModelProperty(value = "单价")
        private BigDecimal price;
    }

使用

在项目中要使用Swagger2很简单,按照以下几步即可:

  • 在pom文件中引入jar包 每个微服务都需要使用,我们直接将其引入在cloud-common服务中
    <!--swagger2-->
    <dependency>
    	<groupId>io.springfox</groupId>
    	<artifactId>springfox-swagger2</artifactId>
        <version>2.9.2</version>
    </dependency>
    
    <dependency>
    	<groupId>io.springfox</groupId>
    	<artifactId>springfox-swagger-ui</artifactId>
        <version>2.9.2</version>
    </dependency>
  • 在微服务中编写swagger2的配置类SwaggerConfig
    @Configuration
    @EnableSwagger2
    public class SwaggerConfig {
        private static final String VERSION = "1.0.0";
        /**
         * 创建API
         */
        @Bean
        public Docket createRestApi(){
            return new Docket(DocumentationType.SWAGGER_2)
                    .apiInfo(apiInfo())
                    .select()
                    //指定接口包所在路径
                    .apis(RequestHandlerSelectors.basePackage("com.javadaily.product.controller"))
                    .paths(PathSelectors.any())
                    .build();
        }
    
        /**
         * 添加摘要信息
         */
        private ApiInfo apiInfo() {
            return new ApiInfoBuilder()
                    .title("product-server接口文档")
                    .contact(new Contact("JAVA日知录","http://javadaily.cn","jianzh5@163.com"))
                    .description("product-server接口文档")
                    .termsOfServiceUrl("http://javadaily.cn")
                    .license("The Apache License, Version 2.0")
                    .licenseUrl("http://www.apache.org/licenses/LICENSE-2.0.html")
                    .version(VERSION)
                    .build();
        }
    }

.apis方法用于指定生成注解的范围,有以下四种取值逻辑 ①RequestHandlerSelectors.any(),为所有接口都生成API文档,这种方式不必在接口上加任何注解,但是生成的文档没有任何注释,可读性不高;
RequestHandlerSelectors.basePackage(xx.xx),为指定包下的controller生成接口文档
RequestHandlerSelectors.withClassAnnotation(Api.class),为有@api注解的接口生成api文档
RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class),为有@ApiOperation注解的方法生成API文档。

  • 给相关接口加上Swagger的注解 注解的详细说明参见上文。

  • 打开swagger2接口API页面`http://localhost:8020/swagger-ui.html```

网关聚合

我们已经给各个微服务加上了api文档,但是每次都需要分别输入各个微服务的文档地址,不太方便。本节内容主要是将各个微服务的api地址聚合到网关层,打开网关的api地址即可查看其它所有服务的接口文档,效果如下:

实现步骤如下:

  • 编写配置类实现 SwaggerResourcesProvider 接口聚合其他微服务的api资源
    @Component
    @AllArgsConstructor
    public class CustomSwaggerResourceProvider implements SwaggerResourcesProvider {
        /**
         * Swagger2默认的url后缀
         */
        public static final String SWAGGER2URL = "/v2/api-docs";
        /**
         * 网关路由
         */
        private final RouteLocator routeLocator;
        private final GatewayProperties gatewayProperties;
        /**
         * 聚合其他服务接口
         * @return
         */
        @Override
        public List<SwaggerResource> get() {
            List<SwaggerResource> resourceList = new ArrayList<>();
            List<String> routes = new ArrayList<>();
            //获取网关中配置的route
            routeLocator.getRoutes().subscribe(route -> routes.add(route.getId()));
            gatewayProperties.getRoutes().stream().filter(routeDefinition -> routes.contains(routeDefinition.getId()))
                    .forEach(routeDefinition -> routeDefinition.getPredicates().stream()
                    .filter(predicateDefinition -> "Path".equalsIgnoreCase(predicateDefinition.getName()))
                    .forEach(predicateDefinition -> resourceList.add(
                                swaggerResource(
                                    routeDefinition.getId(),
                                    predicateDefinition
                                            .getArgs()
                                            .get(NameUtils.GENERATED_NAME_PREFIX + "0")
                                            .replace("/**",SWAGGER2URL)
    //这里拼接时需要注意
    //网关配置account映射到account-service,要么将网关的配置修改成account-service映射成account-service
    //要么就在这个拼接处解决
                            )
                    )));
            return resourceList;
        }
    
        private SwaggerResource swaggerResource(String name, String location) {
            SwaggerResource swaggerResource = new SwaggerResource();
            swaggerResource.setName(name);
            swaggerResource.setLocation(location);
            swaggerResource.setSwaggerVersion("2.0");
            return swaggerResource;
        }
    }
  • 自定义Rest接口
    @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)));
        }
    }

  • 31
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值