目录

1.Vert.x的核心定位

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

3.Vertx的路由处理机制

3.1 实现内容

3.2 实现步骤

3.2.1 创建Maven项目

3.2.2 添加Maven依赖

3.2.3 具体实现

3.2.4 运行与测试

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

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

4.1 实现目标

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

4.3 实现步骤

4.3.1 添加数据库相关依赖

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

4.3.3 核心业务实现(Chapter2)

4.3.4 运行与测试

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

5.1 实现目标

5.2 前置准备:DataDex 平台配置

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

5.2.2 创建接口

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

5.3 实现步骤

5.3.1 添加 Hutool 依赖

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

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

5.3.4 运行与测试

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

6.1 实现目标

6.2 实现步骤

6.2.1 新建 Maven 项目 vertdemo2

6.2.2 添加依赖

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

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

6.2.5 Thymeleaf 模板文件(index.html)

6.2.6 运行与测试

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

7.1 实现目标

7.2 实现步骤

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

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

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

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.xSpring 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 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 具体实现

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 前置准备:数据库初始化

-- 创建表 --
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 基础上补充以下依赖:

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

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)

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

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

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

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)

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

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)

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

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)

<!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)。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