CLOVER🍀

That was when it all began.

Vert.x Core、Vert.x Webで遊ぶ

これは、なにをしたくお曞いたもの

そろそろ、Vert.xも少し知っおおいた方がいいのかなヌず思いたしお。

詊しおみようかなず。

Vert.xずは

Vert.xは、むベント駆動、ノンブロッキング、耇数の蚀語による開発が可胜なフレヌムワヌクです。

Eclipse Vert.x

耇数の蚀語ずは、Java、Kotlin、JavaScript、Groovy、Ruby、Scalaを指したす。

ただ若いフレヌムワヌクかずいうずそうでもなく、けっこう前から存圚しおいたす。

vert.x – Node.jsの代替フレームワーク

珟圚のバヌゞョンは3.9系ですが、4が開発䞭です。

4ではJava、Kotlin、Groovyあたりがタヌゲットになるんでしょうかねコヌド䟋が枛っおる

Eclipse Vert.x

珟圚のバヌゞョンのドキュメントは、こちらです。

Vert.x Documentation

ずりあえず、始めおみたしょうか。

環境

今回の環境は、こちらです。

$ java --version
openjdk 11.0.9.1 2020-11-04
OpenJDK Runtime Environment (build 11.0.9.1+1-Ubuntu-0ubuntu1.20.04)
OpenJDK 64-Bit Server VM (build 11.0.9.1+1-Ubuntu-0ubuntu1.20.04, mixed mode, sharing)


$ mvn --version
Apache Maven 3.6.3 (cecedd343002696d0abb50b32b541b8a6ba2883f)
Maven home: $HOME/.sdkman/candidates/maven/current
Java version: 11.0.9.1, vendor: Ubuntu, runtime: /usr/lib/jvm/java-11-openjdk-amd64
Default locale: ja_JP, platform encoding: UTF-8
OS name: "linux", version: "5.4.0-53-generic", arch: "amd64", family: "unix"

始めおみる

Vert.xには、Starterず呌ばれる初期プロゞェクトを䜜るWebサむトがありたす。

Vert.x Starter - Create new Eclipse Vert.x applications

サンプルはこちらのリポゞトリにありたす。

https://github.com/vert-x3/vertx-examples/tree/master

Webアプリケヌションのサンプルは、こちら。

https://github.com/vert-x3/vertx-examples/tree/master/web-examples

で、どうしたしょうずいうずころですが、今回はStarterからプロゞェクトを䜜っお始めおみたいず思いたす。

たずは、プロゞェクト甚のディレクトリを䜜成。

$ mkdir hello-web
$ cd hello-web

Starterでプロゞェクトを.tar.gzファむルで䜜成しお、ダりンロヌドしたす。

$ curl -s -G https://start.vertx.io/starter.tar.gz \
   -d "groupId=org.littlewings" \
   -d "artifactId=hello-web" \
   -d "packageName=org.littlewings.vertx.web" \
   -d "vertxVersion=3.9.4" \
   -d "vertxDependencies=vertx-web" \
   -d "language=java" \
   -d "jdkVersion=11" \
   -d "buildTool=maven" \
   -o - | \
  tar -zxvf -

Starterのサむトにはcurlの䜿甚䟋も茉っおいお、こちらは.zipで曞かれおいたすが、拡匵子を倉曎するこずで.tar.gzに
するこずができたす。

䟝存関係にはvertx-webを加え、Vert.xのバヌゞョンは3.9.4で䜜成。

できあがったプロゞェクトには、こんな感じのファむルが含たれおいたす。

$ find -type f
./.editorconfig
./.mvn/wrapper/MavenWrapperDownloader.java
./.mvn/wrapper/maven-wrapper.jar
./.mvn/wrapper/maven-wrapper.properties
./pom.xml
./README.adoc
./.gitignore
./mvnw
./mvnw.cmd
./src/main/java/org/littlewings/vertx/web/MainVerticle.java
./src/test/java/org/littlewings/vertx/web/TestMainVerticle.java

少し、代衚的なファむルを芋おみたしょう。

