231419585
在第一篇文章中开发了一个很是简单的Vert.x 3应用程序,还包括怎么测试、打包和执行。在第二篇文章中对端口进行了可变配置。html
这篇文章中,开发一个CRUD(增删改查)应用,发布一个HTML页面,经过REST API与后台进行交互。RESTfull形式的API不简单,这篇文章中就不涉及了。java
接下来,能看到:git
这篇文章开发的代码放在GitHub上,是从第二篇文章的代码基础上进行的。github
若是你看了前面的文章,使用Vert.x Core来处理复杂的HTTP应用仍是很麻烦的,因此就有了Vert.x Web,它可使Vert.x开发一个web应用更加简单,并且不会改变Vert.x的思想。web
更新pom.xml文件,添加下面的依赖:数据库
<dependency> <groupId>io.vertx</groupId> <artifactId>vertx-web</artifactId> <version>3.0.0</version> </dependency>
这就是使用Vert.x Web的惟一前提。json
还记得在上一篇文章中,当请求http://localhost:8080
时,返回一个Hello World消息,使用Vert.x Web完成一样的事情,打开name.quanke.study.vertx.first.MyFirstVerticle.java
类,修改start
方法:后端
@Override public void start(Future<Void> fut) { // Create a router object. Router router = Router.router(vertx); // Bind "/" to our hello message - so we are still compatible. router.route("/").handler(routingContext -> { HttpServerResponse response = routingContext.response(); response .putHeader("content-type", "text/html") .end("<h1>Hello from my first Vert.x 3 application</h1>"); }); // Create the HTTP server and pass the "accept" method to the request handler. vertx .createHttpServer() .requestHandler(router::accept) .listen( // Retrieve the port from the configuration, // default to 8080. config().getInteger("http.port", 8080), result -> { if (result.succeeded()) { fut.complete(); } else { fut.fail(result.cause()); } } ); }
在开始start方法里建立了一个Router
对象。router是Vert.x Web的基础,负责分发HTTP请求到handler(处理器),在Vert.x Web中还有两个很重要的概念。api
若是明白了这3个概念(Router、Routes、Handlers),就明白了Vert.x Web的全部了。数组
仔细看看下面这段代码:
router.route("/").handler(routingContext -> { HttpServerResponse response = routingContext.response(); response .putHeader("content-type", "text/html") .end("<h1>Hello from my first Vert.x 3 application</h1>"); });
将访问"/"(http://localhost:8080/
)的请求“路由”到指定的handler。Handlers接收RoutingContext对象。这个handler的方法和咱们以前的代码很像,他们操做的是同一个HttpServerResponse类型的对象。
让咱们来看看剩下的代码:
vertx .createHttpServer() .requestHandler(router::accept) .listen( // Retrieve the port from the configuration, // default to 8080. config().getInteger("http.port", 8080), result -> { if (result.succeeded()) { fut.complete(); } else { fut.fail(result.cause()); } } ); }
除了改变了request handler,基本和以前的代码同样。传router::accept
给handler。你可能对这个符号不太熟悉。它表示引用一个方法(这里是引用router
的accept
方法)。换句话说,当接收到一个请求的时候,告诉vert.x从router
里调用accept
方法。
让咱们来看下它是怎么工做的:
mvn clean package java -jar target/my-first-app-1.0-SNAPSHOT-fat.jar
浏览器打开http://localhost:8080
,你会看到Hello的消息。
如今有了第一个使用Vert.x Web开发的应用。先在写增长一个index.html页面(静态资源)。
这个HTML页面将会是咱们应用的入口。在src/main/resources/assets目录下,index.html文件在github上。此文不涉及这个文件的细节。
基本上,就是一个简单的CRUD
的UI界面,actions
是由经过AJAX
调用的REST API
执行的。
建立完了页面后,编辑name.quanke.study.vertx.first.MyFirstVerticle类,并修改start方法:
@Override public void start(Future<Void> fut) { Router router = Router.router(vertx); router.route("/").handler(routingContext -> { HttpServerResponse response = routingContext.response(); response .putHeader("content-type", "text/html") .end("<h1>Hello from my first Vert.x 3 application</h1>"); }); // Serve static resources from the /assets directory // 将访问“/assets/*”的请求route到“assets”目录下的资源 router.route("/assets/*").handler(StaticHandler.create("assets")); vertx .createHttpServer() .requestHandler(router::accept) .listen( // Retrieve the port from the configuration, // default to 8080. config().getInteger("http.port", 8080), result -> { if (result.succeeded()) { fut.complete(); } else { fut.fail(result.cause()); } } ); }
就这段代码和前面的不一样:
router.route("/assets/*").handler(StaticHandler.create("assets"));
这一行是什么意思?挺简单的。将访问“/assets/*”的请求route到“assets”目录下的资源。如今能够经过http://localhost:8080/assets/index.html
来访问index.html了。
测试以前,咱们花一些时间来看一下handler的建立。全部的处理请求动做在Vert.x Web里都实现成handler。而建立一个handler须要调用create
方法。
编译、运行:
mvn clean package java -jar target/my-first-app-1.0-SNAPSHOT-fat.jar
浏览器,输入http://localhost:8080/assets/index.html
。
如今这个table是空的。那是由于咱们尚未实现REST的API。如今让咱们来开始吧。
Vert.x Web实现REST API很简单。看下面:
在实现REST API以前,须要建立Whisky的数据模型。使用下面的内容建立src/main/java/quanke/name/study/vertx/first/Whisky.java
:
package name.quanke.study.vertx.first; import java.util.concurrent.atomic.AtomicInteger; public class Whisky { private static final AtomicInteger COUNTER = new AtomicInteger(); private final int id; private String name; private String origin; public Whisky(String name, String origin) { this.id = COUNTER.getAndIncrement(); this.name = name; this.origin = origin; } public Whisky() { this.id = COUNTER.getAndIncrement(); } public String getName() { return name; } public String getOrigin() { return origin; } public int getId() { return id; } public void setName(String name) { this.name = name; } public void setOrigin(String origin) { this.origin = origin; } }
这是一个很简单的bean类。由于Vert.x依赖Jackson来处理JSON格式,Jackson可以自动序列化和反序列化bean类,让代码变得更简单,因此选择这样的格式。
如今,建立几瓶威士忌。在MyFirstVerticle类中,添加下面的代码:
// Store our product // 存储产品 private Map<Integer, Whisky> products = new LinkedHashMap<>(); // Create some product // 建立一些产品 private void createSomeData() { Whisky bowmore = new Whisky("Bowmore 15 Years Laimrig", "Scotland, Islay"); products.put(bowmore.getId(), bowmore); Whisky talisker = new Whisky("Talisker 57° North", "Scotland, Island"); products.put(talisker.getId(), talisker); }
而后,在start
方法里,调用createSomeData
方法:
@Override public void start(Future<Void> fut) { createSomeData(); // Create a router object. Router router = Router.router(vertx); // Rest of the method }
在这里并无一个后台数据库。仅使用一个map,将数据存储在内存中。添加后端数据库的介绍我准备放在另外一篇文章中讲。
GET /api/whiskies
,JSON数组中返回产品列表。
在start
方法里,添加下面这行(static handler):
router.get("/api/whiskies").handler(this::getAll);
告诉router
调用getAll
方法来处理"/api/whiskies"
的GET请求。代码能够写在handler
里,可是为了让代码更加清晰,另外建立一个方法:
private void getAll(RoutingContext routingContext) { routingContext.response() .putHeader("content-type", "application/json; charset=utf-8") .end(Json.encodePrettily(products.values())); }
每个handler(好比:请看上面的代码)都会接受一个RoutingContext
参数。经过设置content-type
和一些内容来填充response
。由于内容可能会碰到特殊的字符,因此强制使用UTF-8的格式。建立内容的时候,并不须要本身去处理JSON格式的字符串。Vert.x有处理Json的API。使用Json.encodePrettily(products.values())处理JSON字符串。本应使用Json.encodePrettily(products),可是为了让JavaScript代码更简单,咱们仅返回威士忌(产品)的数据集合,并无返回包含Id=>Bottle
的键值对。
打包运行:
mvn clean package java -jar target/my-first-app-1.0-SNAPSHOT-fat.jar
浏览器访问http://localhost:8080/assets/index.html
,而后你将会看到下面这个页面。
很好奇,想看一下REST API到底返回了什么。打开浏览器,访问http://localhost:8080/api/whiskies。你会看到下面这样的信息:
[ { "id" : 0, "name" : "Bowmore 15 Years Laimrig", "origin" : "Scotland, Islay" }, { "id" : 1, "name" : "Talisker 57° North", "origin" : "Scotland, Island" } ]
能获取到威士忌(产品)了,如今须要建立一个产品。不像以前的REST API,这一次,须要读取request
的body
。由于性能的缘由,它应该被显式地启用。不要怕,这也仅仅是一个handler
而已。
在start
方法中,添加下面的内容到getAll
的后面:
router.route("/api/whiskies*").handler(BodyHandler.create()); router.post("/api/whiskies").handler(this::addOne);
第一行容许"/api/whiskies"
下的全部route
读取请求的body
。经过使用router.route().handler(BodyHandler.create())
,能让它在全局生效。
第二行将对/api/whiskies
的POST请求映射到addOne
方法。让咱们来建立这个方法:
private void addOne(RoutingContext routingContext) { final Whisky whisky = Json.decodeValue(routingContext.getBodyAsString(), Whisky.class); products.put(whisky.getId(), whisky); routingContext.response() .setStatusCode(201) .putHeader("content-type", "application/json; charset=utf-8") .end(Json.encodePrettily(whisky)); }
开始从请求的body
中取出Whisky
对象。只是将body读成一个字符串并将它传入到Json.decodeValue方法里。Whisky这个对象一旦建立好,将被添加到后台的map中,并以JSON的格式返回。
从新编译而且运行:
mvn clean package java -jar target/my-first-app-1.0-SNAPSHOT-fat.jar
刷新HTML页面,点击Add a new bottle
按钮。输入数据,如:“quanke”
做为名字, “quanke.name” 做为产地 ,就OK了。
状态码 201 ? CREATED
和在REST API中建立一个entity时,response的状态码为201。。默认的vert.x web设置一个200的状态码表明OK。
在start
方法里,添加:
router.delete("/api/whiskies/:id").handler(this::deleteOne);
在URL
里,参数为::id
。在处理一个相匹配的请求的时候,Vert.x提取路径中与这个参数对应的一段,可以在handler中得到。例如,/api/whiskies/0
将id
映射为0
。
看一下在handler
方法中这个参数是怎样被使用的。建立一个deleteOne
方法。
private void deleteOne(RoutingContext routingContext) { String id = routingContext.request().getParam("id"); if (id == null) { routingContext.response().setStatusCode(400).end(); } else { Integer idAsInteger = Integer.valueOf(id); products.remove(idAsInteger); } routingContext.response().setStatusCode(204).end(); }
状态码 204 ? 状态码为204 - NO CONTENT。HTTP delete动做一般都是无返回内容的。
实现getOne和updateOne很简单,和上面的差很少,此文再也不详细介绍。源码在github上
此文介绍了如何用Vert.x web轻松的实现一个REST API,如何访问静态资源。比之前的文章复杂些,但仍然仍是很简单。