Knife4j + Nacos + springCloudGateway最快,最全,最有效的整合方式

5,106 阅读2分钟

「这是我参与2022首次更文挑战的第3天,活动详情查看:2022首次更文挑战

基于微服务开发的大环境,有一个公共统一的接口文档很关键,所以借着此次整合项目组件的机会,分享下Knife4j + Nacos + springCloudGateway的整合过程,希望帮助到各位开发者,不废话,纯干货!!!

nacos的部署配置参考:Naocs 2.0版本变更要点详解

项目地址:gitee.com/wei_rong_xi…

一、引入依赖

目前knife4j做的不错,全局配合springboot只需要引入一个依赖就可以了,无论是网关,还是其他的子服务,都需要引入如下的依赖:

<dependency>
    <groupId>com.github.xiaoymin</groupId>
    <artifactId>knife4j-spring-boot-starter</artifactId>
    <version>2.0.9</version>
</dependency>

另外,因为我本人懒得写get/set方法,所以通常都会引入lombok:

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.22</version>
</dependency>

nacos注册中心和配置中心的依赖:

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    <version>2.2.7.RELEASE</version>
</dependency>

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
    <version>2.2.7.RELEASE</version>
</dependency>

二、服务配置

2.1 网关-SpringCloudGateway

网关需要在springboot项目中引入其依赖:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
    <version>2.2.10.RELEASE</version>
</dependency>

【注意】 不要引入下面的依赖,否则网关启动会报冲突错误,而普通springboot服务是需要的:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

配置文件增加如下内容:

spring:
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true # 开启从注册中心动态创建路由的功能,利用微服务名进行路由

增加 如下两个class:

  • SwaggerProvider:获取nacos当中注册的服务名称,以服务名称拼接接口文档路径,组成完成的接口文档访问路径
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.cloud.gateway.route.RouteLocator;
    import org.springframework.stereotype.Component;
    import springfox.documentation.swagger.web.SwaggerResource;
    import springfox.documentation.swagger.web.SwaggerResourcesProvider;
    
    import java.util.ArrayList;
    import java.util.HashSet;
    import java.util.List;
    import java.util.Set;
    
    @Component
    public class SwaggerProvider implements SwaggerResourcesProvider {
        /**
         * 接口地址
         */
        public static final String API_URI = "/v2/api-docs";
    
        /**
         * 路由加载器
         */
        @Autowired
        private RouteLocator routeLocator;
    
        /**
         * 网关应用名称
         */
        @Value("${spring.application.name}")
        private String applicationName;
    
        @Override
        public List<SwaggerResource> get() {
            //接口资源列表
            List<SwaggerResource> resources = new ArrayList<>();
            //服务名称列表
            List<String> routeHosts = new ArrayList<>();
            // 获取所有可用的应用名称
            routeLocator.getRoutes().filter(route -> route.getUri().getHost() != null)
                    .filter(route -> !applicationName.equals(route.getUri().getHost()))
                    .subscribe(route -> routeHosts.add(route.getUri().getHost()));
            // 去重,多负载服务只添加一次
            Set<String> existsServer = new HashSet<>();
            routeHosts.forEach(host -> {
                // 拼接url
                String url = "/" + host + API_URI;
                //不存在则添加
                if (!existsServer.contains(url)) {
                    existsServer.add(url);
                    SwaggerResource swaggerResource = new SwaggerResource();
                    swaggerResource.setUrl(url);
                    swaggerResource.setName(host);
                    resources.add(swaggerResource);
                }
            });
            return resources;
        }
    
    }
    
  • SwaggerHandler:获取接口文档
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.http.HttpStatus;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    import reactor.core.publisher.Mono;
    import springfox.documentation.swagger.web.*;
    
    import java.util.Optional;
    
    @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));
        }
    
        /**
         * 获取接口信息
         * @date: 2020/12/3
         * @param
         * @return reactor.core.publisher.Mono<org.springframework.http.ResponseEntity>
         * @author weirx
         * @version 3.0
         */
        @GetMapping("")
        public Mono<ResponseEntity> swaggerResources() {
            return Mono.just((new ResponseEntity<>(swaggerResources.get(), HttpStatus.OK)));
        }
    }
    

