Vert.x不仅仅是一个网络编程工具包,它还提供了一套完整的Web开发解决方案。通过vertx-web模块,开发者可以轻松构建功能丰富的Web应用和RESTful API服务。下面就来说说Vert.x在Web开发领域的强大功能,包括路由配置、请求处理、模板渲染以及实时WebSocket通信等高级特性。
添加Vert.x Web依赖
要使用Vert.x的Web功能,首先需要在项目中添加vertx-web依赖。直接在上一章的Maven项目中的pom.xml中添加:
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-web</artifactId>
</dependency>
<!-- 添加json支持依赖,否则在返回json结果时会报错 "... is not available without Jackson Databind on the classpath " -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
Vert.x Web构建在vertx-core之上,提供了更高层次的Web开发抽象,如路由、会话管理、模板支持等,同时保持了Vert.x的异步非阻塞特性。
路由与请求处理
Vert.x Web的核心是Router,它负责将HTTP请求路由到对应的处理器(Handler)。下面是一个基本的RESTful API示例:
import io.vertx.core.Future;
import io.vertx.core.Promise;
import io.vertx.core.VerticleBase;
import io.vertx.core.Vertx;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.RoutingContext;
import io.vertx.ext.web.handler.BodyHandler;
public class RestApiVerticle extends VerticleBase {
@Override
public Future<?> start() {
Router router = Router.router(vertx);
// 添加全局中间件
router.route().handler(this::loggingHandler);
// REST API路由
router.get("/api/greeting").handler(this::handleGreeting);
router.get("/api/users/:userId").handler(this::handleGetUser);
router.post("/api/users").handler(BodyHandler.create()).handler(this::handleCreateUser);
// 错误处理
router.errorHandler(404, this::handleNotFound);
return vertx.createHttpServer()
.requestHandler(router)
.listen(8080);
}
private void loggingHandler(RoutingContext ctx) {
System.out.println("Received request: " + ctx.request().method() + " " + ctx.request().path());
ctx.next();
}
private void handleGreeting(RoutingContext ctx) {
String name = ctx.queryParam("name").stream().findFirst().orElse("World");
ctx.json(new Greeting("Hello, " + name + "!"));
}
private void handleGetUser(RoutingContext ctx) {
String userId = ctx.pathParam("userId");
// 模拟异步数据库查询
getUserFromDatabase(userId)
.onSuccess(user -> ctx.json(user))
.onFailure(err -> ctx.fail(500, err));
}
private void handleCreateUser(RoutingContext ctx) {
User user = ctx.body().asPojo(User.class);
System.out.println("Received user: " + user);
// 处理用户创建...
ctx.response().setStatusCode(201).end();
}
private void handleNotFound(RoutingContext ctx) {
ctx.json(new JsonObject().put("error", "Resource not found"));
}
private Future<User> getUserFromDatabase(String userId) {
// 模拟异步数据库查询
Promise<User> promise = Promise.promise();
vertx.setTimer(100, id -> {
promise.complete(new User(userId, "forest", "cxl_forest@foxmail.com"));
});
return promise.future();
}
static class Greeting {
public final String message;
public Greeting(String message) { this.message = message; }
}
static class User {
public String id, name, email;
public User() {}
public User(String id, String name, String email) {
this.id = id; this.name = name; this.email = email;
}
@Override
public String toString() {
return "User{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", email='" + email + '\'' +
'}';
}
}
public static void main(String[] args) {
Vertx.vertx().deployVerticle(new RestApiVerticle()).onComplete(ar -> {
if (ar.succeeded())
System.out.println("Deployment id is: " + ar.result());
else
System.out.println("Deployment failed!");
});
}
}
这个示例展示了Vert.x Web的几个关键特性:
路由配置:支持路径参数、查询参数和正则表达式匹配
中间件支持:可以在请求处理前/后执行通用逻辑
JSON处理:内置JSON与Java对象转换支持
异步处理:可以与各种异步操作(如数据库查询)无缝集成
错误处理:统一处理各种错误情况
静态资源与模板渲染
Vert.x Web可以轻松地提供静态资源(HTML、CSS、JS文件)和渲染动态模板。以下是一个结合静态资源和模板引擎的示例:
首先添加模板引擎依赖(如Handlebars):
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-web-templ-handlebars</artifactId>
<version>5.0.1</version>
</dependency>
然后配置静态资源和模板:
Router router = Router.router(vertx);
// 静态资源处理
router.route("/assets/*").handler(StaticHandler.create("web/assets"));
// 模板引擎配置
HandlebarsTemplateEngine engine = HandlebarsTemplateEngine.create(vertx);
// 在resources目录下新建了一个 templates.hbs 模板
TemplateHandler handler = TemplateHandler.create(engine, "./templates", "text/html");
router.get("/dynamic").handler(ctx -> {
JsonObject data = new JsonObject()
.put("title", "Vert.x cxl Web Demo")
.put("message", "Hello cxl from Handlebars template!");
ctx.put("request_path", ctx.request().path());
ctx.put("data", data);
ctx.next();
});
// 动态路由
router.get("/dynamic").handler(handler);
Vert.x支持多种模板引擎,包括Handlebars、Thymeleaf、Freemarker等,开发者可以根据喜好选择。
WebSocket实时通信
Vert.x对WebSocket提供了出色的支持,使得构建实时应用(如聊天室、实时游戏等)变得非常简单。下面是一个简单的WebSocket聊天服务器示例:
import io.vertx.core.Future;
import io.vertx.core.VerticleBase;
import io.vertx.core.Vertx;
import io.vertx.core.http.HttpServer;
public class WebSocketVerticle extends VerticleBase {
public static void main(String[] args) {
Vertx.vertx().deployVerticle(new WebSocketVerticle());
}
@Override
public Future<?> start() {
HttpServer server = vertx.createHttpServer();
server.webSocketHandler(ws -> {
System.out.println("Client connected: " + ws.textHandlerID());
// 处理收到的消息
ws.textMessageHandler(message -> {
System.out.println("Received message: " + message);
// 广播给所有连接的客户端
vertx.eventBus().publish("chat.broadcast", message);
});
// 监听关闭事件
ws.closeHandler(v -> {
System.out.println("Client disconnected: " + ws.textHandlerID());
});
// 订阅广播消息
vertx.eventBus().consumer("chat.broadcast", msg -> {
if (!ws.isClosed()) {
ws.writeTextMessage((String) msg.body());
}
});
});
return server.listen(8080).onComplete(ar -> {
if (ar.succeeded()) {
System.out.println("WebSocket server started on port 8080");
} else {
ar.cause().printStackTrace();
}
});
}
}
这个示例展示了Vert.x处理WebSocket的核心能力:
通过
webSocketHandler
处理WebSocket连接使用
textMessageHandler
处理文本消息利用Vert.x的事件总线实现消息广播
处理连接关闭事件
身份验证与授权
Vert.x Web提供了灵活的身份验证和授权机制,支持多种认证方式(Basic、JWT、OAuth2等)。以下是一个使用JWT的示例:
// 初始化JWT认证
JWTAuthOptions authConfig = new JWTAuthOptions()
.setKeyStore(new KeyStoreOptions()
.setType("jceks")
.setPath("keystore.jceks")
.setPassword("secret"));
JWTAuth authProvider = JWTAuth.create(vertx, authConfig);
// 登录路由(颁发token)
router.post("/login").handler(ctx -> {
// 验证用户名密码(简化示例)
String username = ctx.request().getParam("username");
String password = ctx.request().getParam("password");
if ("admin".equals(username) && "password".equals(password)) {
String token = authProvider.generateToken(
new JsonObject().put("username", username),
new JWTOptions().setExpiresInSeconds(3600));
ctx.json(new JsonObject().put("token", token));
} else {
ctx.fail(401);
}
});
// 受保护的路由
router.route("/protected/*")
.handler(JWTAuthHandler.create(authProvider))
.handler(ctx -> {
// 获取认证信息
JsonObject principal = ctx.user().principal();
ctx.json(new JsonObject().put("message", "Hello, " + principal.getString("username")));
});
相关依赖
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-auth-jwt</artifactId>
<version>5.0.1</version>
</dependency>
跨域与API文档
构建现代Web应用通常需要考虑跨域资源共享(CORS)和API文档化。Vert.x Web提供了简单的CORS配置:
router.route().handler(
CorsHandler.create()
.allowedMethod(HttpMethod.GET)
.allowedMethod(HttpMethod.POST)
.allowedHeader("Content-Type")
);
对于API文档,Vert.x可以与Swagger/OpenAPI集成,需要添加vertx-openapi依赖,目前还是预览版本。
通过以上示例,我们可以看到Vert.x Web提供了构建现代Web应用所需的全套功能,从基本的路由到高级的实时通信和安全控制。Vert.x的异步特性在这些场景中表现得尤为出色,能够以少量资源支持高并发访问。