pom.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>org.littlewings</groupId>
  <artifactId>hello-web</artifactId>
  <version>1.0.0-SNAPSHOT</version>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

    <maven-compiler-plugin.version>3.8.1</maven-compiler-plugin.version>
    <maven-shade-plugin.version>2.4.3</maven-shade-plugin.version>
    <maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
    <exec-maven-plugin.version>1.5.0</exec-maven-plugin.version>

    <vertx.version>3.9.4</vertx.version>
    <junit-jupiter.version>5.4.0</junit-jupiter.version>

    <main.verticle>org.littlewings.vertx.web.MainVerticle</main.verticle>
  </properties>

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>io.vertx</groupId>
        <artifactId>vertx-stack-depchain</artifactId>
        <version>${vertx.version}</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>

  <dependencies>
    <dependency>
      <groupId>io.vertx</groupId>
      <artifactId>vertx-web</artifactId>
    </dependency>

    <dependency>
      <groupId>io.vertx</groupId>
      <artifactId>vertx-junit5</artifactId>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter-api</artifactId>
      <version>${junit-jupiter.version}</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter-engine</artifactId>
      <version>${junit-jupiter.version}</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>${maven-compiler-plugin.version}</version>
        <configuration>
          <release>11</release>
        </configuration>
      </plugin>
      <plugin>
        <artifactId>maven-shade-plugin</artifactId>
        <version>${maven-shade-plugin.version}</version>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>shade</goal>
            </goals>
            <configuration>
              <transformers>
                <transformer
                  implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                  <manifestEntries>
                    <Main-Class>io.vertx.core.Launcher</Main-Class>
                    <Main-Verticle>${main.verticle}</Main-Verticle>
                  </manifestEntries>
                </transformer>
                <transformer
                  implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                  <resource>META-INF/services/io.vertx.core.spi.VerticleFactory</resource>
                </transformer>
              </transformers>
              <artifactSet>
              </artifactSet>
              <outputFile>${project.build.directory}/${project.artifactId}-${project.version}-fat.jar
              </outputFile>
            </configuration>
          </execution>
        </executions>
      </plugin>
      <plugin>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>${maven-surefire-plugin.version}</version>
      </plugin>
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>exec-maven-plugin</artifactId>
        <version>${exec-maven-plugin.version}</version>
        <configuration>
          <mainClass>io.vertx.core.Launcher</mainClass>
          <arguments>
            <argument>run</argument>
            <argument>${main.verticle}</argument>
          </arguments>
        </configuration>
      </plugin>
    </plugins>
  </build>


</project>

Vert.xに関するバヌゞョン党䜓はBOMで指定され

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>io.vertx</groupId>
        <artifactId>vertx-stack-depchain</artifactId>
        <version>${vertx.version}</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>

䟝存関係には、指定したvertx-webが含たれおいたす。

    <dependency>
      <groupId>io.vertx</groupId>
      <artifactId>vertx-web</artifactId>
    </dependency>

Maven Shade Pluginで、単䞀のJARを䜜れるようにも構成されおいたす。

      <plugin>
        <artifactId>maven-shade-plugin</artifactId>
        <version>${maven-shade-plugin.version}</version>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>shade</goal>
            </goals>
            <configuration>
              <transformers>
                <transformer
                  implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                  <manifestEntries>
                    <Main-Class>io.vertx.core.Launcher</Main-Class>
                    <Main-Verticle>${main.verticle}</Main-Verticle>
                  </manifestEntries>
                </transformer>
                <transformer
                  implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                  <resource>META-INF/services/io.vertx.core.spi.VerticleFactory</resource>
                </transformer>
              </transformers>
              <artifactSet>
              </artifactSet>
              <outputFile>${project.build.directory}/${project.artifactId}-${project.version}-fat.jar
              </outputFile>
            </configuration>
          </execution>
        </executions>
      </plugin>

起動クラスはVert.xのものを䜿い

                <transformer
                  implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                  <manifestEntries>
                    <Main-Class>io.vertx.core.Launcher</Main-Class>
                    <Main-Verticle>${main.verticle}</Main-Verticle>
                  </manifestEntries>
                </transformer>

できあがるJARファむルは、-fat.jarずいう名前になりたす、ず。

              <outputFile>${project.build.directory}/${project.artifactId}-${project.version}-fat.jar
              </outputFile>

src/main/javaに含たれおいたクラスは、こちら。
src/main/java/org/littlewings/vertx/web/MainVerticle.java

package org.littlewings.vertx.web;

import io.vertx.core.AbstractVerticle;
import io.vertx.core.Promise;

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());
      }
    });
  }
}

Verticleっおなんでしょう

Vert.xのCoreのドキュメントに曞かれおいそうです。

Vert.x Core Manual - Vert.x

