20、微服务构建:Spring Boot 与 Vert.x 的 API 文档及应用实践

微服务构建:Spring Boot 与 Vert.x 的 API 文档及应用实践

1. Swagger 文档与 OpenAPI

在微服务架构中,会构建大量的 API 用于数据暴露和服务间通信,因此对 API 进行文档记录十分必要。为规范 REST API 的描述,开放 API 倡议(OAI)应运而生,其目的是创建和发展一个与供应商无关的标准描述格式。SmartBear 公司将 Swagger 规范捐赠给 OAI,使其成为 API 文档的事实标准。

Spring 本身没有内置的 API 文档生成机制,但借助 SpringFox 等开源框架可以轻松实现。SpringFox 能为使用 Spring 框架编写的 JSON API 自动生成可读的规范。

1.1 集成 Swagger 和 SpringFox

要集成 Swagger 和 SpringFox,需在 Maven 的 pom.xml 文件中添加相关依赖:

<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>

然后在 Spring Boot 配置中创建 Docket bean 以集成 Swagger 2:

@Configuration
@EnableSwagger2
public class SwaggerConfig extends WebMvcConfigurationSupport {
    @Bean
    public Docket api() {
        return new Docket(DocumentationType.SWAGGER_2).select()
           .apis(RequestHandlerSelectors.basePackage(
"com.packtpub.springboot.footballplayermicroservice.controller"))
           .paths(PathSelectors.any())
           .build();
    }
    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("swagger-ui.html")
            .addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**")
            .addResourceLocations("classpath:/META-INF/resources/webjars/");
    }
}

这里使用 @EnableSwagger2 注解启用 Swagger 支持, api 方法通过字符串谓词过滤要记录的控制器和方法。

运行应用程序:

$ mvn spring-boot:run

通过访问 http://localhost:8080/v2/api-docs 可获取 API 文档的 JSON 表示。以下是部分示例:

{
    "swagger":"2.0",
    "info":{
        "description":"Api Documentation",
        "version":"1.0",
        "title":"Api Documentation",
        "termsOfService":"urn:tos",
        "contact":{},
        "license":{
            "name":"Apache 2.0",
            "url":"http://www.apache.org/licenses/LICENSE-2.0"
        }
    },
    "host":"localhost:8080",
    "basePath":"/",
    "tags":[
        {
            "name":"football-player-rest-controller",
            "description":"Football Player REST Controller"
        }
    ],
    "paths":{
        "/footballplayer":{
            "get":{
                "tags":[
                    "football-player-rest-controller"
                ],
                "summary":"findAll",
                "operationId":"findAllUsingGET",
                "produces":[
                    "application/json"
                ],
                "responses":{
                    "200":{
                        "description":"OK",
                        "schema":{
                            "$ref":"#/definitions/Iterable«FootballPlayer»"
                        }
                    },
                    "401":{
                        "description":"Unauthorized"
                    },
                    "403":{
                        "description":"Forbidden"
                    },
                    "404":{
                        "description":"Not Found"
                    }
                },
                "deprecated":false
            }
        },
        "/footballplayer/delete/{id}":{
            "delete":{
                "tags":[
                    "football-player-rest-controller"
                ],
                "summary":"delete",
                "operationId":"deleteUsingDELETE",
                "produces":[
                    "application/json"
                ],
                "parameters":[
                    {
                        "name":"id",
                        "in":"path",
                        "description":"id",
                        "required":true,
                        "type":"integer",
                        "format":"int32"
                    }
                ],
                "responses":{
                    "200":{
                        "description":"OK"
                    },
                    "204":{
                        "description":"No Content"
                    },
                    "401":{
                        "description":"Unauthorized"
                    },
                    "403":{
                        "description":"Forbidden"
                    }
                },
                "deprecated":false
            }
        }
    }
}
1.2 使用 Swagger UI

为获取可读、结构化的文档,可使用 Swagger UI。访问 http://localhost:8080/swagger-ui.html 即可查看生成的文档。

在使用前,可自定义控制台的头部部分,向用户解释 UI 中描述的 API 文档类型。在 SwaggerConfig 类中添加元数据 API 信息:

