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灯, 水草

请输入看板名称,例如:BuyTogether站内搜寻

TOP