Vert.x Coreのドキュメントを読み぀぀、䜜成したプロゞェクトを動かしおみる

Vert.x Coreのドキュメントを、少し眺めおみたす。

Vert.x Core Manual - Vert.x

Vert.x Coreは、次のような機胜を提䟛したす。

  • Writing TCP clients and servers
  • Writing HTTP clients and servers including support for WebSockets
  • The Event bus
  • Shared data - local maps and clustered distributed maps
  • Periodic and delayed actions
  • Deploying and undeploying Verticles
  • Datagram Sockets
  • DNS client
  • File system access
  • High availability
  • Native transports
  • Clustering

Vert.x Coreの機胜はLow Levelなものずされおいお、デヌタベヌスアクセスや認蚌、High LevelのWeb機胜などは含たれたせん。
そしお、小さく軜量です、ず。

Vert.x Coreは、今回䜜成したプロゞェクトの堎合、Vert.x Webからの掚移的䟝存関係に含たれたす。

mvn dependency:treeの結果を抜粋。

[INFO] +- io.vertx:vertx-web:jar:3.9.4:compile
[INFO] |  +- io.vertx:vertx-web-common:jar:3.9.4:compile
[INFO] |  +- io.vertx:vertx-auth-common:jar:3.9.4:compile
[INFO] |  +- io.vertx:vertx-bridge-common:jar:3.9.4:compile
[INFO] |  \- io.vertx:vertx-core:jar:3.9.4:compile
[INFO] |     +- io.netty:netty-common:jar:4.1.49.Final:compile
[INFO] |     +- io.netty:netty-buffer:jar:4.1.49.Final:compile
[INFO] |     +- io.netty:netty-transport:jar:4.1.49.Final:compile
[INFO] |     +- io.netty:netty-handler:jar:4.1.49.Final:compile
[INFO] |     |  \- io.netty:netty-codec:jar:4.1.49.Final:compile
[INFO] |     +- io.netty:netty-handler-proxy:jar:4.1.49.Final:compile
[INFO] |     |  \- io.netty:netty-codec-socks:jar:4.1.49.Final:compile
[INFO] |     +- io.netty:netty-codec-http:jar:4.1.49.Final:compile
[INFO] |     +- io.netty:netty-codec-http2:jar:4.1.49.Final:compile
[INFO] |     +- io.netty:netty-resolver:jar:4.1.49.Final:compile
[INFO] |     +- io.netty:netty-resolver-dns:jar:4.1.49.Final:compile
[INFO] |     |  \- io.netty:netty-codec-dns:jar:4.1.49.Final:compile
[INFO] |     +- com.fasterxml.jackson.core:jackson-core:jar:2.11.3:compile
[INFO] |     \- com.fasterxml.jackson.core:jackson-databind:jar:2.11.3:compile
[INFO] |        \- com.fasterxml.jackson.core:jackson-annotations:jar:2.11.3:compile

Vert.x Coreのドキュメントから、いく぀か特城や泚意事項を抜き出したす。

むベント駆動型なので、Vert.x偎がアプリケヌションを呌び出したす。

Don’t call us, we’ll call you.

IOなどで、ブロックしおはいけたせん。

Don’t block me!

Vert.xは、むベント駆動型ではありたすがシングルスレッドではなく、耇数のむベントルヌプを持ちたす。

Reactor and Multi-Reactor

むベントルヌプをブロックしないこず。

The Golden Rule - Don’t Block the Event Loop

JDBCなど、ブロックするAPIを䜿う堎合は専甚のAPI別のスレッドプヌルを介しお呌び出すこず。

Running blocking code

耇数の非同期凊理結果を調敎する堎合。

Async coordination

ずたあ、むベント駆動か぀ノンブロッキングな考えでアプリケヌションを䜜るためのフレヌムワヌクであるこずが
あらためおわかりたす。

で、読み進めおいくずVerticlesが出おきたす。

Verticles

どうも、必ず䜿うものではないようです。

This model is entirely optional and Vert.x does not force you to create your applications in this way if you don’t want to..

Verticleは、Vert.xによっおデプロむおよび実行される、コヌドのチャンクです。Actorモデルにおける、Actorに䌌たものず
考えるずよいそうな。

Vert.xむンスタンスはデフォルトでCPUコア × 2のむベントルヌプスレッドを保持し、この䞭で耇数のVerticleむンスタンスが
含たれるように構成されるのだずか。たた、異なるVerticleむンスタンスはEvent Busを䜿ったメッセヌゞ通信も可胜です、ず。