private ApiInfo metaData() {
    return new ApiInfoBuilder()
       .title("Spring Boot REST API")
       .description("\"Spring Boot REST API for Football Player Microservice\"")
       .version("1.0.0")
       .license("Apache License Version 2.0")
       .licenseUrl("https://www.apache.org/licenses/LICENSE-2.0\"")
       .contact(new Contact("Mauro Vocale",
            "https://github.com/Hands-on-MSA-JakartaEE",
            "mauro.vocale@gmail.com"))
       .build();
}

并在 SwaggerConfig 类的 api 方法的管道构建器中添加对 metaData 方法的调用。重新运行应用程序:

$ mvn spring-boot:run

此时可看到与构建和暴露 API 的组织相关的更详细信息。

1.3 自定义控制器类

为描述操作端点的目的,可使用 @ApiOperation 注解描述端点及其响应类型,示例如下:

@ApiOperation(value = "View all available football players", response = Iterable.class)
@ApiResponses(value = {
    @ApiResponse(code = 200, message = "Successfully retrieved list"),
    @ApiResponse(code = 404, message = "The resource you were trying to reach is not found")
})
@RequestMapping(method = RequestMethod.GET, produces = "application/json")
public Iterable<FootballPlayer> findAll() {
    return service.findAll();
}

@ApiOperation(value = "Add a football player")
@RequestMapping(value = "/save", method = RequestMethod.POST, produces = "application/json")
public FootballPlayer save(@RequestBody FootballPlayer entity) {
    return service.save(entity);
}

@ApiOperation(value = "Update a football player")
@RequestMapping(value = "/update/{id}", method = RequestMethod.PUT, produces = "application/json")
public FootballPlayer edit(@PathVariable Integer id, @RequestBody FootballPlayer entity) {
    return service.save(entity);
}

@ApiOperation(value = "Delete a football player")
@RequestMapping(value = "/delete/{id}", method = RequestMethod.DELETE, produces = "application/json")
public void delete(@PathVariable Integer id) {
    service.deleteById(id);
}

@ApiOperation(value = "Search a football player with an ID", response = FootballPlayer.class)
@RequestMapping(value = "/show/{id}", method = RequestMethod.GET, produces = "application/json")
public Optional<FootballPlayer> findById(@PathVariable Integer id) {
    return service.findById(id);
}

这样用户就能清楚了解微服务应用暴露的 API 及其目标。

1.4 测试 API

以“Search a football player with an ID” API(路径为 /footballplayer/show/{id} )为例,Swagger 会显示以下信息:
- HTTP 动词:GET
- API 简要描述
- 调用 API 所需的参数(此处为 Id)
- 不同类型的响应:JSON 对象表示和 HTTP 错误代码

测试 API 的步骤如下:
1. 点击“Try it out”按钮。
2. 插入 ID 参数并点击“Execute”按钮。
3. 查看 API 调用的响应。

2. 使用 Vert.x 构建微服务

Vert.x 是一个用于构建分布式和响应式系统的开源 Eclipse 工具包,基于响应式流原则,提供了编写轻量级和响应式应用程序的灵活方式。它采用异步和非阻塞的开发模型,基于事件循环处理请求,避免客户端长时间等待。

2.1 Maven 设置

