Vert.x初體驗

Vert .x

什麼是Vert .x

Vert.x框架基於事件和異步,依託於全異步Java服務器Netty,並擴展了不少其餘特性,以其輕量、高性能、支持多語言開發html

Hello world

建立一個簡單的項目https://start.vertx.io/ 無需添加任何依賴java

public class MainVerticle extends AbstractVerticle {

  @Override
  public void start(Promise<Void> startPromise) throws Exception {
    vertx.createHttpServer().requestHandler(req -> {
      req.response()
        .putHeader("content-type", "text/plain")
        .end("Hello from Vert.x!");
    }).listen(8888, http -> {
      if (http.succeeded()) {
        startPromise.complete();
        System.out.println("HTTP server started on port 8888");
      } else {
        startPromise.fail(http.cause());
      }
    });
 }

這個代碼第一眼看上去就很複雜,可是其實仔細分析一下,會感受其實很好理解web

大體就是Vert.x建立了一個Http的服務,並添加請求頭和響應的內容,監聽8888的端口,當服務建立成功時輸出HTTP server started on port 8888shell

Run

下面兩個命令很重要切記編程

打包
$ mvn package

運行
$ mvn exec:java
HTTP server started on port 8888
一月 28, 2021 11:14:37 下午 io.vertx.core.impl.launcher.commands.VertxIsolatedDeployer
信息: Succeeded in deploying verticle

訪問
$ curl http://127.0.0.1:8888/
Hello from Vert.x!

web項目

添加Vert.x Web 依賴json

<dependency>
    <groupId>io.vertx</groupId>
    <artifactId>vertx-web</artifactId>
</dependency>
public class MainVerticle extends AbstractVerticle {

  @Override
  public void start(Promise<Void> startPromise) throws Exception {
   // 建立一個路由
    Router router = Router.router(vertx);

    // 在每一個路徑和HTTP方法中爲全部傳入請求安裝處理程序
    router.route().handler(context -> {
      // 獲取請求的地址
      String address = context.request().connection().remoteAddress().toString();
      // Get the query parameter "name"
      MultiMap queryParams = context.queryParams();
      String name = queryParams.contains("name") ? queryParams.get("name") : "unknown";
      // Write a json response
      context.json(
        new JsonObject()
          .put("name", name)
          .put("address", address)
          .put("message", "Hello " + name + " connected from " + address)
      );
    });

    // Create the HTTP server
    vertx.createHttpServer()
      // Handle every request using the router(使用路由器處理每一個請求)
      .requestHandler(router)
      // Start listening
      .listen(8888)
      // Print the port
      .onSuccess(server ->
        System.out.println(
          "HTTP server started on port " + server.actualPort()
        )
      );
  }
 }
訪問
$ curl http://127.0.0.1:8888/
{"name":"unknown","address":"127.0.0.1:3402","message":"Hello unknown connected from 127.0.0.1:3402"}

$ curl http://127.0.0.1:8888?name=shaojie
{"name":"shaojie","address":"127.0.0.1:3605","message":"Hello shaojie connected from 127.0.0.1:3605"}

Vert.x-Web基本概念

Router是Vert.x-Web的核心概念之一。它是保持零個或多個的對象 Routes服務器

路由器接收一個HTTP請求,並找到該請求的第一個匹配路由,而後將請求傳遞到該路由。app

路由能夠具備與之關聯的處理程序,該處理程序而後接收請求。而後您能夠對請求進行處理,而後結束請求或將其傳遞給下一個匹配的處理程序。框架

建立一個簡單的路由:curl

HttpServer server = vertx.createHttpServer();
Router router = Router.router(vertx);
router.route().handler(ctx -> {
    HttpServerResponse response = ctx.response();
    response.putHeader("content-type", "text/plain");
    response.end("Hello World from Vert.x-Web!");
});

server.requestHandler(router).listen(8080);

處理請求並調用下一個處理程序

當Vert.x-Web決定將請求路由到匹配的路由時,它將在的實例中傳遞該路由的處理程序RoutingContext。路由能夠具備不一樣的處理程序,您可使用 handler

若是您未在處理程序中結束響應,則應進行調用,next以便其餘匹配的路由能夠處理請求(若是有)。

Route route = router.route("/some/path/");
route.handler(ctx -> {
    HttpServerResponse response = ctx.response();
    // 啓用分塊響應,由於咱們將在執行其餘處理程序時添加數據。僅一次且僅當多個處理程序進行輸出時才須要這樣作
    response.setChunked(true);
    response.write("route1\n");
    // 延遲5秒後呼叫下一條匹配路線
    ctx.vertx().setTimer(5000, tid -> ctx.next());
});

route.handler(ctx -> {
    HttpServerResponse response = ctx.response();
    response.write("route2\n");
    // 延遲5秒後呼叫下一條匹配路線
    ctx.vertx().setTimer(5000, tid -> ctx.next());
});

route.handler(ctx -> {
    HttpServerResponse response = ctx.response();
    response.write("route3");
    // Now end the response
    ctx.response().end();
});
$ curl http://127.0.0.1:8080/some/path/
route1
route2
route3

在上面的示例route1中,將響應寫入響應,而後在5秒鐘後將route2其寫入響應,而後在5秒鐘後將route3其寫入響應,並結束響應。(注意,全部這些都在沒有任何線程阻塞的狀況下發生。)

簡單的迴應

處理程序很是強大,由於它們容許您構建很是複雜的應用程序。對於簡單的響應,例如,直接從vert.x API返回異步響應,路由器包括處理程序的快捷方式,以確保:

