首先, 我必須承認,作為一個有著十多年開發經驗的java開發者,我已經形成了解決絕大部分問題的固有套路,儘管它們很多時候顯得笨重和繁瑣。 比如說如果要讀取一個文件,那應該就是初始化一個BufferedReader 實例並傳入一個FileReader,這幾乎是順理成章的,我在很多自認為算得上「企業級」的專案中編寫這樣的程式碼並且很享受這個過程,可以說我就是一個對其他語言不屑一顧的java腦殘粉。
如果你正在閱讀這篇博文,你可能已經陷入了我多年前早就陷入的一個誤區,作為一名合格的開發人員應該不斷地學習新的技術並且根據實際工作需求選用適當的技術。儘管我一直在變老並且有朝一日可能會厭煩了java。但是我現在真的發現了一個令人興奮的新東西,node.js對於我就像一個兒童得到一個新奇的玩具,在這篇博文中,我將先向您展示如何使用Java EE創建一個簡單的Rest服務來讀取MongoDB資料庫。然後我會用node.js來實現相同的功能,你會更容易了解到這種新的開發語言的激動人心之處。
從基礎開始――什麼是Node.js?
首先,我要說明一點,Node.js不是那種“新潮時尚”,只有“潮人”才使用的語言。雖然它是本著這種認知開始,但是我很高興的報告給大家,Node.js是一種成熟的語言――並且在當下這個互聯網時代,它已經找到了其自己的方式進入大型企業,支撐起一些最高流量的網站。 Node.js是你技能儲備當中的一個非常實用的工具,在建立穩定、安全且高效能的程式碼上,其便利度會讓你大吃一驚。
言而總之,Node是一種針對伺服器端活動的語言。它使用了Javascript語言,並且有非常多的函式庫可用,例如npm模型。你可以把那些npm 模型比喻為Java中的.jar套件。當你需要一部分功能,並且不喜歡自己全部寫這部分程式碼,極有可能在npm模型中已經提供了你正在尋找的特性。
Node應用程式通常執行時需要實現效率最大化利用非阻塞I/O 和非同步事件。對於Java開發者來講需要知道的一點是Node應用程式運行單執行緒中。然而,後端節點程式碼使用多個執行緒進行操作,如網路和檔案存取。有鑑於此,Node對於那些需要即時經驗的應用是完美的選擇。
繼續――IDE支持
你可能會像我一樣,在IDE中“生存”和“呼吸”,這可能源於Java實在是太羅嗦了,需要我們在軟體開發過程中編寫恆定的程式碼來完成功能。一旦我們找到了程式碼完成的好處,我們慢慢學會了使用IDE 進行檔案管理、 偵錯和其他非常有用的功能。可以這樣說,我喜歡使用一款IDE並且在使用Nodeb工作時繼續使用它。下面是目前最為第一批支援Node的IDE:
1.Eclipse――這應該很容易上手當你在Java中已經使用它。僅需安裝Node.js外掛程式即可。
2.JetBrains IntelliJ IDEA――一款非常流行的商業化的IDE。到目前為止,這是我最喜歡的IDE。
3.Microsoft Visual Studio――是的,你沒看錯。 Node已經成長到微軟在Visual Studio中增加了對其的原生支援。這個實作非常穩定,並且VS是我第二喜歡的IDE。說來也怪,我使用VS僅僅用作一些基礎的Node專案。
4.CodeEnvy――一款基於web的IDE
5.Cloud9――一款基於web的IDE
6.SublimeText 2――沒有多餘裝飾的文字編輯器,由於其輕量級,在開發者中的知名度越來越高。
這是我工作在Node基礎專案上的最喜歡的幾款IDE。僅做個舉例。
從一個範例開始
在這篇文章的剩餘部分裡,我們將要用Java EE和Node.js結合起來創建一個簡單的REST服務。這個REST服務將會簡單的從MongoDB資料庫裡面讀取資訊並且傳回這些結果給請求者。而關於Java應用伺服器和MongoDB資料庫的安裝和配置則不在本文的討論範圍。
創建我們的Java應用
第一步:配置pom.xml文件
我們把這個範例叫做restexample ,我將會使用JBoss EAP應用伺服器。第一件我們要做的事情就是為使用Maven建置系統的依賴管理來設定我們的pom.xml檔案。以下就是包含了我們這個restexample 應用程式裡面所需要的依賴的pom.xml檔:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http:/ /maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>restexample</groupId> <artifactId>restexample</artifactId> <packaging>war</packaging> <version>1.0</version> <name>restexample</name> <repositories> <repository> <id>eap</id> <url>http://maven.repository.redhat.com/techpreview/all</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>true</enabled> </ snapshots> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>eap</id> <url>http://maven.repository.redhat.com/techpreview/all</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>true</enabled> </ snapshots> </pluginRepository> </pluginRepositories> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.6</maven.compiler.source> <maven.compiler.target>1.6</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.jboss.spec</groupId> <artifactId>jboss-javaee-6.0</artifactId> <version>3.0.2.Final-redhat-4</version> <type>pom</type> <scope>provided</scope> </dependency> <dependency > <groupId>org.mongodb</groupId> <artifactId>mongo-java-driver</artifactId> <version>2.9.1</version> </dependency> </dependencies> </project>
酷,相當的詳細,但是我希望你們能夠理解裡面的程式碼,在這篇文章中我假設讀者都已經了解Java,因此我不准備解釋裡面的細節了。
第二步:建立beans.xml檔案並且設定我們的servlet映射
作為範例的一部分,我們將會對我們的資料庫存取類別使用CDI(上下文依賴注入)。根據官方的CDI配置說明,一個應用程式要使用CDI的話就要在該應用的WEB-INF 目錄裡麵包含一個beans.xml檔。因此我們就來創建這個文件並且按照我們所需的資訊來配置它。進入到你的/src/main/webapp/WEB-INF 目錄然後建立一個beans.xml文件,加入下面的程式碼:
<?xml version="1.0"?><beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema- instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://jboss.org/schema/cdi/beans_1_0.xsd"/>
我們也需要在web.xml 檔案裡面為我們的RESI API設定servlet映射。在/src/main/webapp/WEB-INF 目錄的檔案裡面加入下面的servlet映射元素:
<servlet-mapping> <servlet-name>javax.ws.rs.core.Application</servlet-name> <url-pattern>/ws/*</url-pattern></servlet-mapping>
第三步:建立DBConnection類
到這一步,我們已經建立好專案並且我們的pom.xml檔案已經包含了MongoDB資料庫的驅動依賴,記得要確保所需要的驅動程式已經被打包好在我們的應用程式裡面。下一件事我們就要建立一個類別用來管理資料庫的連線。建立一個新的檔案命名為DBConneection.java,把這個檔案放到/src/main/java/com/strongloop/data 目錄裡面,然後再這個檔案裡面加入下面的程式碼:
注意:要確保你安裝MongoDB資料庫配置好適當的連線授權細節資訊!
package com.strongloop.data; import java.net.UnknownHostException; import javax.annotation.PostConstruct;import javax.enterprise.context.ApplicationScoped;import javax.inject.Named; import com.mongodb。 ; @Named@ApplicationScopedpublic class DBConnection { private DB mongoDB; public DBConnection() { super(); } @PostConstruct public void afterCreate() { String mongoHost = "127.0.0.1" String mongoPort = "27001" String mongoUser = "strong ; String mongoDBName = "restexample"; int port = Integer.decode(mongoPort); Mongo mongo = null; try { mongo = new Mongo(mongoHost, port); } catch (UnknownHostException e) { System.out.println("Couldn't connect to MongoDB: " + e. getMessage() + " :: " + e.getClass()); } mongoDB = mongo.getDB(mongoDBName); if (mongoDB.authenticate(mongoUser, mongoPassword.toCharArray()) == false) { System.out.println("Failed to authenticate DB "); } } public DB getDB() { return mongoDB ; } }第四步:把資料導入到MongoDB中(mmmm啤酒)
在我們的專案中,我們想要載入所有名稱為Pabst的啤酒清單。如果你不熟悉啤酒業,你可以試試Pabst Brewing公司生產的美式淡啤酒。這些啤酒上面有藍瑤帶和柯爾特{敏感字}圖案,他們包含所有的麥芽糖飲料種類。
首先你需要下載一個json文件,裡麵包含所有需要回傳的資料。你可以用下面的URL來實現這一點:
https://dl.dropboxusercontent.com/u/72466829/beers.json
下載結束後,使用mongoimport指令把它匯入到資料庫中,指令如下:
$ mongoimport --jsonArray -d yourDBName -c beers --type json --file /tmp/beers.json -h yourMongoHost --port yourMongoPort -u yourMongoUsername -p yourMongoPassword
你可以看到如下結果:
connected to: 127.0.0.1:27017Tue Jun 10 20:09:55.436 check 9 24Tue Jun 10 20:09:55.437 imported 24 objects
第5步: 建立Beer模型對象
我們已經創建了一個資料庫連接類別並且已經把啤酒資訊載入到MongoDB資料庫裡了,是時候創建一個模型物件來控制我們的啤酒資訊了。建立一個新文件,名為Beer.java並把它放到/src/main/java/com/strongloop/data目錄下。創建好該文件後,在其中添加如下程式碼:
package com.strongloop.data; public class Beer { private String id; private String name; private String description; public String getId() { return id; } public void setId(String id) { this.id = id; } public String; getName() { return name; } public void setName(String name) { this.name = name; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; }}注意: 提供好的JSON檔案中包含了更多我們將會使用到的信息,所以可以找出來看看,並向其中添加一些額外的功能來拓寬你的學習經驗。
步驟6: 建立REST服務
猜猜看該做什麼了?不錯,我們終於準備好要創建基於REST的web服務了,它使我們可以獲取到上一個步驟當中載入進來的啤酒資訊。為此,我們需要建立一個新的名為BeerWS.java的文件,並把它放到/src/main/java/com/strongloop/webservice目錄下。創建好之後,加入下列程式碼:
package com.strongloop.webservice; import java.util.ArrayList;import java.util.List;import javax.enterprise.context.RequestScoped;import javax.inject.Inject;import javax.ws.rs.GET;import javax.inject.Inject;import javax.ws.rs.GET;import javax.ws .rs.Path;import javax.ws.rs.Produces;import javax.ws.rs.QueryParam;import com.strongloop.data.DBConnection;import com.strongloop.data.Beer;import com.mongodb.BasicDBObject;import com.mongodb.DB;import com.mongodb.DBCollection;import com. mongodb.DBCursor;import com.mongodb.DBObject; @RequestScoped@Path("/beers")public class BeerWS { @Inject private DBConnection dbConnection; private DBCollection getBeerCollection() { DB db = db.getDB(); DBCollection beerCollection = db.getCollection(" bollection"); } private Beer populateBeerInformation(DBObject dataValue) { Beer theBeer = new Beer(); theBeer.setName(dataValue.get("name")); theBeer.setDescription(dataValue.get("name")); theBeer.setId(dataValue.get( "_id").toString()); return theBeer; } // 取得所有啤酒@GET() @Produces("application/json") public List<Beer> getAllBeers() { ArrayList<Beer> allBeersList = new ArrayList<Beer>(); DBCollection beers = this.getBeerCollection(); DBCursor cursor = beers.find(); try { while (cursor.hasNext()) { allBeersList.add(this.populateBeerInformation(cursor.next())); } } finally { cursor.close(); } return allBeersList; }}步驟7: 瀏覽著啤酒資訊傻樂
喔,搞定。我們已經寫好了一個REST服務,可以從資料庫中取得所有的啤酒資訊。現在把你的程式碼部署到你的應用程式伺服器吧, 在瀏覽器中開啟下列位址看看它是否運作正常:
http://yourserverlocation/ws/beers
如果所有東西都正常,你將會看到所有的啤酒資訊列表,如下圖所示:
創建Node 應用
如果你按照上面的步驟使用java進行編程,你會意識到使用javaEE創建應用儘管進展很快,但是創建一個類似REST服務的簡單應用還是很麻煩。不要誤會,我仍然很喜歡用javaEE,但發現對於很多場景,例如創建返回json資料的REST服務,Node更適用。接下來,我們將要使用StrongLoop的LoopBack API建立一個簡單的web服務。另外,我會向你展示如何在蘋果OSX系統上安裝Node。
步驟1:安裝Node
最簡單的安裝Node的方式是透過一個相容於大部分作業系統的二進位套件。開啟瀏覽器造訪下面的網頁,根據你的作業系統下載適用的版本:
http://nodejs.org/download/
下載完成後,你會看到下面的內容:
如果你用的是Mac OSX,點選通用的.pkg檔。這會把安裝程式保存到你本機中。下載了該檔案之後,雙擊它就可以啟動安裝程序,你會看到下列安裝對話框:
一路預設的安裝下去,成功安裝之後,點選close按鈕來退出安裝程式。
相當簡單,是吧?
步驟2:使用NPM安裝LoopBack
現在本地系統中已經安裝了Node,接下來要安裝StroopLoop公司提供的LoopBack套件。 LoopBack是一個開放的API源碼包,當你學習使用Node開發、部署軟體時,LoopBack可以讓程式設計更簡單。
為了安裝LoopBack,我們要使用npm命令列,它是Node語言核心的一部分。 NPM是一個官方的套件管理工具,用於安裝應用程式依賴的類別庫或模版。如果你是java程式設計師,你可以把NPM比喻成Maven。使用Maven建構項目,開發人員可以在pom.xml中配置專案所依賴的jar包或模版。當專案開始編譯時,Maven會下載所有依賴的文件,並將jar包引入專案中。 NPM工作原理和Maven相同,對於一些特殊的項目,它使用package.json檔案來配置專案依賴的檔案。你也可以使用命令列方式將依賴的檔案下載到本機系統。如果這些內容你不理解,別擔心,在接下來的步驟裡我們會詳細描述package.json檔案。
為了安裝LoopBack, 我們使用一個簡單的命令列來下載和安裝所有依賴的檔案。打開你的window命令列窗口,輸入下面命令:
$ npm install -g strongloop
提示:安裝時,你可能需要使用其它使用者帳號來執行這個指令。
這個命令列是什麼意義呢? -g參數表示告訴npm我們想要安裝strong-cli套件。 -g參數使這個包對任何系統和應用程式都相容。一旦你運行了上面的命令,NPM會下載所有依賴的檔案。下載的時間視網速而定,可能需要幾分鐘。
步驟3:建立應用程式
使用LoopBack API建立一個應用程式很簡單。 打開你的window命令列窗口,使用下面的命令來創建一個新的應用程式restexample.
$ slc loopback
接下來它會提示輸入項目根路徑的名稱。 在這個範例中,使用restexample。 接下來它會提示輸入應用程式名稱。 使用預設值restexample。
slc命令現在已經創建一個名稱為restexample的LoopBack應用程序,並且已經配置了這個應用程式。 如果再次執行上面的指令,仍然使用restexample命名,LoopBack會建立一個新的目錄。 可以使用cd指令來修改應用程式的根路徑。
$ cd restexample
現在我們已經創建完一個應用程序,接下來我們將MongoDB配置為程式的資料來源。
步驟4:定義資料來源
為了連通MongoDB,我們需要為應用程式增加一個資料來源,執行以下命令即可:
$ slc loopback:datasource
在彈出的提示符號下,可以輸入任意自訂的資料來源名稱,這裡選擇myMongo
[?] Enter the data-source name: myMongo
這樣我們就將後端的資料來源定義附加到由StrongLoop支援的真實連接器上面.這裡我們從清單選擇MongoDB連接器.
[?] Select the connector for myMongo:PostgreSQL (supported by StrongLoop)Oracle (supported by StrongLoop)Microsoft SQL (supported by StrongLoop)MongoDB (supported by StrongLoop)SOAP webservices (supported by StrongLet4 servicesby StrongL8) (LngRESTs Stro provided by community)(Move up and down to reveal more choices)
步驟5:指向真實的資料來源
為了連通MongoDB,我們需要指向真實際的MongoDB實例.LoopBack在datasource.json檔案中定義了所有的資料來源設定資訊.這個檔案位於應用程式的root/server目錄.開啟這個檔案,按照如下的方式,為MongoDB增加一個資料來源:
{ "db": { "name": "db", "connector": "memory" }, "myMongo": { "name": "myMongo", "connector": "mongodb" "url": "mongodb: //localhost:27017/restexample" }}注意:要保證為MongoDB資料庫提供正確的連接URL.針對這個範例,我創建了一個名為restexample 的資料庫,它用來作為資料來源.
步驟6:導入資料到MongoDB(mmmmm 啤酒)
就像本文Java部分說到的那樣,我們需要加載資料集到MongoDB資料庫中.如果你已經按照本文說到的方法完成了這個步驟,然後打算使用同一個資料庫,你可以忽略步驟6,直接跳到步驟7.
首先,你需要下載一個包含所有要回傳資訊的JSON檔,可以從如下的URL取得:
https://dl.dropboxusercontent.com/u/72466829/beers.json
資料集檔案下載完畢後,直接使用如下的mongoimport指令將它載入到資料庫:
$ mongoimport --jsonArray -d yourDBName -c beers --type json --file /tmp/beers.json -h yourMongoHost --port
你應該可以看到如下的結果:
connected to: 127.6.189.2:27017Tue Jun 10 20:09:55.436 check 9 24Tue Jun 10 20:09:55.437 imported 24 objects
步驟7:創造我們自己的啤酒模型
在Java世界裡,由此可以想到對像模型.它代表這一個對象,只是在這裡,這個對像是啤酒.LoopBack通過命令行,提供了一種創建模型對象的簡便方式.打開終端窗口,進入到工程資料夾,輸入如下命令:
$ slc loopback:model
這將會開啟一個互動的會話來定義模型.首先需要輸入的是模型名稱,這裡輸入"beer".接下來會提示,這個模型應該附加到的資料來源,這裡選擇之前建立的myMongo資料來源.
[?] Enter the model name: beer[?] Select the data-source to attach beer to:db (memory)myMongo (mongodb)
接下來提示,是否透過REST將此API暴露出來.當然,這裡希望這樣.
[?] Expose beer via the REST API? Yes
最後,為模型選擇網路複數名,這裡模型名為beer,所以複數為beers(預設).敲擊Enter鍵接受預設值.
[?] Custom plural form (used to build REST URL):
接下來會提示定義模型屬性.對這個範例程式,我們專注於名稱和對啤酒的描述.
Enter an empty property name when done.[?] Property name: name
只要敲擊了Enter,就會提示輸入各個指定屬性的資料類型.第一個項目是name,這裡選擇字串類型.選擇字串類型,然後敲擊
Enter.[?] Property type: (Use arrow keys)stringnumberbooleanobjectarraydatebuffergeopoint(other)
接下來,按照同樣的方式創建description屬性,接著會要求輸入資料類型.它同樣是一個字串類型,選擇字串選項,然後敲擊
Enter.Let's add another beer property.Enter an empty property name when done.[?] Property name: descriptioninvoke loopback:property[?] Property type: string[?] Required? Yes
恭喜!你已經使用LoopBack結合Node完成了模型對象的創建.如果想查看在這個過程中真正創建了什麼,可以打開位於應用程序root/common/models目錄的beer.json文件,滾動到這個文件的最後,將會看到以下模型:
{ "name": "beer", "base": "PersistedModel", "properties": { "name": { "type": "string", "required": true }, "description": { "type" : "string", "required": true } }, "validations": [], "relations": {}, "acls": [], "methods": []}這裡可以看到,我們創建了一個模型,同時,name和description屬性已經賦予了這個模型.
在/server/model-config.js檔案中,可以注意到,檔案中包含一些額外的欄位,包括public和datasource.其中public域指定我們希望透過一個REST網路服務將此模型暴露給外部.datasource域則指定這個模型的CRUD操作將會用到的資料來源.
"beer": { "dataSource": "myMongo", "public": true }步驟8:沉浸在看到beers的喜悅中
恭喜!你已經創建了第一個Node.js應用程式,其中包含可以獲取beer資訊的REST網路服務.最後,我們需要做的就是部署這個應用程式.
慶幸的是,部署是已經很容易的事情.可以透過在應用程式根目錄執行以下指令來完成:
$ slc run
只要應用程式一運行,就可以透過瀏覽器轉到如下的URL來確認部署是否成功:
http://0.0.0.0:3000/api/beers
相當酷,是不是?
LoopBack同時也包含了一個允許查看應用程式所有可用服務的頁面,包括Beer模型和我們創建的REST服務,將瀏覽器指向如下的URL即可查看:
http://0.0.0.0:3000/explorer
頁面載入成功後,你會看到下面的介面,我們已經創建了beers節點作為博客的一部分,我把/beers端點進行高亮顯示了:
你可以點選/beers來展開可供呼叫的API,你可以操作並測試一下,如下圖所示:
結論
在這篇文章中,我展示瞭如何使用java EE 去創建一個rest服務,這個服務能夠返回Pabst啤酒公司的啤酒產品清單資料。 之後我又使用node.js以及基於node.js的loopback框架使用很少的程式碼實現了相同功能的rest服務。 最重要的是,LoopBack API 也對beer實體的增刪查改提供了預設的實現,使得我們不用再寫一行程式碼就得到了一個具有完整增刪查改功能的rest服務。
下面的清單對博文中涉及的javaEE和node.js各自特性進行一個對比:
Feature | Java EE | Node.js |
完善的IDE支持 | Yes, 多種IDE供選擇,包括Eclipse, Sublime and Idea | Yes,多種IDE可供選擇,Visual Studio, Eclipse, Sublime |
依賴管理 | Maven | NPM |
有企業級專案採用 | Yes | Yes |
龐大的組件生態系統 | Yes | Yes |
需要JVM | Yes | No |
通用開發框架 | Spring, JEE | Express |
資料庫支援 | Yes | Yes |
ORM 框架 | Yes | Yes |
測試框架 | Yes | Yes |
接下來的內容?
即將發布的Node v0.12 將帶來至少8個令人興奮的新特性,它們會是什麼呢?造訪「What's New in Node.js v0.12」 頁面以了解更多.
對Node相關的培訓和認證感興趣? StrongLoop 公司提供各種服務滿足您的需求。