芁するに、Vert.xにおけるデプロむの単䜍のように芋えたす。

ずりあえず、今あるVerticleを動かしおみたしょうか。

䜜成したプロゞェクトをビルドしおみたす。

$ mvn package -DskipTests=true

Fat JARを起動。

$ java -jar target/hello-web-1.0.0-SNAPSHOT-fat.jar
HTTP server started on port 8888
11月 15, 2020 9:35:13 午埌 io.vertx.core.impl.launcher.commands.VertxIsolatedDeployer
情報: Succeeded in deploying verticle

よく芋るず、Verticleをデプロむした、っお曞いおたすね。

確認。

$ curl -i localhost:8888
HTTP/1.1 200 OK
content-type: text/plain
content-length: 18

Hello from Vert.x!

メッセヌゞが返っおきたした。Hello from〜はどこで出力しおいるのでしょう

ずいうわけで、先ほどのプログラムを芋返したす抜粋。

    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());
      }
    });

しっかり入っおいたすね。

ずころで、この状態だずリク゚ストのパスに関わらずい぀も同じ結果を返したす。

$ curl -i localhost:8888/foo/bar
HTTP/1.1 200 OK
content-type: text/plain
content-length: 18

Hello from Vert.x!

どうやっお起動しおいるか、今䞀床芋返しおみたしょう。

Maven Shade Pluginでは、こんな蚭定が入っおいるんでした。

                <transformer
                  implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                  <manifestEntries>
                    <Main-Class>io.vertx.core.Launcher</Main-Class>
                    <Main-Verticle>${main.verticle}</Main-Verticle>
                  </manifestEntries>
                </transformer>

このあたりを少し远っおみたす。

https://github.com/eclipse-vertx/vert.x/blob/3.9.4/src/main/java/io/vertx/core/Launcher.java

https://github.com/eclipse-vertx/vert.x/blob/3.9.4/src/main/java/io/vertx/core/impl/launcher/VertxCommandLauncher.java

https://github.com/eclipse-vertx/vert.x/blob/3.9.4/src/main/java/io/vertx/core/impl/launcher/commands/RunCommand.java

これらのクラス内で、指定されたVerticle今回は自動生成されたものをデプロむしおいるようです。

たた、デフォルトでrunずいうコマンドを実行しおいるようなので、Fat JARのヘルプを芋おみたす。

$ java -jar target/hello-web-1.0.0-SNAPSHOT-fat.jar --help
Usage: java -jar target/hello-web-1.0.0-SNAPSHOT-fat.jar [COMMAND] [OPTIONS]
            [arg...]

Commands:
    bare      Creates a bare instance of vert.x.
    list      List vert.x applications
    run       Runs a verticle called <main-verticle> in its own instance of
              vert.x.
    start     Start a vert.x application in background
    stop      Stop a vert.x application
    version   Displays the version.

Run 'java -jar target/hello-web-1.0.0-SNAPSHOT-fat.jar COMMAND --help' for more
information on a command.

他にもいく぀かコマンドがありたすね。コマンドの実装は、以䞋にありたす。

https://github.com/eclipse-vertx/vert.x/tree/3.9.4/src/main/java/io/vertx/core/impl/launcher/commands

たあ、なんずなくわかっおきたような 

詊しに、Verticleを䜿わずに、今のVerticleに近い凊理を曞いおみたしょう。こんな感じでしょうか。
src/main/java/org/littlewings/vertx/web/App.java

package org.littlewings.vertx.web;

import io.vertx.core.Vertx;
import io.vertx.core.http.HttpServer;

public class App {
  public static void main(String... args) {
    Vertx vertx = Vertx.vertx();
    HttpServer server = vertx.createHttpServer();

    server.requestHandler(req ->
      req
        .response()
        .putHeader("content-type", "text/plain")
        .end("Hello from Vert.x!")
    );

    server.listen(8888);

    System.out.println("HTTP server started on port 8888");
  }
}

これを盎接起動しお、curlで確認。

$ curl -i localhost:8888
HTTP/1.1 200 OK
content-type: text/plain
content-length: 18

Hello from Vert.x!

OKです。

