结合vert.x和mongo构建应用
Posted Vertx北京用户组
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了结合vert.x和mongo构建应用相关的知识,希望对你有一定的参考价值。
这篇文章是介绍vert.x系列的一部分。上篇,我们看到了怎样使用`vertx-jdbc-client`并通过JDBC驱动连接到一个数据库。在这篇文章中,我们会讲JDBC client替换成为`vertx-mongo-client`,也就是连接到Mongo数据库。
如果你不了解mongo,去看下[Mongo](https://www.mongodb.org/)的网站。
深入学习之前,让我们来回顾下。
前面介绍vert.x的文章
第一篇文章中,描述了怎么使用maven建立一个vert.x应用并执行测试。
第二篇文章中,描述了应用怎么来配置。
第三篇文章介绍了`vertx-web`,开发了一个小的集合管理应用。应用使用前端html/javascript提供了一个REST的API。
第四篇文章中,描述了怎样运行集成测试来保证你的应用表现的和预期一致。
最后一篇文章中,描述了怎样使用`vertx-jdbc-client`与数据库交互。
这篇文章描述了另一个vert.x编写的可以使用MongoDB的客户端应用。这个客户端应用提供了vert.x API异步的访问Mongo数据库。我们不会比较JDBC是否优于Mongo,他们各有利弊,你需要根据你的需求来确定你使用哪个数据库。重要的是Vert.x可以让你决定使用那种数据库。
这里是vertx-mongo-client文档:http://vertx.io/docs/vertx-mongo-client/java/
这篇文章的开发的代码在分支[post-6](https://github.com/cescoffier/my-vertx-first-app/tree/post-6)。基于分支[post-5](https://github.com/cescoffier/my-vertx-first-app/tree/post-5)开发的。
异步数据获取
异步性是vert.x的一个特性之一。使用异步API,你不需要等待结果。当结果准备好了的时候,你会被通知到。vert.x中通知是由同一个线程发起的,就像初始化request一样:
左边你的代码想要调用mongo client,并通过一个回调获得结果,这个回调当结果准备好时会被调用。调用mongo client是无阻塞并且马上返回。客户端处理并当结果从mongo中计算或检索完成时,它会在event loop中回调,就像request一样。
这种模式非常强大,因为它避免了同步的陷阱。当然,你的代码是通过一个单一的线程调用的,并不需要同步任何东西。
像每一个Maven程序一样
我们首先也需要更新我们的`pom.xml`文件。
在`pom.xml`里,将`vertx-jdbc-client`替换为`vertx-mongo-client`:
不像JDBC,我们在运行的时候实例化一个数据库。这里,我们需要明确的启动一个MongoDB的服务器。为了在测试中启动Mono服务器,我们添加上下面这个依赖:
这个依赖将会在我们的单元测试中使用,因为它会让我们通过代码来启动mongo服务器。在集成测试里,我们需要通过maven插件来启动和停止mongo服务器,在开始和结束我们集成测试的时候。将下面这段plugin代码添加到`pom.xml`文件`<plugins>`段落里:
注意到,我们这里使用的是37017端口,我们后面会使用到这个端口。
足够的xml内容了
现在,我们已经更新好了`pom.xml`文件,是时候来修改我们的verticle了。第一件事就是将jdbc客户端替换称为mongo客户端:
这个客户端是通过传入配置文件到verticle来配置的。使用mongo客户端,我们不需要得到一个连接,因为可以在里面获取它。因此,我们的启动序列变得更简单:
和前一篇文章一样,如果数据库为空,我们需要插入一些预定义的数据:
为了查明数据库中,是否已经包含了数据,我们从`whiskies`集合里检索documents的数量。这是通过`mongo.count(COLLECTION, new JsonObject(), count -> {})`完成的。第二个参数是查询。在这个例子中,我们想要计算所有的documents。通过使用`new JsonObject()`来完成,将会创建一个查询获取集合里所有的documents。它等效于`SELECT * FROM ...`。
同时,你也应该注意到了`insert`的调用。documents是作为JSON对象传入的,所以插入一个对象,仅需要将它序列化为JSON并使用`mongo.insert(COLLECTION, json, completion handler)`。
Mongo-ize的REST handlers
我们的应用启动序列已经转换成了mongo,现在我们更新代码来处理REST请求。
我们先从`getAll`方法开始,此方法返回所有存储的产品。为了实现这个,我们需要使用一个`find`方法。像我们前面在`count`方法里看到的,我们传入一个空的JSON对象,描述一个查询来接受所有的documents:
查询结果作为一个JSON对象的列表传入。通过这个列表,我们可以创建我们的产品实例,并且填满HTTP response。
为了删除一个特定的document,我们需要先使用`id`查询到这个document:
这个`new JsonObject().put("_id", id)`描述了一个查询,通过它独特的`id`,选择这个document,它等效于`SELECT * WHERE id=...`。注意到,`_id`是mongo的语法,用来通过id选择document。
更新document,相对来说是次要的:
从上代码里,我们可以看到,`update`方法携带了两个JSON对象作为参数:
第一个意味着查询(这里我们通过id来选择一个单一的document)。
第二个对象携带了修改来应用到这个选择的document上。它使用了mongo语法。在这个例子里,我们更新document使用`$set`操作。
替换document
在这个代码里,我们更新document仅替换一组字段。你可以用`mongo.replace(...)`替换整个document。
我明确的建议去看一下MongoDB的说明文档,特别是:
[Query syntax documentation](https://docs.mongodb.org/manual/tutorial/query-documents/)
[Update syntax documentation](https://docs.mongodb.org/manual/tutorial/modify-documents/)
是时候配置了
代码已经改好了,但是我们仍然需要更新我们的配置文件。使用JDBC时,我们在配置文件中传入了JDBC url和driver class。使用mongo,我们需要配置`connection_string`-我们的应用需要连接的这个`mongo://`url,还有`db_name`-数据源的名字。
启动我们的单元测试,编辑`MyFirstVerticleTest`文件,并且添加下面的代码:
在启动测试之前,我们通过代码启动了一个mongo数据库并监听端口12345。当我们的测试之行完了,我们关闭这个数据库。
因此,这个mongo服务器是被管理的。我们需要给verticle正确的配置。更新`DeploymentOption`实例:
这就是单元测试需要的全部。
集成测试里,我们需要使用额外的JSON配置文件。编辑`src/test/resources/my-it-config.json`:
注意到这里mongo服务器使用的端口,这个端口是在`pom.xml`文件里配置的。
最后但不是很重要的,我们仍然还有一个配置文件需要修改:在生产环境下,你用来启动应用的配置文件:
这里,你可能需要编辑`localhost:27017`正确的url来连接你的mongo服务器。
集成测试里的一些改动
由于mongo document的id是String类型的并不是integer类型,我们需要在集成测试里小幅的修改下document的选择。
是时候来运行了
是时候来打包、运行应用并且检查所有的API都运行正常。打包应用:
译者注:在实践的过程中,视网络的情况,一些必要组件没有下载下来,然后测试失败。重新运行即可。
然后,启动它,先启动你的mongo服务器然后启动:
这里,需要先启动mongo服务器,将mongo下载后,启动,如图:
然后输入上述命令,部署应用,结果如图:
最后打开浏览器访问[http://localhost:8082/assets/index.html](http://localhost:8082/assets/index.html),如图所示:
如果你和我一样,几乎使用docker/docker-machine做所有事情,编辑配置文件,将URL改成正确的主机(docker使用localhost,如果你使用docker-machine,使用docker-machine的ip)然后启动:
朋友们,大功告成了
我们到了这篇文章的结尾了。我们看到了,怎么使用vert-mongo-client来异步获取、存储数据到mongo数据库以及插入和更新数据。现在,你可以选择JDBC或Mongo来实现你的应用。此外,vert.x还提供了Redis的客户端。
下次,我们将会看到这个verticle怎么分离成两个verticles,以便更好的组织你的代码。这两个verticles之间通过services来相互通信。
翻译:weiyiysw
实践:weiyiysw
校对:子期
PS:小编水平有限,不足之处还请各位大侠指正。
以上是关于结合vert.x和mongo构建应用的主要内容,如果未能解决你的问题,请参考以下文章