java 板


LINE

Blog 版:http://blog.dontcareabout.us/2013/07/gwt-websocket.html BBS 版以 markdown 格式撰寫 ______________________________________________________________________ 前言 ==== 這一陣子因為專案需要 server 與 browser 之間有即時雙向溝通的能力, 所以就用了 websocket。 又由於 server 端綁定 PHP(還好 browser 也綁定 Chrome XD), 再加上傳輸的資料<strike>還</strike>沒有很複雜,單純字串就可以解決, 所以沒有用現有的 GWT websocket library,統統自己來了...... [遮臉] 於是也就順便寫了這篇文章,借 websocket 介紹下面兩個主題: 1. GWT 如何整合 JavaScript 程式碼(JSNI) 1. EventHandler 的使用 (當然行有餘力的話也想涵蓋 GWT RPC,不過目前無法) 這三個主題在作〈[GWT 版 GAE Channel API]〉的時候都有用到 (但是 RPC 的部份只抄其 code、不明其理 [遮臉]), 不過拿 websocket 來介紹可能比較實在一點, GAE 的 channel API 可能太少人用了 [死]。 [GWT 版 GAE Channel API]: http://blog.dontcareabout.us/2012/04/gwt-gae-channel-api.html webocket ======== 因為我們要用 GWT 把 websocket 給包起來, 所以還是得理解一下 websocket client 端的行為。 // ======== JavaScript code ======== // //建立 websocket,目前似乎 FOO_PATH 打啥都沒差, //主要還是看 address 跟 port 號 var websocket = new WebSocket("ws://localhost:8000/FOO_PATH"); websocket.onopen = function(evnt) { alert("connected!"); } websocket.onmessage = function(evnt) { alert("Receive : " + evnt.data); } //其他還有 websocket.onerror 跟 websocket.onclose,自己比照辦理 //送資料 websocket.send(SOMETHING); 大抵上可以望文生意,就不特別作解釋了 [逃] JSNI ==== JSNI 全名 JavaScript Native Interface, 用不太嚴謹的類比講法就是 GWT 中的 JNI,不過沒有 JNI 那麼複雜。 畢竟從 GWT compile 完的最終結果來看,所有程式碼統統會變成 JavaScript, 沒有 JavaScript 反向呼叫 Java code 的問題,因此單純很多。 開發人員可以透過 JSNI 把某一些 JavaScript 程式碼重新包裝成 Java code, 然後就可以完全用 Java 的思維與寫法去使用它(其實 GWT 底層滿滿的都是 JSNI)。 例如 JavaScript 當中常用的 `console.log()`,就可以這樣包起來: // ======== Java code ======== // public class Console { public static native void log(String message) /*-{ $wnd.console.log(message); }-*/; } //使用 Console.log("hello world"); 完整的 JSNI 文件可以參閱 [GWT 文件], 或是這兩篇中文 Blog:[DontCare 1]、[DontCare 2]。 這篇文章只針對必要的部份作講解。 (其實也沒什麼好講的 XD) [GWT 文件]: http://www.gwtproject.org/doc/latest/DevGuideCodingBasicsJSNI.html [DontCare 1]: http://blog.dontcareabout.us/2010/02/gwt-part-1jsni_8514.html [DontCare 2]: http://blog.dontcareabout.us/2010/02/ gwt-part-2javascript-overlay-type_9960.html 要把 JavaScript 的 websocket 包起來,會稍微複雜一點。 首先必須得要建立一個 `JsWebSocket` 物件像這樣: // ======== Java code ======== // class JsWebSocket extends JavaScriptObject { //必須要有一個 protected 的 contructor protected JsWebSocket() {} //將 WebSocket.send() 包成 Java method public native final void send(String msg) /*-{ this.send(msg); }-*/; } `JsWebSocket` 算是 Java object 與 JavaScript object 中間的橋樑, 畢竟以 Java 的角度,必須要明確定義 class 有哪些 method 與 field, 所以包一個 class 來滿足這個需求。 再來是我們真正要在程式當中使用的 `WebSocket`: // ======== Java code ======== // package psmonkey.client.websocket; public class WebSocket { private String uri; private JsWebSocket jsWebSocket; public WebSocket(String uri) { this.uri = uri; } public void send(String msg) { jsWebSocket.send(msg); } public native void open() /*-{ //在 native method 當中就是寫 JavaScript var websocket = new $wnd.WebSocket( [email protected]::uri ); [email protected]::jsWebSocket = websocket; //直接複製貼上剛剛的 JavaScript 碼 websocket.onopen = function(evnt) { alert("connected!"); } websocket.onmessage = function(evnt) { alert("Receive : " + evnt.data); } //onerror、onclose 繼續跳過 XD }-*/; } 關鍵點在於 `open()` 這個 method。 首先,透過 `this.@PACKAGE_NAME.CLASS_NAME::FIELD_NAME` 這種扭曲的方式, 我們可以在 native method 當中存取 Java code 的 field; 而 `jsWebSocket` 也是用這樣的方式 assign 值。 然後我們就可以用很 Java 的方式來作到一開始 JavaScript 程式碼的功能: // ======== Java code ======== // WebSocket websocket = new WebSocket("ws://localhost:8000/FOO_PATH"); websocket.open(); websocket.send(SOMETHING); 但是這樣還不夠 Java, 因為 `onopen`、`onmessage` 的行為都還是用 JavaScript 寫。 所以接下來要把這部份也給 Java 化 // ======== Java code ======== // //in class : WebSocket public native void open() /*-{ //在 native method 當中就是寫 JavaScript var websocket = new $wnd.WebSocket( [email protected]::uri ); [email protected]::jsWebSocket = websocket; var self = this; websocket.onopen = function(event) { [email protected]::onOpen()(); } websocket.onmessage = function(event) { [email protected]::onMessage( Ljava/lang/String;)(event.data); } }-*/ public void onOpen() { Window.alert("connected!"); } public void onMessage(String data) { Window.alert("Receive : " + data); } 一樣也是 `this.@PACKAGE_NAME.CLASS_NAME::METHOD_NAME` 這種扭曲的方式, 可以在 native method 當中去指定要呼叫的 Java method。 如此一來,後頭就都是 Java 的事情了! .... to be continue -- 錢鍾書: 說出來的話 http://www.psmonkey.org 比不上不說出來的話 Java 版 cookcomic 版 只影射著說不出來的話 and more...... --



