每个 Route 对象只允许有一个子路由器

Only one sub router per Route object is allowed

我使用 Vert.x 创建了一个网络应用,如下所示:

class MainVerticle : AbstractVerticle() {

  private fun apiResource(r: Router): Unit {
    r.route("/api/*")
      .subRouter(GenderApi(vertx).create())
      .subRouter(InterestApi(vertx).create())
  }

  private fun rootResource(r: Router): Unit {
    r.route("/").handler {
      val res = it.response()
      res.putHeader("content-type", "text/plain");

      // Write to the response and end it
      res.end("I am healthy");
    }
  }

  override fun start(startPromise: Promise<Void>) {
    val server = vertx.createHttpServer()

    val router = Router.router(vertx)

    apiResource(router)
    rootResource(router)
    server.requestHandler(router).listen(8888) { http ->
      if (http.succeeded()) {
        startPromise.complete()
        println("HTTP server started on port 8888")
      } else {
        startPromise.fail(http.cause());
      }
    }
  }
}


class InterestApi(private val vertx: Vertx) {

  private val router = Router.router(vertx)

  init {
     readAll()
  }

  private fun readAll(): Route =
    router
      .get("/interests")
      .handler {
        val res = it.response()
        res.putHeader("content-type", "text/plain");

        // Write to the response and end it
        res.end("I am genders path");
      }


  fun create(): Router = router

}


class GenderApi(private val vertx: Vertx) {

  private val router = Router.router(vertx)

  init {
    readAll()
  }

  private fun readAll() : Route =
    router
      .get("/genders")
      .handler {
        val res = it.response()
        res.putHeader("content-type", "text/plain");

        // Write to the response and end it
        res.end("I am genders path");
      }

  fun create(): Router = router
}

编译器抱怨:

java.lang.IllegalStateException: Only one sub router per Route object is allowed.
        at io.vertx.ext.web.impl.RouteImpl.subRouter(RouteImpl.java:161)
        at io.databaker.MainVerticle.apiResource(MainVerticle.kt:15)
        at io.databaker.MainVerticle.start(MainVerticle.kt:33)
        at io.vertx.core.impl.DeploymentManager.lambda$doDeploy(DeploymentManager.java:196)
        at io.vertx.core.impl.AbstractContext.dispatch(AbstractContext.java:96)
        at io.vertx.core.impl.AbstractContext.dispatch(AbstractContext.java:59)
        at io.vertx.core.impl.EventLoopContext.lambda$runOnContext[=11=](EventLoopContext.java:40)
        at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:164)
        at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:472)
        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:500)
        at io.netty.util.concurrent.SingleThreadEventExecutor.run(SingleThreadEventExecutor.java:989)
        at io.netty.util.internal.ThreadExecutorMap.run(ThreadExecutorMap.java:74)
        at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
        at java.base/java.lang.Thread.run(Thread.java:834)

如何解决?

我想我用 误导了你。

Vertx 4 的正确语法是:

class MainVerticle : AbstractVerticle() {

    private fun apiResource(r: Router) {
        r.route("/api/genders*")
            .subRouter(GenderApi(vertx).create())
        r.route("/api/interests*")
            .subRouter(InterestApi(vertx).create())
    }

    private fun rootResource(r: Router): Unit {
        r.route("/").handler {
            val res = it.response()
            res.putHeader("content-type", "text/plain");

            // Write to the response and end it
            res.end("I am healthy");
        }
    }

    override fun start(startPromise: Promise<Void>) {
        val server = vertx.createHttpServer()

        val router = Router.router(vertx)

        apiResource(router)
        rootResource(router)
        server.requestHandler(router).listen(8888) { http ->
            if (http.succeeded()) {
                startPromise.complete()
                println("HTTP server started on port 8888")
            } else {
                println(http.cause())
                startPromise.fail(http.cause());
            }
        }
    }
}


class InterestApi(vertx: Vertx) {

    private val router = Router.router(vertx)

    init {
        readAll()
    }

    private fun readAll(): Route =
        router
            .get("/")
            .handler {
                val res = it.response()
                res.putHeader("content-type", "text/plain");

                // Write to the response and end it
                res.end("I am genders path");
            }


    fun create(): Router = router
}


class GenderApi(vertx: Vertx) {

    private val router = Router.router(vertx)

    init {
        readAll()
    }

    private fun readAll(): Route =
        router
            .get("/")
            .handler {
                val res = it.response()
                res.putHeader("content-type", "text/plain");

                // Write to the response and end it
                res.end("I am genders path");
            }

    fun create(): Router = router
}

如果您打算将 Interests 用作资源,则在 Vert.x 中使用子路由器是有意义的。

那么你会得到类似的东西:

router.get(...)
router.post(...)

不过,有一种更好的方法可以实现该功能。您可以使用 mountSubRouter:

而不是使用 subRouter
class MainVerticle : AbstractVerticle() {

    private fun apiResource(r: Router) {
        r.mountSubRouter("/api/", GenderApi(vertx).create())

        r.mountSubRouter("/api/", InterestApi(vertx).create())
    }

    private fun rootResource(r: Router): Unit {
        r.route("/").handler {
            val res = it.response()
            res.putHeader("content-type", "text/plain");

            // Write to the response and end it
            res.end("I am healthy");
        }
    }

    override fun start(startPromise: Promise<Void>) {
        val server = vertx.createHttpServer()

        val router = Router.router(vertx)

        apiResource(router)
        rootResource(router)
        server.requestHandler(router).listen(8888) { http ->
            if (http.succeeded()) {
                startPromise.complete()
                println("HTTP server started on port 8888")
            } else {
                println(http.cause())
                startPromise.fail(http.cause());
            }
        }
    }
}


class InterestApi(vertx: Vertx) {

    private val router = Router.router(vertx)

    init {
        readAll()
    }

    private fun readAll(): Route =
        router
            .get("/interests")
            .handler {
                val res = it.response()
                res.putHeader("content-type", "text/plain");

                // Write to the response and end it
                res.end("I am interests path");
            }


    fun create(): Router = router
}


class GenderApi(vertx: Vertx) {

    private val router = Router.router(vertx)

    init {
        readAll()
    }

    private fun readAll(): Route =
        router
            .get("/genders")
            .handler {
                val res = it.response()
                res.putHeader("content-type", "text/plain");

                // Write to the response and end it
                res.end("I am genders path");
            }

    fun create(): Router = router
}

请注意,使用mountSubRouter时,/api/*后不需要*,事实上,这会产生错误。