使用vert.x 2.0,RxJava和mongoDB创建simpe RESTful服务
中斷了將近半年后發表了一篇新文章。 在本文中,我們將快速了解如何開始使用vert.x,更有趣的是,如何使用RxJava簡化異步系統的編程。 我們將涵蓋以下主題:
- 使用Maven創建一個空的vert.x項目
- 導入IntelliJ并創建一個簡單的HTTP服務器
- 使用vert.x mongoDB持久性模塊從mongoDB加載數據
- 通過REST界面公開拉鏈
- 用RxJava觀察者替換回調
首先要做的很簡單,我們只是使用標準的Maven原型創建一個vert.x項目。 (請注意,可以從github下載完整的最終示例: https : //github.com/josdirksen/smartjava/tree/master/vertx-demo-1 )
使用Maven創建一個空的vert.x項目
轉到要在其中創建vert.x項目的目錄,鍵入以下內容,然后按Enter鍵:
jos@Joss-MacBook-Pro.local:~/Dev/playground$ mvn archetype:generate -Dfilter=io.vertx:這顯示了所有可用的io.vertx原型(在這種情況下只有1個)
[INFO] Scanning for projects... [INFO] [INFO] ------------------------------------------------------------------------ [INFO] Building Maven Stub Project (No POM) 1 [INFO] ------------------------------------------------------------------------ [INFO] [INFO] >>> maven-archetype-plugin:2.2:generate (default-cli) @ standalone-pom >>> [INFO] [INFO] <<< maven-archetype-plugin:2.2:generate (default-cli) @ standalone-pom <<< [INFO] [INFO] --- maven-archetype-plugin:2.2:generate (default-cli) @ standalone-pom --- [INFO] Generating project in Interactive mode [INFO] No archetype defined. Using maven-archetype-quickstart (org.apache.maven.archetypes:maven-archetype-quickstart:1.0) Choose archetype: 1: remote -> io.vertx:vertx-maven-archetype (-) Choose a number or apply filter (format: [groupId:]artifactId, case sensitive contains): :由于只有一個,因此只需輸入“ 1”,然后按Enter。 接下來,它將顯示您可以選擇的版本。 在此示例中,我選擇了2.0.1-最終版本。
Choose io.vertx:vertx-maven-archetype version: 1: 1.0.0-beta1 2: 1.0.0-beta2 3: 1.0.0-beta3 4: 1.0.0-CR1 5: 1.0.0-CR2 6: 2.0.0-final 7: 2.0.1-final Choose a number: 7:輸入“ 7”,然后按Enter。 接下來的步驟使您可以定義項目的名稱和版本:
Define value for property 'groupId': : org.smartjava Define value for property 'artifactId': : vertx-demo-1 Define value for property 'version': 1.0-SNAPSHOT: : Define value for property 'package': org.smartjava: : Confirm properties configuration: groupId: org.smartjava artifactId: vertx-demo-1 version: 1.0-SNAPSHOT package: org.smartjavaY: : Y輸入您可以在上面看到的值(或使用自己的值),最后輸入“ Y”以確認您的選擇。 現在將創建一個項目:
[INFO] ---------------------------------------------------------------------------- [INFO] Using following parameters for creating project from Archetype: vertx-maven-archetype:2.0.1-final [INFO] ---------------------------------------------------------------------------- [INFO] Parameter: groupId, Value: org.smartjava [INFO] Parameter: artifactId, Value: vertx-demo-1 [INFO] Parameter: version, Value: 1.0-SNAPSHOT [INFO] Parameter: package, Value: org.smartjava [INFO] Parameter: packageInPathFormat, Value: org/smartjava [INFO] Parameter: package, Value: org.smartjava [INFO] Parameter: version, Value: 1.0-SNAPSHOT [INFO] Parameter: groupId, Value: org.smartjava [INFO] Parameter: artifactId, Value: vertx-demo-1 [INFO] project created from Archetype in dir: /Users/jos/Dev/playground/vertx-demo-1 [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 5:37.710s [INFO] Finished at: Sun Nov 24 14:55:12 CET 2013 [INFO] Final Memory: 9M/24M [INFO] ------------------------------------------------------------------------要測試一切是否正確,只需轉到剛剛創建的目錄,然后運行“ mvn install”。 這將下載所有必需的庫,運行一些測試并將您的項目安裝到本地Maven存儲庫。 現在我們有了一個maven項目,我們可以將其加載到我們最喜歡的IDE中。 就我而言,我使用IntelliJ,但是Eclipse的工作方式幾乎相同。
導入IntelliJ并創建一個簡單的HTTP服務器
啟動IntelliJ并選擇“文件->導入項目”,導航到maven創建的目錄并導入項目。
只需在所有問題上單擊“下一步”,您就可以在IntelliJ中擁有一個項目。 如果您基于此原型創建項目,則會自動獲得許多可以試用的頂點。 groovy中定義了其中的幾個。 IntelliJ會自動嘗試編譯它們,但是由于找不到合適的編譯器,因此編譯/生成過程失敗。 在此示例中,我們將首先關注vert.x的Java部分,因此只需從“ src / main / resources”和“ test / resources / integration_tests / groovy”目錄中刪除.groovy文件。
現在,我們可以通過使用maven安裝模塊,然后調用'vertx:runModIDEA'目標,直接通過maven使用提供的處理程序運行vert.x。 請注意,您確實需要先調用'mvn:compile'來查看所做的更改。 如果您不想使用maven從IDE運行項目,則還可以使用其他方法,即使用'org.vertx.java.platform.impl.cli.Starter'類啟動vert.x。直接從IDE。 在IntelliJ中,您為此創建以下啟動配置:
如果運行此命令,仍然會看到錯誤。 像這樣:
Exception in thread "main" java.lang.ClassNotFoundException: org.vertx.java.platform.impl.cli.Starterat java.net.URLClassLoader$1.run(URLClassLoader.java:366)at java.net.URLClassLoader$1.run(URLClassLoader.java:355)at java.security.AccessController.doPrivileged(Native Method)at java.net.URLClassLoader.findClass(URLClassLoader.java:354)at java.lang.ClassLoader.loadClass(ClassLoader.java:424)at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)at java.lang.ClassLoader.loadClass(ClassLoader.java:357)at java.lang.Class.forName0(Native Method)at java.lang.Class.forName(Class.java:190)at com.intellij.rt.execution.application.AppMain.main(AppMain.java:113)之所以會這樣,是因為在由vert.x原型創建的pom.xml中,將vert.x庫指定為“提供”。 作為快速解決方案,請打開pom.xml并將三個io.vertx依賴項的范圍從“提供”更改為“編譯”。 現在,當您從IntelliJ運行此啟動器時,vert.x將正確啟動。
/Library/Java/JavaVirtualMachines/jdk1.7.0_25.jdk/Contents/Home/bin/java -Didea.launcher.port=7543 "-Didea.launcher.bin.path=/Applications/IntelliJ IDEA 12.app/bin" -Dfile.encoding=UTF-8 -classpath "..." com.intellij.rt.execution.application.AppMain org.vertx.java.platform.impl.cli.Starter runmod org.smartjava~vertx-demo-1~1.0-SNAPSHOT log4j:WARN No appenders could be found for logger (io.netty.util.internal.logging.InternalLoggerFactory). log4j:WARN Please initialize the log4j system properly. log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info. Nov 24, 2013 3:43:26 PM org.vertx.java.core.logging.impl.JULLogDelegate info INFO: Module org.smartjava~vertx-demo-1~1.0-SNAPSHOT successfully installed Nov 24, 2013 3:43:26 PM org.vertx.java.core.logging.impl.JULLogDelegate info INFO: PingVerticle started Nov 24, 2013 3:43:26 PM org.vertx.java.core.logging.impl.JULLogDelegate info INFO: Succeeded in deploying module現在,我們已經在IntelliJ中設置了項目,并且可以直接從IDE輕松運行它(并使用ctrl-F5重新啟動它),讓我們開始創建一個簡單的HTTP服務器,以便我們可以看到瀏覽器中的一些輸出以進行測試更容易(請注意,比我在這里顯示的測試vert.x和verticles更好的方法,但這是另一篇文章)。 打開PingVerticle.java文件,并將啟動方法替換為以下代碼:
package org.smartjava;import org.vertx.java.core.Handler; import org.vertx.java.core.http.HttpServerRequest; import org.vertx.java.platform.Verticle;public class PingVerticle extends Verticle {public void start() {vertx.createHttpServer().requestHandler(new Handler<HttpServerRequest>() {@Overridepublic void handle(HttpServerRequest httpServerRequest) {httpServerRequest.response().end("Hello smartjava");}}).listen(8888);container.logger().info("Webserver started, listening on port: 8888");} }運行此命令,然后打開瀏覽器到localhost:8888,您將看到以下內容。
這是您在vert.x中創建并直接從IDE運行的Web服務器。 小菜一碟到目前為止。 現在,讓我們獲取一些數據來處理。
使用vert.x mongoDB持久性模塊從mongoDB加載數據
我不會深入探討如何安裝mongoDB,互聯網上有足夠的文章對此進行了解釋。 如果您在Mac上運行并安裝了macport,則只需使用以下命令行即可安裝mongoDB:
sudo port install mongodb在本文的其余部分中,我假設您已經安裝了mongoDB,并且可以從控制臺獲得其命令行工具。 我們需要做的第一件事是獲取一些數據。 在此示例中,我們將使用可從mongoDB網站下載的郵政編碼列表: http ://media.mongodb.org/zips.json。 下載此文件,打開控制臺并運行以下命令,首先啟動mongoDB,然后將此zip列表導入mongoDB。
jos@Joss-MacBook-Pro.local:~/Dev/playground/vertx-demo-1$ mkdir data jos@Joss-MacBook-Pro.local:~/Dev/playground/vertx-demo-1$ mongod --dbpath ./data/ Sun Nov 24 16:23:51.765 [initandlisten] MongoDB starting : pid=77755 port=27017 dbpath=./data/ 64-bit host=Joss-MacBook-Pro.local Sun Nov 24 16:23:51.765 [initandlisten] db version v2.4.5 Sun Nov 24 16:23:51.765 [initandlisten] git version: nogitversion Sun Nov 24 16:23:51.765 [initandlisten] build info: Darwin Joss-MacBook-Pro.local 12.4.0 Darwin Kernel Version 12.4.0: Wed May 1 17:57:12 PDT 2013; root:xnu-2050.24.15~1/RELEASE_X86_64 x86_64 BOOST_LIB_VERSION=1_54 Sun Nov 24 16:23:51.765 [initandlisten] allocator: tcmalloc Sun Nov 24 16:23:51.765 [initandlisten] options: { dbpath: "./data/" } Sun Nov 24 16:23:51.766 [initandlisten] journal dir=./data/journal Sun Nov 24 16:23:51.766 [initandlisten] recover : no journal files present, no recovery needed Sun Nov 24 16:23:51.779 [FileAllocator] allocating new datafile ./data/local.ns, filling with zeroes... Sun Nov 24 16:23:51.779 [FileAllocator] creating directory ./data/_tmp Sun Nov 24 16:23:51.812 [FileAllocator] done allocating datafile ./data/local.ns, size: 16MB, took 0.031 secs Sun Nov 24 16:23:51.853 [FileAllocator] allocating new datafile ./data/local.0, filling with zeroes... Sun Nov 24 16:23:52.254 [FileAllocator] done allocating datafile ./data/local.0, size: 64MB, took 0.4 secs Sun Nov 24 16:23:52.260 [initandlisten] command local.$cmd command: { create: "startup_log", size: 10485760, capped: true } ntoreturn:1 keyUpdates:0 reslen:37 480ms Sun Nov 24 16:23:52.260 [initandlisten] waiting for connections on port 27017 Sun Nov 24 16:23:52.260 [websvr] admin web console waiting for connections on port 28017現在我們可以使用mongoImport導入下載的郵政編碼:
jos@Joss-MacBook-Pro.local:~/Dev/playground/vertx-demo-1$ wget http://media.mongodb.org/zips.json --2013-11-24 16:25:45-- http://media.mongodb.org/zips.json Resolving media.mongodb.org... 54.230.131.14, 54.230.131.51, 54.230.128.129, ... Connecting to media.mongodb.org|54.230.131.14|:80... connected. HTTP request sent, awaiting response... 200 OK Length: 2871006 (2.7M) [application/json] Saving to: `zips.json'100%[======================================>] 2,871,006 2.20M/s in 1.2s 2013-11-24 16:25:47 (2.20 MB/s) - `zips.json' saved [2871006/2871006]jos@Joss-MacBook-Pro.local:~/Dev/playground/vertx-demo-1$ mongoimport --db vertx --collection zips --file ./zips.json connected to: 127.0.0.1 Sun Nov 24 16:26:28.337 check 9 29470 Sun Nov 24 16:26:28.458 imported 29470 objects jos@Joss-MacBook-Pro.local:~/Dev/playground/vertx-demo-1$如果您已在IntelliJ中安裝了mongoDB插件,則可以輕松測試它是否正常工作:
此時,我們只需要從vert.x調用mongoDB實例并加載數據即可。 為此,我們將使用mongodb持久性庫。 首先,我們需要將此模塊添加到Maven構建中(請注意,這主要用于我們要在內部進行調試的vert.x解析此模塊本身):
<dependency><groupId>io.vertx</groupId><artifactId>mod-mongo-persistor</artifactId><version>2.1.0-SNAPSHOT</version><scope>compile</scope></dependency>Vert.x有一個非常有趣的模塊系統(另一篇文章也有此內容),要使用此mongo-persistor,我們首先需要將其部署為模塊。 這實際上很容易做到:
// load the general config object, loaded by using -config on command line JsonObject appConfig = container.config();// deploy the mongo-persistor module, which we'll use for persistence container.deployModule("io.vertx~mod-mongo-persistor~2.1.0-SNAPSHOT", appConfig.getObject("mongo-persistor"));在這里,我們要做的是加載該模塊的配置,然后調用該模塊的名稱以及配置的相關部分的deployModule。 首先,讓我們看看我們用于此的配置:
{"mongo-persistor" : {"address": "mongodb-persistor","host": "localhost","port": 27017,"pool_size": 10,"db_name": "vertx"} }沒什么難的。 我們只是將mongo-persister單元指向我們的mongoDB實例。 您可能會遇到的一個問題是,如何在vert.x中獲取此文件。 為此,我們只需要對啟動器進行一些小的更改,并從以下項更改程序參數:
runmod org.smartjava~vertx-demo-1~1.0-SNAPSHOT對此:
runmod org.smartjava~vertx-demo-1~1.0-SNAPSHOT -conf src/main/resources/config.jsonconfig.json文件包含我們剛剛顯示的配置。 因此,通過此設置,我們可以在事件總線地址“ mongodb-persistor”上監聽mongodb-persistor庫。 現在剩下要做的就是以該模塊可以理解的格式將消息發送到此端點。 第一步,我們將搜索狀態為“ AL”的所有郵政編碼。 如果您瀏覽https://github.com/vert-x/mod-mongo-persistor/的文檔,您會發現我們已經告訴該模塊要搜索的“集合”以及“操作”的類型我們要使用。 根據操作,需要其他配置。 要搜索“ AL”狀態下的所有郵政編碼,我們需要創建以下json消息:
{"action": "find","collection": "zips","matcher": {"state": "AL"} }讓我們更改請求處理程序并查看完整的start方法:
public void start() {// load the general config object, loaded by using -config on command lineJsonObject appConfig = container.config();// deploy the mongo-persistor module, which we'll use for persistencecontainer.deployModule("io.vertx~mod-mongo-persistor~2.1.0-SNAPSHOT", appConfig.getObject("mongo-persistor"));// create and run the serververtx.createHttpServer().requestHandler(new Handler<HttpServerRequest>() {@Overridepublic void handle(final HttpServerRequest httpServerRequest) {// we send the response from the mongo query back to the client.// first create the queryJsonObject matcher = new JsonObject().putString("state", "AL");JsonObject json = new JsonObject().putString("collection", "zips").putString("action", "find").putObject("matcher", matcher);// send it over the busvertx.eventBus().send("mongodb-persistor", json, new Handler<Message<JsonObject>>() {@Overridepublic void handle(Message<JsonObject> message) {// send the response back, encoded as stringhttpServerRequest.response().end(message.body().encodePrettily());}});}}).listen(8888);// output that the server is startedcontainer.logger().info("Webserver started, listening on port: 8888");}在這里,您可以看到我們創建了正確的json消息,通過總線發送了該消息,然后等待將響應發送回,直到我們從mongoDB獲得響應。 我們美化此響應并將其發送回客戶端:
通過REST界面公開拉鏈
現在我們已經有了基本的后端組件,讓我們看看創建一個簡單的基于REST的前端需要什么。 我們將跳過特定于媒體類型的過濾(我將在后面的文章中添加),現在我們只看HTTP動詞和URL。 對于這一部分,我們希望支持以下REST調用:
* GET /zipsShow all the zipcode information that are stored in mongoDB * GET /zips/:idShow the information belonging to the specified zip code * GET /zips?state=:state&city=:citySimple search service, where you can search for zip codes per city or state* POST /zips/:idUpdate existing zip code information非常簡單,但是這里的主要目標是顯示其完成方式,而不是如何創建完整的RESTful服務。 為了處理這些各種URL和動詞,vert.x提供了一個路由匹配器:(為清晰起見,省略了方法體)
RouteMatcher matcher = new RouteMatcher();// the matcher for the complete list and the searchmatcher.get("/zips", new Handler<HttpServerRequest>() {...}// the matcher for a specific idmatcher.get("/zips/:id", new Handler<HttpServerRequest>() {...}// the matcher for the updatematcher.post("/zips/:id", new Handler<HttpServerRequest>() {...}vertx.createHttpServer().requestHandler(matcher).listen(8888);對于那些使用諸如sinatra或scalatra之類的庫的人來說,這看起來很熟悉。 我們定義了要處理的方法(在這種情況下為獲取和發布),我們感興趣的url以及在收到請求時將被調用的處理程序。 如您在最后一行看到的那樣,我們傳入此處理程序來處理對我們創建的服務器的請求。
現在讓我們快速看一下這些處理程序的實現。 在這里,我們創建了與mongoDB通信的mongo-persistor消息。 我不會過多介紹這些方法,因為它們幾乎可以自我解釋:
// the matcher for the complete list and the searchmatcher.get("/zips", new Handler<HttpServerRequest>() {public void handle(final HttpServerRequest req) {JsonObject json = new JsonObject();MultiMap params = req.params();if (params.size() > 0 && params.contains("state") || params.contains("city")) {// create the matcher configurationJsonObject matcher = new JsonObject();if (params.contains("state")) matcher.putString("state", params.get("state"));if (params.contains("city")) matcher.putString("city", params.get("city"));// create the message for the mongo-persistor verticlejson = new JsonObject().putString("collection", "zips").putString("action", "find").putObject("matcher", matcher);} else {// create the queryjson = new JsonObject().putString("collection", "zips").putString("action", "find").putObject("matcher", new JsonObject());}JsonObject data = new JsonObject();data.putArray("results", new JsonArray());// and call the event we want to usevertx.eventBus().send("mongodb-persistor", json, new ReplyHandler(req, data));}});在這種方法中,我們從mongoDB中檢索所有郵政編碼。 由于mongo-persistor不會返回所有內容,因此我們需要對響應進行迭代。 我們使用以下ReplyHandler進行此操作:
private static class ReplyHandler implements Handler<Message<JsonObject>> {private final HttpServerRequest request;private JsonObject data;private ReplyHandler(final HttpServerRequest request, JsonObject data) {this.request = request;this.data = data;}@Overridepublic void handle(Message<JsonObject> event) {// if the response contains more message, we need to get the restif (event.body().getString("status").equals("more-exist")) {JsonArray results = event.body().getArray("results");for (Object el : results) {data.getArray("results").add(el);}event.reply(new JsonObject(), new ReplyHandler(request, data));} else {JsonArray results = event.body().getArray("results");for (Object el : results) {data.getArray("results").add(el);}request.response().putHeader("Content-Type", "application/json");request.response().end(data.encodePrettily());}}}在這個ReplyHandler中,我們僅瀏覽結果并繼續要求提供更多內容,直到不再看到“已存在”狀態為止。 我將跳過僅檢索單個郵政編碼的處理程序,因為它并不那么有趣。 下一個處理程序處理post函數,通過該函數我們可以更新現有元素。
matcher.post("/zips/:id", new Handler<HttpServerRequest>() {public void handle(final HttpServerRequest req) {// process the bodyreq.bodyHandler(new Handler<Buffer>() {@Overridepublic void handle(Buffer event) {// normally we'd validate the input, for now just assume it is correct.final String body = event.getString(0,event.length());// create the queryJsonObject newObject = new JsonObject(body);JsonObject matcher = new JsonObject().putString("_id", req.params().get("id"));JsonObject json = new JsonObject().putString("collection", "zips").putString("action", "update").putObject("criteria", matcher).putBoolean("upsert", false).putBoolean("multi",false).putObject("objNew",newObject);// and call the event we want to usevertx.eventBus().send("mongodb-persistor", json, new Handler<Message<JsonObject>>() {@Overridepublic void handle(Message<JsonObject> event) {// we could handle the errors here, but for now// assume everything went ok, and return the original// and updated jsonreq.response().end(body);}});}});}});代碼本身并不復雜。 我們首先使用處理程序來處理請求,然后從該處理程序中創建一個新的處理程序,該處理程序用于獲取請求的主體,最后創建一個處理程序,該處理程序更新數據庫并發送回響應。 盡管它并不復雜,但是當涉及到越來越多的處理程序時,它會變得有些繁瑣且難以閱讀。 因此,在本文的最后一部分,我們將介紹如何使用rxjava提供的功能替換嵌套處理程序。
用RxJava觀察者替換回調
對于rxjava代碼,我們將只添加幾個與不同URL匹配的額外處理程序。 因此,該網址將是/ rxzips / 90210,而不是/ zips / 90210。 首先,將以下依賴項添加到您的Maven配置中:
<dependency><groupId>io.vertx</groupId><artifactId>mod-rxjava</artifactId><version>1.0.0-beta2-SNAPSHOT</version><scope>compile</scope></dependency>在深入探討如何將rxjava和vert.x一起使用之前(從rxjava站點獲取),快速引語解釋了為什么這樣做很有用:
Java Futures可直接用于單個級別的異步執行,但是嵌套時它們開始增加非同尋常的復雜性。
很難使用Future來最佳地組成條件異步執行流(或者是不可能的,因為每個請求的延遲在運行時會有所不同)。 當然可以這樣做,但是很快就會變得復雜(因此容易出錯),或者過早地在Future.get()上阻塞,這消除了異步執行的好處。
另一方面,RxJava Observables旨在組成異步數據的流和序列。
使用RxJava Observables,可以很容易地組成異步數據流和序列。 如果查看示例中的最后兩個代碼示例,您會發現為什么這樣做會很有用。 在最后一個“ post”示例中,我們有三個嵌套的回調,通過可觀察的函數,可以很容易地編寫它并使代碼實際告訴正在發生的事情。
現在,讓我們擴展post方法來執行以下操作:
如果使用回調進行此操作,則可能需要四個嵌套級別的回調。 在rxjava中,我們可以按以下方式進行操作:
matcher.post("/rxzips/:id", new Handler<HttpServerRequest>() {public void handle(final HttpServerRequest req) {// first access the buffer as an observable. We do this this way, since// we want to keep using the matchhandler and we can't do that with rxHttpServerObservable<Buffer> reqDataObservable = RxSupport.toObservable(req);// after we have the body, we update the element in the databaseObservable<RxMessage<JsonObject>> updateObservable = reqDataObservable.flatMap(new Func1<Buffer, Observable<RxMessage<JsonObject>>>() {@Overridepublic Observable<RxMessage<JsonObject>> call(Buffer buffer) {System.out.println("buffer = " + buffer);// create the messageJsonObject newObject = new JsonObject(buffer.getString(0, buffer.length()));JsonObject matcher = new JsonObject().putString("_id", req.params().get("id"));JsonObject json = new JsonObject().putString("collection", "zips").putString("action", "update").putObject("criteria", matcher).putBoolean("upsert", false).putBoolean("multi", false).putObject("objNew", newObject);// and return an observablereturn rxEventBus.send("mongodb-persistor", json);}});// use the previous input again, so we could see whether the update was successful.Observable<RxMessage<JsonObject>> getLatestObservable = updateObservable.flatMap(new Func1<RxMessage<JsonObject>, Observable<RxMessage<JsonObject>>>() {@Overridepublic Observable<RxMessage<JsonObject>> call(RxMessage<JsonObject> jsonObjectRxMessage) {System.out.println("jsonObjectRxMessage = " + jsonObjectRxMessage);// next we get the latest version from the database, after the update has succeeded// this isn't dependent on the previous one. It just has to wait till the previous// one has updated the database, but we could check whether the previous one was successfullyJsonObject matcher = new JsonObject().putString("_id", req.params().get("id"));JsonObject json2 = new JsonObject().putString("collection", "zips").putString("action", "find").putObject("matcher", matcher);return rxEventBus.send("mongodb-persistor", json2);}});// after we've got the latest version we return this in the response.getLatestObservable.subscribe(new Action1<RxMessage<JsonObject>>() {@Overridepublic void call(RxMessage<JsonObject> jsonObjectRxMessage) {req.response().end(jsonObjectRxMessage.body().encodePrettily());}});}});仍然是一大段代碼,但是大多數都是注釋,并且是由Java不支持閉包(實際上)引起的。 那么這里發生了什么?
這意味著我們希望在請求緩沖區中的數據可用時得到通知。
功能。 這使我們可以指定當先前創建的可觀察對象上有一些數據可用時會發生什么。 因此,我們沒有嵌套回調,而是通過各種異步調用指定了數據流。 收到數據后,我們將使用它來更新數據庫。 請注意,我們使用
rxEventBus.send方法。 這還沒有進行呼叫,但是再次返回了一個可觀察的。
函數并“等待”(仍然是非阻塞)以獲取最終數據庫讀取的結果。 一旦收到,我們將根據收到的消息將響應發送回去。
在此示例中,我們僅展示了rxjava的幾個非常小的部分:
- 我們使用了可觀察對象,使異步操作的工作和排序變得更加容易。
- 我們使用flatmap函數將結果從一個異步調用傳遞到另一個異步調用,從而消除了嵌套回調
- 我們使用rxSupport和rxEventbus rxJava vert.x擴展來輕松創建rxJava可觀察對象
- 然后,我們通過訂閱鏈中的最后一個可觀察到的序列開始了完整的序列
在以后的文章中,我們將對rxJava進行更深入的研究,以了解如何組織更復雜的異步流。
翻譯自: https://www.javacodegeeks.com/2013/12/create-a-simpe-restful-service-with-vert-x-2-0-rxjava-and-mongodb.html
總結
以上是生活随笔為你收集整理的使用vert.x 2.0,RxJava和mongoDB创建simpe RESTful服务的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 拉曼拉是什么 拉曼拉的简介
- 下一篇: 波罗蜜多什么意思 波罗蜜多的意思