Vert.x 与 Apache Maven 3.2 或更高版本兼容,为方便管理所有 Vert.x 依赖,可让 Maven POM 文件继承 vertx-stack-depchain BOM。以下是一个示例 pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    ...
    <properties>
        <java.version>1.8</java.version>
        <maven-compiler-plugin.version>3.5.1</maven-compiler-plugin.version>
        <maven-shade-plugin.version>2.4.3</maven-shade-plugin.version>
        <maven-surefire-plugin.version>2.21.0</maven-surefire-plugin.version>
        <exec-maven-plugin.version>1.5.0</exec-maven-plugin.version>
        <vertx.version>3.5.4</vertx.version>
        ...
    </properties>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>io.vertx</groupId>
                <artifactId>vertx-stack-depchain</artifactId>
                <version>${vertx.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <dependencies>
        ...
    </dependencies>
    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.5.1</version>
                    <configuration>
                        <source>1.8</source>
                        <target>1.8</target>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>${maven-shade-plugin.version}</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                        <configuration>
                            <transformers>
                                <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                    <manifestEntries>
                                        <Main-Class>io.vertx.core.Launcher</Main-Class>
                                        <Main-Verticle>${main.verticle}</Main-Verticle>
                                    </manifestEntries>
                                </transformer>
                                <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                                    <resource>
                                        META-INF/services/io.vertx.core.spi.VerticleFactory
                                    </resource>
                                </transformer>
                            </transformers>
                            <outputFile>
                                ${project.build.directory}/${project.artifactId}-${project.version}-fat.jar
                            </outputFile>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            ...
        </plugins>
    </build>
</project>

使用以下命令构建和打包应用程序:

$ mvn clean package
2.2 Gradle 设置

Gradle 是一个开源的构建自动化工具,可使用 Groovy 或 Kotlin DSL 编写脚本。要在 Gradle 项目中使用 Vert.x,可创建如下 Gradle 文件:

plugins {
    id 'java'
    id 'application'
    id 'com.github.johnrengelman.shadow' version '2.0.4'
}

ext {
    vertxVersion = '3.5.4'
    junitJupiterEngineVersion = '5.2.0'
}

repositories {
    mavenLocal()
    jcenter()
}

group = 'com.packtpub.vertx'
version = '1.0.0-SNAPSHOT'
sourceCompatibility = '1.8'
mainClassName = 'io.vertx.core.Launcher'
def mainVerticleName = 'com.packtpub.vertx.football-player-microservice.MainVerticle'
def watchForChange = 'src/**/*'
def doOnChange = './gradlew classes'

dependencies {
    implementation "io.vertx:vertx-core:$vertxVersion"
    implementation "io.vertx:vertx-config:$vertxVersion"
    ...
}

shadowJar {
    classifier = 'fat'
    manifest {
        attributes 'Main-Verticle': mainVerticleName
    }
    mergeServiceFiles {
        include 'META-INF/services/io.vertx.core.spi.VerticleFactory'
    }
}

...

run {
    args = ['run', mainVerticleName, "--redeploy=$watchForChange", "--launcher-class=$mainClassName", "--on-redeploy=$doOnChange"]
}

构建可执行 JAR 的命令:

$ ./gradlew shadowJar

运行可执行 JAR 的命令:

$ java -jar build/libs/gradle-my-vertx-project.jar

或者使用以下 Gradle 命令运行:

$ ./gradlew run
2.3 构建足球运动员微服务

要构建一个简单的足球运动员微服务,该服务处理足球运动员领域,暴露 CRUD API,并使用 PostgreSQL 数据库存储和检索信息。所需工具及安装信息如下:
| 工具 | 安装链接 |
| ---- | ---- |
| Apache Maven 3.5.4 | https://maven.apache.org/install.html |
| JDK 1.8.0_171 | 推荐 OpenJDK:http://openjdk.java.net/install/ |
| Vert.x 版本 3.5.4 | 后续描述使用说明 |
| Docker Community Edition 18.06.1 | https://docs.docker.com/install/ |

2.4 数据库安装和配置

安装 Docker 后,在新终端窗口中运行以下命令启动 PostgreSQL 容器:

$ docker run --name postgres_vertx -e POSTGRES_PASSWORD=postgresPwd -e POSTGRES_DB=football_players_registry -d -p 5532:5432 postgres

该命令会从 Docker 公共注册表中拉取最新的 PostgreSQL 版本,并下载运行容器所需的所有层。

验证容器是否启动:

$ docker ps -a

查看容器日志:

$ docker logs -f <容器 ID>

连接到容器:

$ docker exec -it <容器 ID> bash

登录 PostgreSQL:

$ psql -U postgres

查看数据库列表:

$ \l

连接到 football_players_registry 数据库:

$ \connect football_players_registry

创建 FOOTBALL_PLAYER 表:

CREATE TABLE FOOTBALL_PLAYER(
    ID SERIAL PRIMARY KEY NOT NULL,
    NAME VARCHAR(50) NOT NULL,
    SURNAME VARCHAR(50) NOT NULL,
    AGE INT NOT NULL,
    TEAM VARCHAR(50) NOT NULL,
    POSITION VARCHAR(50) NOT NULL,
    PRICE NUMERIC
);

查看表结构:

$ \d+ football_player

通过以上步骤,我们完成了使用 Spring Boot 和 Vert.x 构建微服务及相关 API 文档配置和数据库设置的过程。这些技术为开发高效、灵活的微服务应用提供了强大的支持。

3. 微服务构建流程总结与对比
3.1 Spring Boot 与 Swagger 集成流程总结

以下是使用 Spring Boot 和 Swagger 集成实现 API 文档化的详细步骤:
1. 添加依赖 :在 Maven 的 pom.xml 文件中添加 springfox-swagger2 springfox-swagger-ui 依赖。

<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>
  1. 配置 Swagger :创建 SwaggerConfig 类,使用 @EnableSwagger2 注解启用 Swagger 支持,并配置 Docket bean。
@Configuration
@EnableSwagger2
public class SwaggerConfig extends WebMvcConfigurationSupport {
    @Bean
    public Docket api() {
        return new Docket(DocumentationType.SWAGGER_2).select()
           .apis(RequestHandlerSelectors.basePackage(
"com.packtpub.springboot.footballplayermicroservice.controller"))
           .paths(PathSelectors.any())
           .build();
    }
    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("swagger-ui.html")
            .addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**")
            .addResourceLocations("classpath:/META-INF/resources/webjars/");
    }
}
  1. 自定义 API 信息 :在 SwaggerConfig 类中添加 metaData 方法,设置 API 的元数据信息。
