cxl
Published on 2025-07-15 / 6 Visits
0
0

Vert.x Web入门开发

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的几个关键特性:

  1. 路由配置​:支持路径参数、查询参数和正则表达式匹配

  2. 中间件支持​:可以在请求处理前/后执行通用逻辑

  3. JSON处理​:内置JSON与Java对象转换支持

  4. 异步处理​:可以与各种异步操作(如数据库查询)无缝集成

  5. 错误处理​:统一处理各种错误情况

静态资源与模板渲染

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的核心能力:

  1. 通过webSocketHandler处理WebSocket连接

  2. 使用textMessageHandler处理文本消息

  3. 利用Vert.x的事件总线实现消息广播

  4. 处理连接关闭事件

身份验证与授权

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的异步特性在这些场景中表现得尤为出色,能够以少量资源支持高并发访问。


Comment