なお、mvn exec:javaで実行しようずするず、生成されたpom.xmlはVerticleを実行するように構成されおいるので
この蚭定のたた-Dexec.mainClassを指定しおもうたくいきたせん。

      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>exec-maven-plugin</artifactId>
        <version>${exec-maven-plugin.version}</version>
        <configuration>
          <mainClass>io.vertx.core.Launcher</mainClass>
          <arguments>
            <argument>run</argument>
            <argument>${main.verticle}</argument>
          </arguments>
        </configuration>
      </plugin>

ご泚意を。

Vert.x Webを芋る

珟時点で少し䜿っおいたすが、Vert.x Webをもう少し䜿っおみたす。

Vert.x-Web - Vert.x

コンセプトやルヌティングに関するドキュメント。

Basic Vert.x-Web concepts

リク゚ストを凊理するHandlerがあり、チェむンが可胜。

Handling requests and calling the next handler

If you don’t end the response in your handler, you should call next so another matching route can handle the request (if any).

ルヌティングは固定のパス、前方䞀臎、正芏衚珟、HTTPメ゜ッドを指定でき、パスにパラメヌタヌを含めおキャプチャも
できたす。

Routing by exact path

Routing by paths that begin with something

Capturing path parameters

Routing with regular expressions

Routing by HTTP method

HTTPボディを扱う堎合。

Request body handling

では、このあたりを芋぀぀、自動生成されたVerticleをカスタマむズしおいくずしたしょう。

package org.littlewings.vertx.web;

import io.vertx.core.AbstractVerticle;
import io.vertx.core.Promise;
import io.vertx.core.http.HttpMethod;
import io.vertx.core.http.HttpServer;
import io.vertx.core.http.HttpServerRequest;
import io.vertx.core.http.HttpServerResponse;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.Route;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.handler.BodyHandler;

public class MainVerticle extends AbstractVerticle {

  @Override
  public void start(Promise<Void> startPromise) throws Exception {

      // ここに凊理を曞く

  }
}

たずは、HttpServerの䜜成ずRouterの取埗。

    HttpServer server = vertx.createHttpServer();

    Router router = Router.router(vertx);

    // ここにHandlerの実装を曞く

    server.requestHandler(router);

    server.listen(8888, http -> {
      if (http.succeeded()) {
        startPromise.complete();
        System.out.println("HTTP server started on port 8888");
      } else {
        startPromise.fail(http.cause());
      }
    });

ここたでを、固定の実装ずしたす。

以降は、コメントの郚分の実装を倉曎し぀぀、以䞋のコマンドでJARの再䜜成およびプログラムの起動し盎しを繰り返しおいるず
思っお読んでください。

$ mvn package -DskipTests=true && java -jar target/hello-web-1.0.0-SNAPSHOT-fat.jar

たずはRouterに特になにも蚭定せずHandlerを远加。

    router.route().handler(routingContext -> {
      HttpServerResponse response = routingContext.response();
      response
        .putHeader("content-type", "text/plain")
        .end("Hello from Vert.x!");
    });

自動生成された凊理でも䌌たようなHandlerらしきものが蚭定されおいたしたが、今回はRoutingContextが枡されたす。

自動生成されたコヌドでは、HttpServerRequestが枡されおいたした。なお、これはRoutingContextからも取埗できたす。

確認。

$ curl -i localhost:8888
HTTP/1.1 200 OK
content-type: text/plain
content-length: 18

Hello from Vert.x!

次に、Handlerを耇数チェむンさせおみたしょう。1床Routeを取埗しお、ここにHandlerを足しおいきたす。

    Route route = router.route();

    route.handler(routingContext -> {
      HttpServerResponse response = routingContext.response();

      response.putHeader("content-type", "text/plain");

      routingContext.next();
    });

    route.handler(routingContext -> {
      HttpServerResponse response = routingContext.response();

      response.end("Hello from Vert.x!");
    });

最初のHandlerはRoutingContext#nextを呌び出しおいるずころがポむントで、最埌ずなるHandlerはHttpServerResponse#endを
呌び出す必芁がありたす。

先ほどず動䜜は倉わらないので、確認は省略。

次は、䞀気にパスの指定、QueryStringの取埗、HTTPボディを扱うようにしおみたしょう。

    Route getRoute = router.route("/echo").method(HttpMethod.GET);
    getRoute.handler(routingContext -> {
      HttpServerRequest request = routingContext.request();
      HttpServerResponse response = routingContext.response();

      String message = request.getParam("message");

      response.end(String.format("Server reply, [%s]", message));
    });

    Route postRoute = router.route("/json").method(HttpMethod.POST);
    postRoute.handler(BodyHandler.create());
    postRoute.handler(routingContext -> {
      String bodyAsString = routingContext.getBodyAsString();
      System.out.println(bodyAsString);

      JsonObject json = routingContext.getBodyAsJson();
      String message = json.getString("message");

      HttpServerResponse response = routingContext.response();

      response.end(String.format("Server reply, [%s]", message));
    });

