Vert.x的路由器

Posted 方家小白

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Vert.x的路由器相关的知识,希望对你有一定的参考价值。

路由器 (Router) 是Vert.x-web的基础概念之一. 它是一个包含了0个或者多个路由的对象。

路由器接收HTTP请求并找到该请求的第一个匹配路由,并将请求传递给该路由。

路由可以有一个与之关联的处理程序(Headler),然后接收请求。然后,您对请求执行某些操作,然后结束它或将其传递给下一个匹配的处理程序。

对于路由的每个请求,都有一个唯一的路由上下文实例,并且相同的实例将传递给该请求的所有处理程序。一旦我们设置了处理程序,我们就设置HTTP服务器的请求处理程序来传递所有要处理的传入请求。

一个基础的路由器实例

package com.fxb.learn.vertx.router;

import io.vertx.core.AbstractVerticle;
import io.vertx.core.Promise;
import io.vertx.core.http.HttpServer;
import io.vertx.core.http.HttpServerResponse;
import io.vertx.ext.web.Router;

/**
* 基础的路由使用
*
* @author fangjiaxiaobai
* @date 2019-2019/9/8-08
* @since 1.0.0
*/

public class BasicRouterVerticle extends AbstractVerticle {

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

HttpServer httpServer = vertx.createHttpServer();

// 创建一个路由
Router router = Router.router(vertx);
// 路由没有任何匹配条件
router.route()
// 添加一个请求的处理器
.handler(routingContext -> { // 传递给处理程序的对象时RoutingContext,还有Request 和 Response
HttpServerResponse response = routingContext.response();
response.putHeader("context", "application/json");
response.end("hello world");
});


httpServer.requestHandler(router).listen(8080, handler -> {
if (handler.succeeded()) {
startPromise.complete();
System.out.println("HTTP server started on port 8080");
} else {
startPromise.fail(handler.cause());
}
});
}
}

处理请求并调用下一个处理程序

package com.fxb.learn.vertx.router;

import io.vertx.core.AbstractVerticle;
import io.vertx.core.Promise;
import io.vertx.core.http.HttpServerResponse;
import io.vertx.ext.web.Route;
import io.vertx.ext.web.Router;

/**
* 调用下一个handler
*
* @author fangjiaxiaobai
* @date 2019/9/8
* @since 1.0.0
*/

public class CallNextVerticle extends AbstractVerticle {

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

Router router = Router.router(vertx);

Route route = router.route("/append/");
route.handler(routingContext -> {
HttpServerResponse response = routingContext.response();
// 启用分块响应,
// 因为我们将添加数据给其他处理程序执行。
// 仅当多个处理程序输出时使用,这只需要一次。
response.setChunked(true);
response.write("data1");
// 5s之后,在执行下一个处理器
routingContext.vertx().setTimer(5000, tid -> {
routingContext.next();
});
});

route.handler(routingContext -> {
routingContext.response().write("data2");
routingContext.vertx().setTimer(5000, tid -> {
routingContext.next();
});
});

route.handler(routingContext -> {
routingContext.response().write("data3").end();
});

vertx.createHttpServer().requestHandler(router).listen(8081, listener -> {
if (listener.succeeded()) {
System.out.println("HTTP server started on port 8081");
startPromise.complete();
} else {
startPromise.fail(listener.cause());
}
});

}
}

使用阻塞的处理程序

有时,可能会需要阻塞事件,在循环一段时间的处理程序中执行某些操作,例如调用遗留阻止API或进行一些密集计算。你不能在普通的处理程序中这样做,所以vertx提供了在路由上设置阻塞处理程序的能力。阻塞处理程序看起来就像一个普通的处理程序,但Vert.x使用来自工作池的线程调用它而不使用Event Loop。您使用blockingHandler在路由上设置阻止处理程序。

package com.fxb.learn.vertx.router;

import io.vertx.core.AbstractVerticle;
import io.vertx.core.Promise;
import io.vertx.core.http.HttpServerResponse;
import io.vertx.ext.web.Route;
import io.vertx.ext.web.Router;

/**
* 使用阻塞式的处理器
*
* @author fangjiaxiaobai
* @date 2019/9/8
* @since 1.0.0
*/

public class BlockingVerticle extends AbstractVerticle {

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

Router router = Router.router(vertx);

Route route = router.route("/append/");
route.blockingHandler(routingContext -> {
HttpServerResponse response = routingContext.response();
response.setChunked(true);
response.write("data1");
// todo 假装被阻塞了....
// doSomething
routingContext.vertx().setTimer(5000, tid -> {
routingContext.next();
});
});

route.handler(routingContext -> {
routingContext.response().write("data2");
routingContext.vertx().setTimer(5000, tid -> {
routingContext.next();
});
});

route.handler(routingContext -> {
routingContext.response().write("data3").end();
});

vertx.createHttpServer().requestHandler(router).listen(8081, listener -> {
if (listener.succeeded()) {
System.out.println("HTTP server started on port 8081");
startPromise.complete();
} else {
startPromise.fail(listener.cause());
}
});

}
}

我们还是沿用了,上面那个例子的代码,只是修改了

route.blockingHandler(routingContext -> {
HttpServerResponse response = routingContext.response();
response.setChunked(true);
response.write("data1");
// todo 假装被阻塞了....
// doSomething
routingContext.vertx().setTimer(5000, tid -> {
routingContext.next();
});
});

默认情况下,在同一个上下文(例如同一个Verticle实例)上执行的任何阻塞处理程序都是有序的 - 这意味着下一个阻塞处理程序在前一个完成之前不会被执行。如果您不关心orderering并且不介意并行执行阻塞处理程序,则可以使用blockingHandler将阻止处理程序指定为false。例如:

route.blockingHandler(routingContext -> {
HttpServerResponse response = routingContext.response();
response.setChunked(true);
response.write("data1");
// todo 假装被阻塞了....
// doSomething
routingContext.vertx().setTimer(5000, tid -> {
routingContext.next();
});
},false);

如果需要处理阻塞处理程序中的多部分表单数据,则必须使用非阻塞处理程序去处理,并且设置setExpectMultipart(true)。例如

// ... 省略部分代码
Route route = router.route("/append/");

route.handler(routingContext -> {
routingContext.request().setExpectMultipart(true);
routingContext.next();
});
route.blockingHandler(routingContext -> {
HttpServerResponse response = routingContext.response();
// 启用分块响应,
// 因为我们将添加数据给其他处理程序执行。
// 仅当多个处理程序输出时使用,这只需要一次。
response.setChunked(true);
response.write("data1");
// todo 假装被阻塞了....
// doSomething
// 5s之后,在执行下一个处理器
routingContext.vertx().setTimer(5000, tid -> {
routingContext.next();
});
}, false);

// ... 省略部分代码

好了,这篇文章,就先讲到这里.

下一篇我们说下Vert.x的路由规则.

这里提前透露下:

  •  根据路径匹配

  •  根据请求方法匹配

  • 根据基于正则表达式匹配

  • 根据请求的MIME类型进行匹配

敬请期待!

今晚不准备看个电影吗?好好学习,好好生活,好好工作,加油!