目录
[2. Vert.x 与 Spring Boot 核心对比](#2. Vert.x 与 Spring Boot 核心对比)
[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)。