  1. 響應以JSON返回。
  2. 若是處理處理程序時發生錯誤,則返回正確的錯誤。
  3. 若是序列化對JSON的響應時出錯,則返回正確的錯誤。
router
  .get("/some/path")
  // 此處理程序將確保將響應序列化爲json,並將內容類型設置爲「application/json」
  .respond(
    ctx -> Future.succeededFuture(new JsonObject().put("hello", "world")));

router
  .get("/some/path")
  // 這個處理程序將確保Pojo被序列化爲json 內容類型設置爲「application/json」
  .respond(
    ctx -> Future.succeededFuture(new Pojo()));
$ curl http://127.0.0.1:8080/some/path/
{"hello":"world"}

可是,若是提供的函數調用write或,您也能夠將其用於非JSON響應end

router
  .get("/some/path")
  .respond(
    ctx -> ctx
      .response()
        .putHeader("Content-Type", "text/plain")
        .end("hello world!"));

router
  .get("/some/path")
  // 在這種狀況下,處理程序確保鏈接已經結束
  .respond(
    ctx -> ctx
      .response()
        .setChunked(true)
        .write("Write some text..."));
$ curl http://127.0.0.1:8080/some/path/
hello world!

$ curl http://127.0.0.1:8080/some/path/
Write some text...

路由

按確切路徑路由

Route route = router.route().path("/some/path/");
route.handler(ctx -> {
    // 此處理程序將被如下請求路徑調用:
    // `/some/path/`
    // `/some/path//`
    
    // but not:
    // `/some/path` 路徑的結束斜槓使其嚴格
    // `/some/path/subdir`
    HttpServerResponse response = ctx.response();
    response.putHeader("content-type", "text/plain");
    response.end("/some/path/");
});

// 不以斜槓結束的路徑不嚴格 後面的斜槓是可選的 它們能夠任意匹配
Route route2 = router.route().path("/some/path");
route2.handler(ctx -> {
    // 此處理程序將被如下請求路徑調用:
    // `/some/path`
    // `/some/path/`
    // `/some/path//`
    
    // but not:
    // `/some/path/subdir`
    HttpServerResponse response = ctx.response();
    response.putHeader("content-type", "text/plain");
    response.end("/some/path");
});

經過以某些內容開頭的路徑進行路由

Route route = router.route().path("/some/path/*");
route.handler(ctx -> {
    // 此處理程序將被如下請求路徑調用:
    // `/some/path/`, e.g.
    // `/some/path/`
    // `/some/path/subdir`
    // `/some/path/subdir/blah.html`

    // but not:
    // `/some/path` 該路徑是嚴格的,由於它以斜槓結束
    // `/some/bath`
    HttpServerResponse response = ctx.response();
    response.putHeader("content-type", "text/plain");
    response.end("/some/path/*");
});

經過HTTP方法路由

Route route = router.route(HttpMethod.POST, "/some/path/");
route.handler(ctx -> {
    // 對於以/some/path/開頭的URI路徑的任何POST請求,都會調用此處理程序
    HttpServerResponse response = ctx.response();
    response.putHeader("content-type", "text/plain");
    response.end("method--/some/path/");
});

直接調用

getpostputdelete等以HTTP方法名稱命名

router
  .get("/some/path")
  .respond(
    ctx -> ctx
      .response()
        .putHeader("Content-Type", "text/plain")
        .end("hello world!"));

若是要指定一個路由將匹配多個HTTP方法,則能夠method 屢次調用:

Route route = router.route().method(HttpMethod.POST).method(HttpMethod.PUT);
route.handler(ctx -> {});

若是要建立須要自定義HTTP動詞的應用程序(例如WebDav服務器),則能夠指定自定義動詞

Route route = router.route()
  .method(HttpMethod.valueOf("MKCOL"))
  .handler(ctx -> {
    // 任何MKCOL請求都將調用此處理程序
  });

路線順序

參考 處理請求並調用下一個處理程序

若是要覆蓋路由的默認順序,可使用order,指定一個整數值。

路由在建立時被分配一個與添加到路由器的順序相對應的順序,第一個路由編號0,第二個路由編號1,依此類推。

經過指定路線的順序,您能夠覆蓋默認順序。訂單也能夠是負數,例如,若是您要確保在路線編號以前評估一條路線0

router
      .route("/some/path/")
      .order(1)
      .handler(ctx -> {
        HttpServerResponse response = ctx.response();
        response.write("route1\n");
        // Now call the next matching route
        ctx.next();
      });
    router
      .route("/some/path/")
      .order(0)
      .handler(ctx -> {
        HttpServerResponse response = ctx.response();
        // 啓用分塊響應,由於咱們將在執行其餘處理程序時添加數據。
        // 僅一次且僅當多個處理程序進行輸出時才須要這樣作。
        response.setChunked(true);
        response.write("route2\n");
        // Now call the next matching route
        ctx.next();
      });
    router
      .route("/some/path/")
      .order(2)
      .handler(ctx -> {
        HttpServerResponse response = ctx.response();
        response.write("route3");
        // Now end the response
        ctx.response().end();
      });
$ curl http://127.0.0.1:8080/some/path/
route2
route1
route3

關於路由得東西太多,後面單獨整理一期,單獨研究一下,剛開始學習的話,仍是先會用比較好

捕獲路徑參數

router
    .route(HttpMethod.POST, "/catalogue/products/:productType/:productID/")
    .handler(ctx -> {
        String productType = ctx.pathParam("productType");
        String productID = ctx.pathParam("productID");
        HttpServerResponse response = ctx.response();
        response.putHeader("content-type", "text/plain");
        response.end(productType + "--" + productID);
    });
$ curl -X POST http://127.0.0.1:8080/catalogue/products/String/123/
String--123

若是對編程感興趣,請關注個人我的博客 https://www.lzmvlog.top/

本文由博客一文多發平臺 OpenWrite 發佈!

相關文章
相關標籤/搜索