private ApiInfo metaData() {
    return new ApiInfoBuilder()
       .title("Spring Boot REST API")
       .description("\"Spring Boot REST API for Football Player Microservice\"")
       .version("1.0.0")
       .license("Apache License Version 2.0")
       .licenseUrl("https://www.apache.org/licenses/LICENSE-2.0\"")
       .contact(new Contact("Mauro Vocale",
            "https://github.com/Hands-on-MSA-JakartaEE",
            "mauro.vocale@gmail.com"))
       .build();
}
  1. 自定义控制器类 :使用 @ApiOperation @ApiResponses 注解描述控制器方法的操作和响应。
@ApiOperation(value = "View all available football players", response = Iterable.class)
@ApiResponses(value = {
    @ApiResponse(code = 200, message = "Successfully retrieved list"),
    @ApiResponse(code = 404, message = "The resource you were trying to reach is not found")
})
@RequestMapping(method = RequestMethod.GET, produces = "application/json")
public Iterable<FootballPlayer> findAll() {
    return service.findAll();
}
  1. 运行和测试 :使用 mvn spring-boot:run 命令启动应用程序,访问 http://localhost:8080/v2/api-docs 获取 JSON 格式的 API 文档,访问 http://localhost:8080/swagger-ui.html 获取可视化的 API 文档。
3.2 Vert.x 微服务构建流程总结