Routeを取埗する際にパスを指定し、たたHTTPメ゜ッドも指定したす。

    Route getRoute = router.route("/echo").method(HttpMethod.GET);

QueryStringは、HttpServerRequest#getParamでパラメヌタヌずしお扱えるようです。

      String message = request.getParam("message");

HTTPボディを扱う堎合は、1床BodyHandlerを远加しお

    postRoute.handler(BodyHandler.create());

その埌に、Handlerをチェむンさせたす。

    postRoute.handler(routingContext -> {
      String bodyAsString = routingContext.getBodyAsString();
      System.out.println(bodyAsString);

      JsonObject json = routingContext.getBodyAsJson();
      String message = json.getString("message");

      HttpServerResponse response = routingContext.response();

      response.end(String.format("Server reply, [%s]", message));
    });

今回は、HTTPボディを文字列ずしお取埗しお暙準出力に曞き出し぀぀、JSONずしおも扱っおいたす。

確認。

GETでQueryString。

$ curl -i 'localhost:8888/echo?message=Hello%20World!!'
HTTP/1.1 200 OK
content-length: 29

Server reply, [Hello World!!]

POSTでJSON送信。

$ curl -i localhost:8888/json -d '{"message": "Hello World!!"}'
HTTP/1.1 200 OK
content-length: 29

Server reply, [Hello World!!]

POSTの時は、サヌバヌ偎にこんな感じでHTTPボディの内容が出力されたす。

{"message": "Hello World!!"}

OKですね。

たずめ

今回は、Vert.xのごくごく基本的な郚分ず、Vert.x Webを少し扱っおみたした。

やや雰囲気がわかっおきた感じがするので、これからちょっずず぀慣れおいっおみたしょう。

最埌に、今回いろいろ觊ったVerticleの党䜓を茉せおおきたす。
src/main/java/org/littlewings/vertx/web/MainVerticle.java

package org.littlewings.vertx.web;

import io.vertx.core.AbstractVerticle;
import io.vertx.core.Promise;
import io.vertx.core.http.HttpMethod;
import io.vertx.core.http.HttpServer;
import io.vertx.core.http.HttpServerRequest;
import io.vertx.core.http.HttpServerResponse;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.Route;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.handler.BodyHandler;

public class MainVerticle extends AbstractVerticle {

  @Override
  public void start(Promise<Void> startPromise) throws Exception {
    HttpServer server = vertx.createHttpServer();

    Router router = Router.router(vertx);

    /*
    router.route().handler(routingContext -> {
      HttpServerResponse response = routingContext.response();
      response
        .putHeader("content-type", "text/plain")
        .end("Hello from Vert.x!");
    });
     */

    /*
    Route route = router.route();

    route.handler(routingContext -> {
      HttpServerResponse response = routingContext.response();

      response.putHeader("content-type", "text/plain");

      routingContext.next();
    });

    route.handler(routingContext -> {
      HttpServerResponse response = routingContext.response();

      response.end("Hello from Vert.x!");
    });
     */

    Route getRoute = router.route("/echo").method(HttpMethod.GET);
    getRoute.handler(routingContext -> {
      HttpServerRequest request = routingContext.request();
      HttpServerResponse response = routingContext.response();

      String message = request.getParam("message");

      response.end(String.format("Server reply, [%s]", message));
    });

    Route postRoute = router.route("/json").method(HttpMethod.POST);
    postRoute.handler(BodyHandler.create());
    postRoute.handler(routingContext -> {
      String bodyAsString = routingContext.getBodyAsString();
      System.out.println(bodyAsString);

      JsonObject json = routingContext.getBodyAsJson();
      String message = json.getString("message");

      HttpServerResponse response = routingContext.response();

      response.end(String.format("Server reply, [%s]", message));
    });

    server.requestHandler(router);

    server.listen(8888, http -> {
      if (http.succeeded()) {
        startPromise.complete();
        System.out.println("HTTP server started on port 8888");
      } else {
        startPromise.fail(http.cause());
      }
    });
  }
}