2.2 业务服务-用户服务为例

引入一个配置类,次配置类获取我们在服务配置文件当中配置的基本信息,加载到接口文档当中:

/**
 * description: knife4j配置文件
 *
 * @author: weirx
 * @time: 2022/1/18 9:44
 */
@Data
@Configuration
@EnableSwagger2WebMvc
@ConfigurationProperties(prefix="swagger")
public class Knife4jConfiguration {


    private String version;

    private String termsOfServiceUrl;

    private String description;

    private String basePackage;

    @Bean(value = "defaultApi2")
    public Docket defaultApi2() {
        Docket docket = new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(new ApiInfoBuilder()
                        .description(description)
                        .termsOfServiceUrl(termsOfServiceUrl)
                        .version(version)
                        .build())
                .select()
                //这里指定Controller扫描包路径
                .apis(RequestHandlerSelectors.basePackage(basePackage))
                .paths(PathSelectors.any())
                .build();
        return docket;
    }
}

这个配置类建议抽取一个公共依赖服务,或者自己封装一个starter,使用spi的方式加载,否则每个服务都需要增加相同的配置,依赖,甚至是通用工具类,枚举等等。就像spring boot为我们封装了很多引入依赖后就直接可以使用的starter一样。我们可以在其基础上再次封装,添加我们自己需要的配置。

本文使用的样例是使用starter的方式,包括一些公共依赖等。

不明白的同学可参考开篇的gitee源码地址。

配置文件中增加如下,其中base-package这个配置一定要将你的controller包含在内,否则是找不到你的接口地址的:

swagger:
  enabled: true
  base-package: com.wjbgn.user
  version: V1.0
  description: 用户服务
  terms-of-service-url: http://localhost:8003/doc.html

用户服务controller中接口增加部分注解,用来展示接口信息,我们以之前集成mybatis-plus的接口为例,做如下修改,以下只以新增接口代码为例:

  • @Api:是整个controller展示的名字
  • @ApiOperation:是接口的描述
/**
 * @description: 用户controller
 * @author:weirx
 * @date:2022/1/17 17:39
 * @version:3.0
 */
@Api(tags = "mybatis-plus测试接口")
@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private IUserService userService;

    /**
     * description: 新增

     * @return: boolean
     * @author: weirx
     * @time: 2022/1/17 19:11
     */
    @ApiOperation(value = "新增")
    @GetMapping("/save")
    public boolean save() {
        UserDO userDO = new UserDO();
        userDO.setNickname("大漂亮");
        userDO.setSex(SexEnum.MAN);

        return userService.save(userDO);
    }
}

我们还需要在你的DTO的每个字段上面,添加注解@ApiModelProperty(notes = "用户id"),这个表示你的字段的含义是什么。

到此为止,大功已成,下一节直接看效果。

三、测试

下面就是验证我们的成果,启动网关和用户服务,访问网关接口文档访问地址: http://localhost:8000/doc.html ,注意自己的网关的端口是什么,你的可不一定是8000.

image.png

image.png

image.png

注意:微服务在nacos的注册并不是实时的,换言之,需要去检测服务的心跳,nacos应该是5秒,之后你的接口文档才会出现对应的服务,不是启动好立马出现的。

如果出现404,或者503就说明服务还没完全注册,稍等一会儿,刷新就好了。

至此整合完毕,是不是很简单。

项目地址:gitee.com/wei_rong_xi…

如果有问题,没有搭建成功的,评论区留言,咱们一起找问题。

下一篇文章,主要是关于自动代码生成的,补充前面mybatis-plus-generator没有介绍的遗憾。采用mybatis-plus-generator + velocity模板引擎,一次定义好代码格式,模板代码从后端到前端一键生成,嘎嘎方便,记得关注啊。

干货推荐

还不会用mybatis-plus,手把手教你

别在网上乱找了,【idea+maven】多环境配置,不坑!!

Naocs 2.0版本变更要点详解