使用 Vert.x 构建微服务的步骤如下:
1. Maven 设置 :让 Maven POM 文件继承 vertx-stack-depchain BOM,管理 Vert.x 依赖。

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>io.vertx</groupId>
            <artifactId>vertx-stack-depchain</artifactId>
            <version>${vertx.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
  1. Gradle 设置 :在 Gradle 项目中添加 Vert.x 依赖和相关配置。
plugins {
    id 'java'
    id 'application'
    id 'com.github.johnrengelman.shadow' version '2.0.4'
}

ext {
    vertxVersion = '3.5.4'
    junitJupiterEngineVersion = '5.2.0'
}

repositories {
    mavenLocal()
    jcenter()
}

group = 'com.packtpub.vertx'
version = '1.0.0-SNAPSHOT'
sourceCompatibility = '1.8'
mainClassName = 'io.vertx.core.Launcher'
def mainVerticleName = 'com.packtpub.vertx.football-player-microservice.MainVerticle'
def watchForChange = 'src/**/*'
def doOnChange = './gradlew classes'

dependencies {
    implementation "io.vertx:vertx-core:$vertxVersion"
    implementation "io.vertx:vertx-config:$vertxVersion"
    ...
}

shadowJar {
    classifier = 'fat'
    manifest {
        attributes 'Main-Verticle': mainVerticleName
    }
    mergeServiceFiles {
        include 'META-INF/services/io.vertx.core.spi.VerticleFactory'
    }
}

run {
    args = ['run', mainVerticleName, "--redeploy=$watchForChange", "--launcher-class=$mainClassName", "--on-redeploy=$doOnChange"]
}
  1. 数据库安装和配置 :使用 Docker 启动 PostgreSQL 容器,创建数据库和表。
$ docker run --name postgres_vertx -e POSTGRES_PASSWORD=postgresPwd -e POSTGRES_DB=football_players_registry -d -p 5532:5432 postgres
$ docker ps -a
$ docker logs -f <容器 ID>
$ docker exec -it <容器 ID> bash
$ psql -U postgres
$ \l
$ \connect football_players_registry
$ CREATE TABLE FOOTBALL_PLAYER(
    ID SERIAL PRIMARY KEY NOT NULL,
    NAME VARCHAR(50) NOT NULL,
    SURNAME VARCHAR(50) NOT NULL,
    AGE INT NOT NULL,
    TEAM VARCHAR(50) NOT NULL,
    POSITION VARCHAR(50) NOT NULL,
    PRICE NUMERIC
);
$ \d+ football_player
3.3 Spring Boot 与 Vert.x 的对比
特性 Spring Boot Vert.x
开发模型 基于 Spring 框架,提供了丰富的注解和组件,开发相对简单,适合快速开发。 异步和非阻塞的开发模型,基于事件循环,更适合高并发场景。
文档生成 需要借助 SpringFox 等第三方框架生成 API 文档。 未提及内置的 API 文档生成机制,可根据需求集成第三方工具。
数据库集成 支持多种数据库,通过 Spring Data 等模块简化数据库操作。 可与多种数据库集成,需要手动编写数据库操作代码。
生态系统 拥有庞大的生态系统,有大量的第三方库和工具可供使用。 生态系统相对较小,但提供了灵活的开发方式。
4. 总结与展望

通过本文的介绍,我们了解了如何使用 Spring Boot 和 Swagger 集成实现 API 文档化,以及如何使用 Vert.x 构建微服务。Spring Boot 适合快速开发和构建简单的微服务,而 Vert.x 则更适合处理高并发和异步场景。

在实际开发中,可以根据项目的需求和场景选择合适的技术栈。如果项目对开发效率和生态系统有较高的要求,可以选择 Spring Boot;如果项目需要处理大量的并发请求和异步操作,可以选择 Vert.x。

未来,随着微服务架构的不断发展,我们可以期待更多的工具和框架的出现,为微服务的开发和管理提供更好的支持。同时,我们也需要不断学习和掌握新的技术,以适应不断变化的开发需求。

流程图:Spring Boot 与 Swagger 集成流程

graph LR
    A[添加依赖] --> B[配置 Swagger]
    B --> C[自定义 API 信息]
    C --> D[自定义控制器类]
    D --> E[运行和测试]

流程图:Vert.x 微服务构建流程

graph LR
    A[Maven 设置] --> B[Gradle 设置]
    B --> C[数据库安装和配置]
源码地址: https://pan.quark.cn/s/d1f41682e390 miyoubiAuto 米游社每日米游币自动化Python脚本(务必使用Python3) 8更新:更换cookie的获取地址 注意:禁止在B站、贴吧、或各大论坛大肆传播! 作者已退游,项目不维护了。 如果有能力的可以pr修复。 小引一波 推荐关注几个非常可爱有趣的女孩! 欢迎B站搜索: @嘉然今天吃什么 @向晚大魔王 @乃琳Queen @贝拉kira 第三方库 食用方法 下载源码 在Global.py中设置米游社Cookie 运行myb.py 本地第一次运行时会自动生产一个文件储存cookie,请勿删除 当前仅支持单个账号! 获取Cookie方法 浏览器无痕模式打开 http://user.mihoyo.com/ ,登录账号 按,打开,找到并点击 按刷新页面,按下图复制 Cookie: How to get mys cookie 当触发时,可尝试按关闭,然后再次刷新页面,最后复制 Cookie。 也可以使用另一种方法: 复制代码 浏览器无痕模式打开 http://user.mihoyo.com/ ,登录账号 按,打开,找到并点击 控制台粘贴代码并运行,获得类似的输出信息 部分即为所需复制的 Cookie,点击确定复制 部署方法--腾讯云函数版(推荐! ) 下载项目源码和压缩包 进入项目文件夹打开命令行执行以下命令 xxxxxxx为通过上面方式或取得米游社cookie 一定要用双引号包裹!! 例如: png 复制返回内容(包括括号) 例如: QQ截图20210505031552.png 登录腾讯云函数官网 选择函数服务-新建-自定义创建 函数名称随意-地区随意-运行环境Python3....
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值