※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 114.25.4.52
1F:推 johnny1972: 雖然我java很差,不過這篇給了我不少其他靈感,感謝 07/06 11:49
2F:→ PsMonkey:敢問靈感是指? 07/06 12:25
3F:推 tails32100:猴大先推倒再說 [被踹飛] 07/06 15:42
4F:推 gmoz:讚 07/06 20:34
5F:推 cuteclare:膜拜~ 07/06 20:34
6F:推 s3748679:<~ 剛看成: tails32100:先推倒猴大再說 [被踹飛] 07/06 21:34
7F:推 moonjuice:原來還可以這樣結合喔@@ 07/06 22:32
8F:推 cuteclare:最後一段code少了-*/; 07/07 17:27
修正 cateclare 提醒的錯誤以及一些排版 ※ 編輯: PsMonkey 來自: 1.162.248.88 (07/08 11:14)







like.gif 您可能會有興趣的文章
icon.png[問題/行為] 貓晚上進房間會不會有憋尿問題
icon.pngRe: [閒聊] 選了錯誤的女孩成為魔法少女 XDDDDDDDDDD
icon.png[正妹] 瑞典 一張
icon.png[心得] EMS高領長版毛衣.墨小樓MC1002
icon.png[分享] 丹龍隔熱紙GE55+33+22
icon.png[問題] 清洗洗衣機
icon.png[尋物] 窗台下的空間
icon.png[閒聊] 双極の女神1 木魔爵
icon.png[售車] 新竹 1997 march 1297cc 白色 四門
icon.png[討論] 能從照片感受到攝影者心情嗎
icon.png[狂賀] 賀賀賀賀 賀!島村卯月!總選舉NO.1
icon.png[難過] 羨慕白皮膚的女生
icon.png閱讀文章
icon.png[黑特]
icon.png[問題] SBK S1安裝於安全帽位置
icon.png[分享] 舊woo100絕版開箱!!
icon.pngRe: [無言] 關於小包衛生紙
icon.png[開箱] E5-2683V3 RX480Strix 快睿C1 簡單測試
icon.png[心得] 蒼の海賊龍 地獄 執行者16PT
icon.png[售車] 1999年Virage iO 1.8EXi
icon.png[心得] 挑戰33 LV10 獅子座pt solo
icon.png[閒聊] 手把手教你不被桶之新手主購教學
icon.png[分享] Civic Type R 量產版官方照無預警流出
icon.png[售車] Golf 4 2.0 銀色 自排
icon.png[出售] Graco提籃汽座(有底座)2000元誠可議
icon.png[問題] 請問補牙材質掉了還能再補嗎?(台中半年內
icon.png[問題] 44th 單曲 生寫竟然都給重複的啊啊!
icon.png[心得] 華南紅卡/icash 核卡
icon.png[問題] 拔牙矯正這樣正常嗎
icon.png[贈送] 老莫高業 初業 102年版
icon.png[情報] 三大行動支付 本季掀戰火
icon.png[寶寶] 博客來Amos水蠟筆5/1特價五折
icon.pngRe: [心得] 新鮮人一些面試分享
icon.png[心得] 蒼の海賊龍 地獄 麒麟25PT
icon.pngRe: [閒聊] (君の名は。雷慎入) 君名二創漫畫翻譯
icon.pngRe: [閒聊] OGN中場影片:失蹤人口局 (英文字幕)
icon.png[問題] 台灣大哥大4G訊號差
icon.png[出售] [全國]全新千尋侘草LED燈, 水草

請輸入看板名稱,例如:Soft_Job站內搜尋

TOP