Java入门级教程24——Vert.x的学习

目录

1.Vert.x的核心定位

[2. Vert.x 与 Spring Boot 核心对比](#2. Vert.x 与 Spring Boot 核心对比)

3.Vertx的路由处理机制

[3.1 实现内容](#3.1 实现内容)

[3.2 实现步骤](#3.2 实现步骤)

[3.2.1 创建Maven项目](#3.2.1 创建Maven项目)

[3.2.2 添加Maven依赖](#3.2.2 添加Maven依赖)

[3.2.3 具体实现](#3.2.3 具体实现)

[3.2.4 运行与测试](#3.2.4 运行与测试)

[3.3 为什么 Vert.x 不需要 Servlet 容器?](#3.3 为什么 Vert.x 不需要 Servlet 容器?)

[4.Vert.x 路由 + 数据库操作(实战进阶)](#4.Vert.x 路由 + 数据库操作(实战进阶))

[4.1 实现目标](#4.1 实现目标)

[4.2 前置准备:数据库初始化](#4.2 前置准备:数据库初始化)

[4.3 实现步骤](#4.3 实现步骤)

[4.3.1 添加数据库相关依赖](#4.3.1 添加数据库相关依赖)

[4.3.2 封装数据库连接工具类(JdbcUtils)](#4.3.2 封装数据库连接工具类(JdbcUtils))

[4.3.3 核心业务实现(Chapter2)](#4.3.3 核心业务实现(Chapter2))

[4.3.4 运行与测试](#4.3.4 运行与测试)

[5.Vert.x 整合第三方接口(DataDex 实战)](#5.Vert.x 整合第三方接口(DataDex 实战))

[5.1 实现目标](#5.1 实现目标)

[5.2 前置准备:DataDex 平台配置](#5.2 前置准备:DataDex 平台配置)

[5.2.1 新增应用,获取 APPID(对应参数 a1)](#5.2.1 新增应用,获取 APPID(对应参数 a1))

[5.2.2 创建接口](#5.2.2 创建接口)

[5.2.3 创建API Key(对应参数 a2)](#5.2.3 创建API Key(对应参数 a2))

[5.3 实现步骤](#5.3 实现步骤)

[5.3.1 添加 Hutool 依赖](#5.3.1 添加 Hutool 依赖)

[5.3.2 封装第三方接口调用工具类(CallDataDex)](#5.3.2 封装第三方接口调用工具类(CallDataDex))

[5.3.3 Vert.x 整合第三方接口(Chapter3)](#5.3.3 Vert.x 整合第三方接口(Chapter3))

[5.3.4 运行与测试](#5.3.4 运行与测试)

[6.Vert.x 整合 Thymeleaf 实战:快速搭建异步 Web 应用](#6.Vert.x 整合 Thymeleaf 实战:快速搭建异步 Web 应用)

[6.1 实现目标](#6.1 实现目标)

[6.2 实现步骤](#6.2 实现步骤)

[6.2.1 新建 Maven 项目 vertdemo2](#6.2.1 新建 Maven 项目 vertdemo2)

[6.2.2 添加依赖](#6.2.2 添加依赖)

[6.2.3 创建对应文件 chapter1/Chapter1 和 templates/index.html](#6.2.3 创建对应文件 chapter1/Chapter1 和 templates/index.html)

[6.2.4 核心业务代码(Chapter1.java)](#6.2.4 核心业务代码(Chapter1.java))

[6.2.5 Thymeleaf 模板文件(index.html)](#6.2.5 Thymeleaf 模板文件(index.html))

[6.2.6 运行与测试](#6.2.6 运行与测试)

[7.Vert.x 整合 Thymeleaf 实现表单提交与参数接收](#7.Vert.x 整合 Thymeleaf 实现表单提交与参数接收)

[7.1 实现目标](#7.1 实现目标)

[7.2 实现步骤](#7.2 实现步骤)

[7.2.1 创建对应文件 chapter2/Chapter2 和 templates/user.html](#7.2.1 创建对应文件 chapter2/Chapter2 和 templates/user.html)

[7.2.2 后端核心代码(Chapter2.java)](#7.2.2 后端核心代码(Chapter2.java))

[7.2.3 前端表单模板(user.html)](#7.2.3 前端表单模板(user.html))

[7.2.4 运行与测试](#7.2.4 运行与测试)


1.Vert.x的核心定位

Vert.x 是由 Eclipse 基金会维护的多语言、异步、非阻塞、事件驱动的应用开发工具包(Toolkit),而非传统意义上的框架(Framework)。它的设计目标是打造轻量级、高性能、可伸缩的分布式应用,特别适合构建微服务、实时应用(如聊天、游戏、IoT 数据处理)、API 网关等高性能场景。

核心特点总结

  • 非约束性:不像 Spring Boot 那样 "约束" 开发方式,而是提供 "工具箱",按需选用;
  • 多语言支持:基于 JVM,支持 Java、Kotlin、Scala、JavaScript、Python 等;
  • 高性能:异步非阻塞模型,单台服务器可处理数十万 TCP 连接,高吞吐、低延迟;
  • 轻量级:无重量级容器依赖,启动快、资源占用低。

2. Vert.x 与 Spring Boot 核心对比

特性 Vert.x Spring Boot
编程模型 异步非阻塞、事件驱动 同步阻塞(默认)、注解驱动
性能 极高(高吞吐、低延迟) 中等(依赖线程池)
资源占用 极低 较高
开发成本 中等(需理解异步编程思维) 低(约定优于配置,生态成熟)
生态 轻量、聚焦高性能场景 全栈、生态极其丰富
适用场景 高并发、实时性要求高的场景 企业级应用、快速开发的业务系统

3.Vertx的路由处理机制

3.1 实现内容

基于 Vert.x 框架创建一个异步非阻塞的 HTTP 服务器,并通过路由(Router)实现两个接口:

  • 访问 http://localhost:8090/index,返回字符串 Hello Vert.x(默认 UTF-8 编码);
  • 访问 http://localhost:8090/hello,返回中文字符串 欢迎学习Vertx异步非阻塞框架(指定 GB2312 编码);
  • 核心特性:无需 Tomcat 等 Servlet 容器,直接基于 JDK NIO 运行。

3.2 实现步骤

3.2.1 创建Maven项目

3.2.2 添加Maven依赖

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>

    <groupId>com.hy</groupId>
    <artifactId>vertdemo1</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>21</maven.compiler.source>
        <maven.compiler.target>21</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <!-- Vert.x 核心依赖:提供 Vertx、HttpServer、AbstractVerticle 等核心类 -->
        <dependency>
            <groupId>io.vertx</groupId>
            <artifactId>vertx-core</artifactId>
            <version>4.5.7</version>
        </dependency>

        <!-- Vert.x Web 依赖:提供 Router 路由核心功能 -->
        <dependency>
            <groupId>io.vertx</groupId>
            <artifactId>vertx-web</artifactId>
            <version>4.5.7</version>
        </dependency>
    </dependencies>

</project>

3.2.3 具体实现

java 复制代码
package com.hy.chapter1;

import io.vertx.core.AbstractVerticle;
import io.vertx.core.Vertx;
import io.vertx.core.http.HttpServer;
import io.vertx.core.http.HttpServerResponse;
import io.vertx.ext.web.Router;

public class Chapter1 extends AbstractVerticle {

    public static void main(String[] args) {
        // 1. 创建Vert.x核心实例
        // 2. deployVerticle():异步部署当前自定义的Verticle,部署成功后自动调用start()方法
        Vertx.vertx().deployVerticle(new Chapter1());
    }

    public void start() throws Exception {

        // 1. 创建HTTP服务器实例(基于Java NIO实现,异步非阻塞)
        HttpServer server = vertx.createHttpServer();

        // 2. 创建路由对象(Router)
        Router router = Router.router(vertx);

        // 3. 定义第一个路由规则
        router.route("/index").handler(handler -> {
            // 获取请求上下文中的响应对象
            HttpServerResponse response = handler.response();

            // end():结束响应并向客户端返回字符串(异步操作,调用后线程立即释放,不阻塞)
            response.end("Hello Vert.x");
        });

        // 4. 定义第二个路由规则
        router.route("/hello").handler(handler -> {
            // 获取响应对象
            HttpServerResponse response = handler.response();

            // end(字符串, 编码):指定编码返回中文字符串,避免客户端解析乱码
            // 注意:Vert.x默认编码为UTF-8,此处为演示指定GB2312
            response.end("欢迎学习Vertx异步非阻塞框架", "GB2312");
        });

        // 5. 将路由对象绑定到HTTP服务器
        server.requestHandler(router);

        // 6. 启动HTTP服务器,监听8090端口(异步操作,调用后立即返回,不阻塞)
        server.listen(8090, result -> {
            if (result.succeeded()) {
                System.out.println("服务器启动成功,端口:8090");
            } else {
                System.err.println("服务器启动失败:" + result.cause());
            }
        });
    }
}

3.2.4 运行与测试

① 运行 main 方法,控制台输出 服务器启动成功,端口:8090 即表示启动成功

服务器启动成功,端口:8090

② 浏览器访问 http://localhost:8090/index,显示 Hello Vert.x

③ 浏览器访问 http://localhost:8090/hello,显示中文内容(无乱码)

3.3 为什么 Vert.x 不需要 Servlet 容器?

  • Servlet 容器的作用:Tomcat 等容器实现了 Servlet 规范,负责 HTTP 协议解析、线程管理、请求分发等底层工作,传统 Spring MVC 必须依赖它运行;
  • Vert.x 的实现逻辑 :不遵循 Servlet 规范,直接基于 JDK NIO 实现轻量级 HTTP 服务器,自己处理 HTTP 解析、线程管理等底层工作,因此无需外部容器,启动更轻、性能更高。

4.Vert.x 路由 + 数据库操作(实战进阶)

4.1 实现目标

基于 Vert.x JDBC 客户端,实现异步查询 MySQL 数据库,并通过 /query 接口返回查询结果。

4.2 前置准备:数据库初始化

sql 复制代码
-- 创建表 --
CREATE TABLE t_stus (
    sid INT PRIMARY KEY AUTO_INCREMENT,
    sname VARCHAR(20) NOT NULL,
    saddress VARCHAR(200)
);

-- 删除数据库表,用于先前如果创建好的表 --
DROP TABLE t_stus

-- 插入数据 --
INSERT INTO t_stus(sname,saddress) VALUES("张三","南京");
INSERT INTO t_stus(sname,saddress) VALUES("李四","盐城");
INSERT INTO t_stus(sname,saddress) VALUES("王五","苏州");

INSERT INTO t_stus(sname,saddress) VALUES("张六","南京");
INSERT INTO t_stus(sname,saddress) VALUES("王七","盐城");
INSERT INTO t_stus(sname,saddress) VALUES("李八","苏州");

-- 查询表 --
SELECT * FROM t_stus

实现效果:

4.3 实现步骤

4.3.1 添加数据库相关依赖

在原有 pom.xml 基础上补充以下依赖:

XML 复制代码
        <!-- Vert.x JDBC 客户端(必需):提供 JDBCClient、ResultSet 等数据库操作类 -->
        <dependency>
            <groupId>io.vertx</groupId>
            <artifactId>vertx-jdbc-client</artifactId>
            <version>4.0.3</version>
        </dependency>

        <!-- MySQL JDBC 驱动(必需):提供 MySQL 数据库连接驱动类 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.23</version>
        </dependency>

4.3.2 封装数据库连接工具类(JdbcUtils)

java 复制代码
package com.hy.chapter2;

import io.vertx.core.Vertx;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.jdbc.JDBCClient;

public class JdbcUtils {

    // 成员变量:Vert.x的JDBC客户端实例(核心操作类,用于执行SQL语句)
    // JDBCClient是Vert.x封装的异步JDBC客户端,替代传统的JDBC Connection
    private JDBCClient jdbcClient;

    public JdbcUtils(Vertx vertx) {
        // 1. 创建JsonObject对象,用于封装数据库连接配置(键值对形式,类似Map)
        JsonObject dbconfig = new JsonObject();

        // 2. 配置MySQL数据库连接URL
        // 格式:jdbc:mysql://主机地址:端口/数据库名
        // 此处连接的是本地(127.0.0.1)3306端口的mysql2026数据库
        dbconfig.put("url", "jdbc:mysql://127.0.0.1:3306/mysql2026");

        // 3. 配置MySQL驱动类全限定名
        dbconfig.put("driver_class", "com.mysql.cj.jdbc.Driver");

        // 4. 配置数据库登录用户名(本地MySQL的root用户)
        dbconfig.put("user", "root");

        // 5. 配置数据库登录密码
        dbconfig.put("password", "yourpassword");

        // 6. 创建共享的JDBC客户端实例(核心步骤)
        // createShared(vertx实例, 配置项):创建共享连接池的客户端,避免重复创建连接池
        this.jdbcClient = JDBCClient.createShared(vertx, dbconfig);

        // 打印客户端实例(调试用,生产环境建议删除,避免日志冗余)
        System.out.println(this.jdbcClient);
    }

    public JDBCClient getJdbcClient() {
        return this.jdbcClient;
    }

}

4.3.3 核心业务实现(Chapter2)

java 复制代码
package com.hy.chapter2;

import io.vertx.core.AbstractVerticle;
import io.vertx.core.Vertx;
import io.vertx.core.http.HttpServer;
import io.vertx.core.http.HttpServerResponse;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.jdbc.JDBCClient;
import io.vertx.ext.sql.ResultSet;
import io.vertx.ext.web.Router;

import java.util.List;


public class Chapter2 extends AbstractVerticle {

    public static void main(String[] args) {
        // 创建Vert.x实例(包含事件循环、线程池等核心能力)
        // deployVerticle():异步部署自定义Verticle,启动核心业务逻辑
        Vertx.vertx().deployVerticle(new Chapter2());
    }

    @Override
    public void start() throws Exception {

        // 1. 创建HTTP服务器实例(基于Java NIO实现,异步非阻塞)
        HttpServer server = vertx.createHttpServer();

        // 2. 创建路由对象(请求分发器):匹配不同URL路径的请求
        Router router = Router.router(vertx);

        // 3. 定义/query路由规则:匹配所有访问/query路径的请求(GET/POST等)
        router.route("/query").handler(handler -> {

            // 3.1 初始化JDBC工具类,创建MySQL数据库连接客户端
            // 传入vertx实例:保证JDBC客户端与Vert.x事件循环绑定,异步处理
            JdbcUtils jdbcUtils = new JdbcUtils(vertx);
            // 获取Vert.x的JDBC客户端实例(基于配置的数据库连接信息创建)
            JDBCClient jdbcClient = jdbcUtils.getJdbcClient();
            // 打印客户端实例(调试用,生产环境可删除)
            System.out.println("jdbcClient-->" + jdbcClient);

            // 3.2 定义要执行的SQL语句:查询t_stus表所有数据
            String sql = "select * from t_stus";

            // 3.3 异步执行带参数的SQL查询(此处参数为null,因为SQL无占位符)
            // queryWithParams(SQL语句, 参数列表, 回调函数):非阻塞执行,结果通过回调返回
            jdbcClient.queryWithParams(sql, null, queryresult -> {

                // 回调函数:SQL查询完成后执行(成功/失败都会进入)
                if (queryresult.succeeded()) {
                    // 查询成功:获取结果集对象
                    ResultSet resultSet = queryresult.result();
                    // 将结果集转换为JsonObject列表(每行数据封装为一个JsonObject)
                    List<JsonObject> lists = resultSet.getRows();

                    // 获取HTTP响应对象,准备返回数据给客户端
                    HttpServerResponse response = handler.response();
                    // 结束响应并返回查询结果,指定GB2312编码(避免中文乱码)
                    response.end(lists.toString(), "GB2312");
                }
            });
        });

        // 4. 将路由对象绑定到HTTP服务器:所有请求交由Router分发处理
        server.requestHandler(router);

        // 5. 启动HTTP服务器,监听8090端口(异步操作)
        server.listen(8090, result -> {
            if (result.succeeded()) {
                // 启动成功:打印提示日志
                System.out.println("服务器启动成功,端口:8090");
            } else {
                // 启动失败:打印异常原因
                System.err.println("服务器启动失败:" + result.cause());
            }
        });

    }
}

4.3.4 运行与测试

① 运行 main 方法,控制台输出启动成功日志

②浏览器访问 http://localhost:8090/query,返回 JSON 格式的学生数据(无中文乱码)

5.Vert.x 整合第三方接口(DataDex 实战)

5.1 实现目标

基于 Hutool 工具包调用 DataDex 语音数据接口,并通过 Vert.x 路由将接口结果返回给客户端。

5.2 前置准备:DataDex 平台配置

5.2.1 新增应用,获取 APPID(对应参数 a1

应用名称:speekdemo1

应用描述:语音朗读的实现

5.2.2 创建接口

{

"text": "请选择您需要朗读的文字,开始为您朗读。",

"voice": "zh-CN-YunxiNeural",

"rate": 0.9,

"volume": 90,

"format": "audio-16khz-32kbitrate-mono-mp3"

}

5.2.3 创建API Key(对应参数 a2

5.3 实现步骤

5.3.1 添加 Hutool 依赖

XML 复制代码
        <!-- Hutool 全能工具包(必需):提供 HTTP请求、JSON处理、日期、加密等一站式工具类 -->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.38</version>
        </dependency>

5.3.2 封装第三方接口调用工具类(CallDataDex)

java 复制代码
package com.hy.chapter3;

import cn.hutool.http.Header;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONObject;

public class CallDataDex {

    public String callData() {
        // 1. 定义接口请求地址(DataDex平台的语音数据接口)
        String url = "https://open.datadex.com.cn/dexserver/dex-api/v1/speekdata";
        // 初始化响应结果字符串(空字符串作为默认值)
        String result = "";

        // 2. 构建JSON格式的请求体参数
        JSONObject obj = new JSONObject();
        // 添加接口认证参数a1(为APPID)
        obj.putOnce("a1", "APP-V9biPjZ-4240864829726737499-271");
        // 添加接口认证参数a2(为API Key)
        obj.putOnce("a2", "KEY035V9blCEn9hMAht3dw37AxBVoiPCVuU6JPzg9pC0t6273");

        // 3. 构建并发送POST请求
        HttpResponse response = HttpRequest.post(url) // 指定请求方式为POST,传入接口地址
                // 设置请求头:Content-Type为application/json(告知服务端请求体是JSON格式)
                .header(Header.CONTENT_TYPE, "application/json")
                // 设置请求体:将JSONObject转为字符串传入
                .body(obj.toString())
                // 执行请求(发送HTTP请求并获取响应)
                .execute();

        // 4. 获取响应体的字符串内容(接口返回的核心数据)
        result = response.body();

        // 返回接口响应结果
        return result;
    }

    // 测试方法:单独验证接口调用
    public static void main(String[] args) {
        // 创建当前类的实例
        CallDataDex cdd = new CallDataDex();
        // 调用callData方法,获取接口返回结果
        String result = cdd.callData();
        // 打印接口返回的字符串结果
        System.out.println(result);
    }

}

运行结果:

{"msg":"操作成功","duration":52,"code":200,"data":{"voice":"zh-CN-YunxiNeural","volume":90,"rate":0.9,"format":"audio-16khz-32kbitrate-mono-mp3","text":"请选择您需要朗读的文字,开始为您朗读。"}}

5.3.3 Vert.x 整合第三方接口(Chapter3)

java 复制代码
package com.hy.chapter3;

import io.vertx.core.AbstractVerticle;
import io.vertx.core.Vertx;
import io.vertx.core.http.HttpServer;
import io.vertx.core.http.HttpServerResponse;
import io.vertx.ext.web.Router;

public class Chapter3 extends AbstractVerticle {

    public static void main(String[] args) {
        Vertx.vertx().deployVerticle(new Chapter3());
    }

    public void start() throws Exception {

        //启动Vert.x的HttpServer服务
        HttpServer server = vertx.createHttpServer();

        //创建路由对象
        Router router = Router.router(vertx);

        //监听客户端请求
        router.route("/index").handler(handler -> {

            HttpServerResponse response = handler.response();
            response.end("你好,这个是非阻塞异步框架", "GB2312");
        });

        router.route("/hello").handler(handler -> {

            CallDataDex cdd = new CallDataDex();

            String result = cdd.callData();
            HttpServerResponse response = handler.response();

            response.end(result, "GB2312");
        });

        //把请求交给路由来处理,在server上去注册
        server.requestHandler(router);
        server.listen(8090, result -> {
            if (result.succeeded()) {
                // 启动成功:打印提示日志
                System.out.println("服务器启动成功,端口:8090");
            } else {
                // 启动失败:打印异常原因
                System.err.println("服务器启动失败:" + result.cause());
            }
        });
    }
}

5.3.4 运行与测试

① 运行 Chapter3 的 main 方法,启动服务

② 访问 http://localhost:8090/hello,返回 DataDex 接口的结果(或错误提示)

6.Vert.x 整合 Thymeleaf 实战:快速搭建异步 Web 应用

6.1 实现目标

基于 Vert.x 4.x 整合 Thymeleaf 模板引擎,搭建轻量级异步 Web 应用,实现动态数据渲染,解决模板渲染、路径配置、中文乱码等常见问题,依托 Vert.x 异步非阻塞特性实现高性能请求处理。

6.2 实现步骤

6.2.1 新建 Maven 项目 vertdemo2

6.2.2 添加依赖

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>

    <groupId>com.hy</groupId>
    <artifactId>vertdemo2</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>21</maven.compiler.source>
        <maven.compiler.target>21</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <!-- Vert.x 核心依赖 -->
        <dependency>
            <groupId>io.vertx</groupId>
            <artifactId>vertx-core</artifactId>
            <version>4.5.1</version>
        </dependency>
        <!-- Vert.x Thymeleaf 模板引擎集成依赖(核心) -->
        <dependency>
            <groupId>io.vertx</groupId>
            <artifactId>vertx-web-templ-thymeleaf</artifactId>
            <version>4.5.1</version>
        </dependency>
        <!-- Thymeleaf 核心依赖(需配合 vertx 集成包) -->
        <dependency>
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf</artifactId>
            <version>3.1.2.RELEASE</version>
        </dependency>
        <!-- Vert.x Web 核心(仅保留路由必需的最小依赖,避免冲突) -->
        <dependency>
            <groupId>io.vertx</groupId>
            <artifactId>vertx-web</artifactId>
            <version>4.5.1</version>
        </dependency>
    </dependencies>

</project>

6.2.3 创建对应文件 chapter1/Chapter1 和 templates/index.html

6.2.4 核心业务代码(Chapter1.java)

java 复制代码
package com.hy.chapter1;

import io.vertx.core.Vertx;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.http.HttpServer;
import io.vertx.core.http.HttpServerResponse;
import io.vertx.core.AsyncResult;
import io.vertx.core.Handler;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.RoutingContext;
import io.vertx.ext.web.templ.thymeleaf.ThymeleafTemplateEngine;

public class Chapter1 {
    public static void main(String[] args) {
        // 1. 创建Vert.x实例
        Vertx vertx = Vertx.vertx();
        // 2. 创建HTTP服务器
        HttpServer server = vertx.createHttpServer();
        // 3. 创建路由
        Router router = Router.router(vertx);

        // 4. 创建Thymeleaf模板引擎(适配4.x版本,正确初始化)
        ThymeleafTemplateEngine templateEngine = ThymeleafTemplateEngine.create(vertx);

        // 5. 配置/load路由
        router.route("/load").handler(new Handler<RoutingContext>() {
            @Override
            public void handle(RoutingContext routingContext) {
                // 定义模板变量
                String[] dataList = new String[]{"Java", "Vert.x", "Thymeleaf", "HTML"};

                // 构建模板渲染所需的上下文(关键修复:用JsonObject存储变量,而非直接传RoutingContext)
                JsonObject templateData = new JsonObject();
                templateData.put("message", "hello  th模板语言");
                templateData.put("nameLists", dataList);

                // 6. 渲染模板(传递正确的上下文和模板路径)
                templateEngine.render(
                        templateData,  // 修复:传递存储变量的JsonObject,而非强制转换RoutingContext
                        "templates/index.html",  // 修复:模板路径去掉classpath:(Vert.x Thymeleaf适配层会自动处理)
                        new Handler<AsyncResult<Buffer>>() {
                            @Override
                            public void handle(AsyncResult<Buffer> res) {
                                HttpServerResponse response = routingContext.response();
                                if (res.succeeded()) {
                                    // 设置响应头,确保中文不乱码
                                    response.putHeader("Content-Type", "text/html;charset=UTF-8")
                                            .end(res.result());
                                } else {
                                    System.err.println("模板渲染失败:" + res.cause().getMessage());
                                    // 输出完整异常栈,方便排查
                                    res.cause().printStackTrace();
                                    // 返回500错误
                                    response.setStatusCode(500).end("模板渲染失败:" + res.cause().getMessage());
                                }
                            }
                        }
                );
            }
        });

        // 7. 启动服务器
        server.requestHandler(router).listen(8900, result -> {
            if (result.succeeded()) {
                System.out.println("服务器启动成功,访问:http://localhost:8900/load");
            } else {
                System.err.println("服务器启动失败:" + result.cause().getMessage());
                result.cause().printStackTrace();
            }
        });
    }
}

6.2.5 Thymeleaf 模板文件(index.html)

html 复制代码
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Vert.x + Thymeleaf</title>
</head>
<body>
<h1 th:text="${message}"></h1>
<ul>
    <li th:each="name : ${nameLists}" th:text="${name}"></li>
</ul>
</body>
</html>

6.2.6 运行与测试

① 直接运行 Chapter1.java 的 main 方法,控制台输出以下日志表示服务器启动成功

② 打开浏览器访问 http://localhost:8900/load,页面将显示以下内容(动态渲染的字符串和列表)

7.Vert.x 整合 Thymeleaf 实现表单提交与参数接收

7.1 实现目标

基于 Vert.x + Thymeleaf,完成「前端表单页面渲染(GET 请求)+ 后端表单参数接收与返回(POST 请求)」的完整流程。

7.2 实现步骤

7.2.1 创建对应文件 chapter2/Chapter2 和 templates/user.html

7.2.2 后端核心代码(Chapter2.java)

java 复制代码
package com.hy.chapter2;

// Vert.x核心依赖:提供异步运行时、HTTP服务器、缓冲区等基础能力
import io.vertx.core.Vertx;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.http.HttpServer;
import io.vertx.core.http.HttpServerResponse;
import io.vertx.core.AsyncResult;
import io.vertx.core.Handler;
import io.vertx.core.json.JsonObject;
// Vert.x Web核心:路由、请求上下文、表单体处理
import io.vertx.ext.web.Router;
import io.vertx.ext.web.RoutingContext;
import io.vertx.ext.web.handler.BodyHandler;
// Vert.x整合Thymeleaf模板引擎
import io.vertx.ext.web.templ.thymeleaf.ThymeleafTemplateEngine;

public class Chapter2 {
    public static void main(String[] args) {
        // 1. 创建Vert.x核心实例:管理异步事件循环、网络连接等核心资源
        Vertx vertx = Vertx.vertx();
        // 2. 创建非阻塞HTTP服务器:支持高并发,不占用额外线程处理请求
        HttpServer server = vertx.createHttpServer();
        // 3. 创建路由对象:请求分发核心,匹配URL路径和HTTP方法
        Router router = Router.router(vertx);

        // 4. 初始化Thymeleaf模板引擎:Vert.x 4.x默认适配,自动从classpath/templates加载模板
        ThymeleafTemplateEngine templateEngine = ThymeleafTemplateEngine.create(vertx);
        System.out.println(templateEngine);

        // 5. 全局绑定BodyHandler:关键!处理POST请求的表单体/JSON体
        //    必须配置,否则无法通过getParam()获取POST提交的表单参数
        router.route().handler(BodyHandler.create());

        // 6. 配置GET /loadh5路由:渲染用户信息提交表单页面
        router.get("/loadh5").handler(new Handler<RoutingContext>() {
            @Override
            public void handle(RoutingContext routingContext) {
                // 构建模板渲染上下文:传递动态数据到Thymeleaf模板
                JsonObject templateData = new JsonObject();
                // 向模板传递页面标题变量,供Thymeleaf的th:text渲染
                templateData.put("title", "用户信息提交页面");

                // 异步渲染Thymeleaf模板
                templateEngine.render(
                        templateData,  // 模板变量上下文(键值对)
                        "templates/user.html",  // 模板路径:对应src/main/resources/templates/user.html
                        // 模板渲染结果处理器(异步回调)
                        new Handler<AsyncResult<Buffer>>() {
                            @Override
                            public void handle(AsyncResult<Buffer> res) {
                                HttpServerResponse response = routingContext.response();
                                if (res.succeeded()) {
                                    // 渲染成功:设置响应头(UTF-8解决中文乱码),返回渲染后的HTML
                                    response.putHeader("Content-Type", "text/html;charset=UTF-8")
                                            .end(res.result());
                                } else {
                                    // 渲染失败:打印异常栈+返回500错误,便于排查(模板不存在/语法错误等)
                                    System.err.println("模板渲染失败:" + res.cause().getMessage());
                                    res.cause().printStackTrace();
                                    response.setStatusCode(500)
                                            .end("页面加载失败:" + res.cause().getMessage());
                                }
                            }
                        }
                );
            }
        });

        // 7. 配置POST /loadusers路由:接收表单提交的用户信息参数
        router.post("/loadusers").handler(new Handler<RoutingContext>() {
            @Override
            public void handle(RoutingContext routingContext) {
                // 获取表单参数:通过getParam()获取,需提前配置BodyHandler
                // 增加空值判断:避免参数未提交时出现NullPointerException
                String name = routingContext.request().getParam("name");
                System.out.println("获取的name参数值为:" + (name == null ? "空" : name));

                String sex = routingContext.request().getParam("sex");
                System.out.println("获取的sex参数值为:" + (sex == null ? "空" : sex));

                String age = routingContext.request().getParam("age");
                System.out.println("获取的age参数值为:" + (age == null ? "空" : age));

                // 拼接响应信息,返回给客户端
                String responseMsg = "获取的值为:" + name + "," + sex + "," + age;
                HttpServerResponse response = routingContext.response();
                // 设置响应头:指定文本类型+UTF-8编码,避免中文乱码(核心!)
                response.putHeader("Content-Type", "text/plain;charset=UTF-8")
                        .end(responseMsg); // 结束响应并返回结果
            }
        });

        // 8. 启动HTTP服务器,监听8900端口(异步操作)
        server.requestHandler(router).listen(8900, result -> {
            if (result.succeeded()) {
                // 启动成功:提示访问地址
                System.out.println("服务器启动成功,访问:http://localhost:8900/loadh5");
            } else {
                // 启动失败:打印异常(如端口被占用、权限不足)
                System.err.println("服务器启动失败:" + result.cause().getMessage());
                result.cause().printStackTrace();
            }
        });
    }
}

7.2.3 前端表单模板(user.html)

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form method="post" action="/loadusers">
    姓名:<input type="text"  name="name"/>
    <br>
    <label>性别:</label>
    <input  type="checkbox"  name="sex"  value="M">男</input>
    <input  type="checkbox"  name="sex"  value="f">女</input>
    <br>
    <label>年龄:</label>
    <select name="age">
        <option  value="20">20岁</option>
        <option  value="21">21岁</option>
        <option  value="22">22岁</option>
        <option  value="23">23岁</option>
    </select>
    <br>
    <input  type="submit"  value="提交"/>
</form>
</body>
</html>

7.2.4 运行与测试

① 启动服务 :运行 Chapter2 的 main 方法,控制台输出 服务器启动成功,访问:http://localhost:8900/loadh5;

② 访问表单页面 :浏览器打开 http://localhost:8900/loadh5,看到用户信息提交表单;

③ 提交表单 :填写姓名、选择性别 / 年龄,点击 "提交";

④ 查看结果

后端控制台打印获取的参数值;

前端页面显示拼接后的参数结果(如:获取的值为:张三,M,21)。

相关推荐
轩情吖3 小时前
Qt的窗口
开发语言·c++·qt·窗口·工具栏·桌面级开发
Mr_star_galaxy3 小时前
【JAVA】经典图书管理系统的实现
java
hcnaisd23 小时前
深入理解C++内存模型
开发语言·c++·算法
凯子坚持 c3 小时前
Qt常用控件指南(8)
开发语言·数据库·qt
昊坤说不出的梦3 小时前
【实战】监控上下文切换及其优化方案
java·后端
冠希陈、3 小时前
PHP 判断是否是移动端,更新鸿蒙系统
android·开发语言·php
自可乐4 小时前
n8n全面学习教程:从入门到精通的自动化工作流引擎实践指南
运维·人工智能·学习·自动化
HDO清风4 小时前
CASIA-HWDB2.x 数据集DGRL文件解析(python)
开发语言·人工智能·pytorch·python·目标检测·计算机视觉·restful
2201_756989094 小时前
C++中的事件驱动编程
开发语言·c++·算法