Download presentation
Presentation is loading. Please wait.
1
AJAX 的 client/server 溝通機制探究
馮彥文 隨想行動科技
2
講師介紹 馮彥文 隨想行動科技 Javaworld.tw: tempo Email: yenwen.feng@willmobile.com
Blog:
3
這個故事, 就從兩個技術人在一次研討會中的偶然相遇開始…
4
傑克: Hi 珍妮佛, 你知道這個 session 最主要是講?
5
內容主題 AJAX AJAX Framework
利用 AJAX 提高網站與使用者的互動性 (Rich Internet Application) User Interface: DHTML 非同步傳輸: XMLHttpRequest (XHR) 與其他方式, 與他們的黑暗面 AJAX Framework 學習如何利用 DWR(Direct Web Remoting) 來簡化 AJAX 與 Java 間的網路存取, 且為網站增添更多功能 AJAX / Reverse AJAX
6
我們的目標 即時股市報價 http://www.marketwatch.com
7
我們的目標 Web 聊天室
8
What We Will Focus on Here
Browser Compatibility, Cross-Domains, Java Data Marshalling, JSON, JSON-RPC, DOJO, DWR, GWT, iframe, Prototype, Timeout & Error Handling, Reverse AJAX, History & Bookmarks, scriptTag, Web Framework Integration, XHR, XML
9
AJAX 非同步傳輸 1:35
10
珍妮佛: 什麼是 AJAX? 什麼又是非同步傳輸?
11
Asynchronous JavaScript And XML XHTML&CSS DOM JavaScript
AJAX AJAX = DHTML + XHR Asynchronous JavaScript And XML XHTML&CSS DOM JavaScript XMLHttpRequest
12
Classic Web Applications
From:
13
AJAX Web Applications From:
14
傑克: 那我該如何利用 AJAX 存取遠端網站資料呢?
15
XHR(XMLHttpRequest) JavaScript 版的 HttpConnection 介面
open(string url,string asynch): 開啟網頁 send(string): 傳送資料 onreadystatechange: 狀態改變回呼函式 status: HTTP 狀態 responseXML: 回傳的 XML DOM responseText: 回傳的文字內容
16
XHR 使用者輸入觸動 XHR // 建立 XHR request = new XMLHttpRequest(); // 設定回呼函式
request.onreadystatechange=handleResponse; // 開啟連結 request.open("GET"," // 傳送資料 request.send(null);
17
XHR 接收資料後立刻更新UI function handleResponse() { // 檢查 XHR 狀態
if(request.readyState == 4){ // 檢查 http 狀態 if(request.status == 200){ // 讀取回傳 XML 資料 var doc = request.responseXML; // 取得網頁上需被更新的 node 位置 var node = document.getElementById(“resp"); // 設定該 node 的內容 node.innerHTML = doc.documentElement.childNodes[0].nodeValue; }
18
DEMO: Hello World
19
Tips & Tricks about XHR 1:40
20
珍妮佛: 傑克, 這真是太神奇了, 但傳輸的資料一定要是 XML 格式嗎?
21
XHR 接受的資料型態 不, XHR 除了 XML 資料之外, 還可以傳送 text, 所以也包括了 HTML, JavaScript (JSON) [{author:‘tempo’, title:‘智者的對談'}, {author:‘browser,koji’, title:‘JSP技術手冊'}, {author:‘caterpillar’, title:‘Spring技術手冊'}, {author:‘piggy’, title:’Java2全方位學習’];
22
傑克: 那所有的瀏覽器都有支援 XHR 嗎?
23
瀏覽器支援 XHR 支援以下瀏覽器 但不同的瀏覽器 XHR 建立方式不同 IE 5.0+ Mozilla 1.0+ Safari 1.2
Konqueor Opera 8.0 但不同的瀏覽器 XHR 建立方式不同 IE: ActiveX Others: JavaScript
24
瀏覽器支援 function httpRequest(reqType,url){
if(window.XMLHttpRequest){ // Mozilla, Opera, Safari, … request = new XMLHttpRequest(); } else if (window.ActiveXObject){ // IE request=new ActiveXObject("Msxml2.XMLHTTP"); if (!request){ request=new ActiveXObject("Microsoft.XMLHTTP"); } if(request){ … } else { alert("Your browser does not permit the use of all "+ "of this application's features!");
25
珍妮佛: 真奇怪, 我使用 XHR, 瀏覽器卻一直跳出安全性問題?
26
跨網域支援 有可能是其他問題, 但 XHR 限制僅能存取該網站上的資料, 無法存取其他網站的資料
For example, 若此網頁的網址為 則 XHR: 不可存取: test.abc.com/*, abc.com/* 可存取: AJAX SOA?
27
傑克: 少來了 tempo, 明明除了 XHR 之外, 還有其它方式來存取網站資料
28
<iframe>與<script>
29
<iframe>與<script>使用
var sObj = document.createElement('iframe'); sObj.src = ‘ sObj.onload = function() { iframe_loaded( sObj ); }; document.body.appendChild( sObj ); var sObj = document.createElement('script'); sObj.src = ‘ document.body.appendChild( sObj );
30
<iframe>與<script>資料接收
回傳資料為 HTML 格式 <script> 回傳資料為 JavaScript 格式 但都可以經過額外的步驟轉換為 XML 或 JavaScript
31
<iframe>與<script>優缺點
優點 可以跨網域存取資料, 不像 XHR 有限制 <iframe> 瀏覽過的網頁會被加入瀏覽器的歷史紀錄內 支援較多的瀏覽器 缺點 使用起來較繁瑣 僅支援 HTTP GET
32
tempo: 那我來做個整理吧
33
各種方法比較
34
小細節需要注意 三種傳輸方式 三種資料格式 跨網域問題 瀏覽器支援問題 上一頁/下一頁與書籤問題*
XHR, <iframe>, <script> 三種資料格式 XML, HTML, JavaScript 跨網域問題 瀏覽器支援問題 上一頁/下一頁與書籤問題*
35
珍妮佛: 好吧 tempo, 這太複雜了, 我只是想要存取網站上的資料而已
36
透過 AJAX Framework 來做非同步傳輸
XHR, <iframe>, <script> 各有不同的優點與缺點 瀏覽器有不同的 bugs 與標準 自行維護非同步傳輸底層不容易
37
透過 AJAX Framework 來做非同步傳輸
現有的AJAX Framework都有提供自己的XHR Utility或包裝 Framework: Google Web Toolkit, ZK, Dojo, … RPC: DWR, JSON-RPC, … Libraries: Prototype, … DWR 是其中最專業也是支援最廣的 AJAX 非同步傳輸 Framework
38
Direct Web Remoting 1:50
39
傑克: 什麼是 DWR 呢?
40
DWR(Direct Web Remoting)
RPC-Style AJAX Easy AJAX for Java Easy to integrate AJAX: Expose Java to the Browser Reverse AJAX: Expose JavaScript to the Server
41
DWR From:
42
珍妮佛: 我也想試試 DWR, 我該如何安裝呢?
43
Step 1: Download 從網站下載 DWR: http://getahead.ltd.uk/dwr/download
Copy dwr.jar into WEB-INF/lib 2:00
44
Step 2: web.xml 修改 web.xml, 新增 DwrServlet <servlet>
<servlet-name>dwr-invoker</servlet-name> <display-name>DWR Servlet</display-name> <servlet-class> org.directwebremoting.servlet.DwrServlet </servlet-class> <init-param> <param-name>debug</param-name> <param-value>true</param-value> </init-param> </servlet> <servlet-mapping> <url-pattern>/dwr/*</url-pattern> </servlet-mapping>
45
Step 3: dwr.xml 將遠端 Java 物件註冊到 dwr.xml <dwr> <allow>
<create creator="new" javascript="JDate"> <param name="class" value="java.util.Date"/> </create> </allow> </dwr>
46
DEMO: Installation
47
DWR 除錯視窗 在 web.xml 設定 init-param, ‘debug’ = true
顯示註冊在 dwr.xml 的物件與提供直接測試用 請不要在正式環境使用!!! <init-param> <param-name>debug</param-name> <param-value>true</param-value> </init-param>
48
建民: 那 tempo, 你應該要講怎麼做 Hello World 了吧?
2:05
49
Step1: 建立伺服器端的 Java 物件 package com.willmobile.ajaxtm;
public class HelloWorld { public String sayHelloWorldTo(String name) { return "Hello World " + name + "!"; }
50
Step2: 在 dwr.xml 中註冊類別 在 dwr.xml 的 <allow> 內建立 <create>
<create creator="new“ javascript="HelloWorld" scope="page"> <param name="class" value="com.willmobile.ajaxtm.HelloWorld" /> </create> </allow> </dwr>
51
Step3: 在網頁中 include JavaScript
engine.js 與 util.js 是 dwr 的公用 script HelloWorld.js 是我們註冊的遠端物件 script <head> <script type='text/javascript' src='/dwr-helloworld/dwr/interface/HelloWorld.js'/> <script type='text/javascript‘ src='/dwr-helloworld/dwr/engine.js‘/> src='/dwr-helloworld/dwr/util.js‘/> </script> </head>
52
Step4: 撰寫 client 端 JavaScript
<head> <script type="text/javascript"> window.onload = function() { functon callback(str) { $('output').innerHTML = str; } HelloWorld.sayHelloWorldTo("JavaTwo 2006", callback); </script> </head>
53
遠端物件方法呼叫方式 參數與一般呼叫方式相同 回傳值使用 callback function, 放在最後一個參數
用 Meta-data Object 定義 callback function public class Remote { public String getData(int index) { ... } } function handleGetData(str) { alert(str); } Remote.getData(42, handleGetData);
54
Demo: Hello World http://localhost:8080/dwr-helloworld/
55
Tips & Tricks about DWR 2:15
56
傑克: 可以讓遠端 Java 物件存放在 session 或 application scope 嗎?
57
設定遠端物件的 Scope 物件的 scope 可以透過 dwr.xml 內的 create 屬性設定
application, session, request, page <dwr> <allow> <create creator="new“ javascript="HelloWorld" scope="page"> <param name="class" value="com.willmobile.ajaxtm.HelloWorld" /> </create> </allow> </dwr>
58
珍妮佛: 參數可以是自訂的類別嗎?
59
Converters 定義在 dwr.xml 中描述 remote 物件 var r = Remote.method(param);
Uses a Converter Uses a Creator From:
60
Converters 自動轉換 預設 Converters Primitive Type (與他們對應的 class 型態) String
Date 預設 Converters Bean/Object Converter Array/Collection Converter Dom Objects Enum Converter
61
Converters設定 在 dwr.xml 的 <allow> 內建立 <convert> <dwr>
<create> … </create> <convert converter="bean“ match="com.willmobile.ajaxtm.User"> </convert> </allow> </dwr>
62
傑克: 任何遠端 Java 物件上的方法都可以呼叫嗎?
63
<include>, <exclude>
可在 dwr.xml 中設定遠端 Java 物件存取的權限 <dwr> <allow> <create creator="new“ javascript="HelloWorld" scope="page"> <param name="class" value="com.willmobile.ajaxtm.HelloWorld" /> <exclude method=“noUse"/> </create> <convert converter="bean“ match="com.willmobile.ajaxtm.User"> <param name="exclude" value="password"/> </convert> </allow> </dwr>
64
tempo: 那該輪到做一個 Web Form 來試試看
2:20
65
Step1: 建立伺服器端的 Java 物件 public class User { private String id;
private String password; private String name; private String title; … }
66
Step2: 建立伺服器端的 Java 物件 public class UserManager {
private final List<User> users = new ArrayList<User>(); public synchronized void add(User user) { users.add(user); } public synchronized List<User> getAll() { return new ArrayList<User>(users);
67
Step3: client script function addUser() {
var user = { id:"", name:"", title:"" }; DWRUtil.getValues(user); UserManager.add(user); UserManager.getAll(fillTable); } var cellFuncs = [ function(data) { return data.id; }, function(data) { return data.name; }, function(data) { return data.title; } ]; function fillTable(users) { DWRUtil.removeAllRows("usersBody"); DWRUtil.addRows("usersBody", users, cellFuncs);
68
Demo: DWR Form
69
Reverse AJAX 2:25
70
珍妮佛: 我也會做 jsp 的聊天室呀, 你前面的 Demo 有比較好嗎?
71
Reverse AJAX AJAX(與一般 WEB 應用) Reverse AJAX
由瀏覽器發動每個需求, 伺服器不能主動傳給瀏覽器任何資料 Pull Model Reverse AJAX 伺服器可主動傳送資訊至瀏覽器顯示或執行 Push Model (但其實是用 pull 模擬) Polling Comet(Long Live HTTP)
72
Polling 瀏覽器 伺服器 1.新資料到 2.新資料傳至瀏覽器 3.顯示 N秒送出一個 req1 request req2 req3
73
Comet 瀏覽器 伺服器 req1 2.新資料傳至瀏覽器 1.新資料到 3.顯示 req2
74
Reverse AJAX DWR 將這些複雜的操作隱藏起來 Comet(Long Live HTTP) Polling
Server Push JavaScript 至 Client ScriptSession.addScript("alert('Hi')");
75
Reverse AJAX 適合需要即時回應的網路應用 股市資訊 線上遊戲 聊天交友 會員客戶服務
76
珍妮佛: 我也想做像前面 Demo 那樣的聊天室~~
77
Step1: 建立伺服器端的 Java 物件 public void addMessage(String text) { …
final WebContext wctx = WebContextFactory.get(); // For all the browsers on the current page: String currentPage = wctx.getCurrentPage(); Collection sessions = wctx.getScriptSessionsByPage(currentPage); DwrUtil utilAll = new DwrUtil(sessions); utilAll.removeAllOptions("chatlog"); utilAll.addOptions("chatlog", messages, "text"); }
78
Step1: 建立伺服器端的 Java 物件 <script type="text/javascript">
window.onload = function() { DWREngine.setReverseAjax(true); Chatroom.getAllMessages(function(messages) { DWRUtil.removeAllOptions('chatlog'); DWRUtil.addOptions( 'chatlog', messages, 'text'); }); } function sendMessage() { Chatroom.addMessage(DWRUtil.getValue("text")); </script>
79
Demo: DWR Chat http://localhost:8080/dwr-chat/before.jsp
80
傑克: 那你之前 Demo 的股市報價, 也是用同一種技術囉?
2:30
81
Step1: 建立伺服器端的 Java 物件 private class SendTickerDataTask
extends TimerTask { public void run() { ServerContext sctx = ServerContextFactory.get(servletContext); Collection sessions = sctx.getScriptSessionsByPage( “/dwr-reverse/after.jsp”); DwrUtil pages = new DwrUtil( sessions, servletContext); pages.setValue(symbol, RandomStockSnapshot. getRandomStockSnapshotString(symbol)); }
82
Demo: DWR Reverse http://localhost:8080/dwr-reverse/before.jsp
83
Web Framework Integration
2:35
84
珍妮佛: 我不想呼叫物件, 我想把整個網頁 include 進來, 這可以嗎?
85
AJAX Includes 可以, DWR 提供 Server-side Include Server Browser
public String getInclude() { return WebContextFactory.get() .forwardToString("/forward.jsp"); } function update() { Demo.getInclude(function(html) { DWRUtil.setValue("somediv", html); } );
86
傑克:這樣也行, 那我想要呼叫我伺服器上的 spring beans, 不會也可以吧?
87
Spring Integration SpringCreator web.xml <allow>
<create creator="spring" javascript="Fred"> <param name="beanName" value="Shiela"/> </create> </allow> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/classes/beans.xml</param-value> </context-param>
88
珍妮佛:好吧, 那像 Struts, Webwork 應該也不是問題囉?
89
Struts Integration StrutsCreator Webwork
整合至 Action 層, 可透過 JavaScript 直接將 form 丟給 Action <allow> <create creator="struts" javascript="Fred"> <param name="beanName" value="Shiela"/> </create> </allow>
90
其他的功能 2:40
91
傑克: 我想要連續呼叫三個遠端函式, 這樣使用者會等比較久嗎?
92
Batching 會的, 所以若需要將數個 dwr 功能一次送出, 請將需要在同一個交易內的功能放到 Batch 中
beginBatch(); … endBatch();
93
珍妮佛: 我看你的網頁右上方都有像 gmail 一樣的 loading message, 我也要
94
Loading Message 請在網頁 onLoad 時呼叫 useLoadingMessage() 即可
DWRUtils.useLoadingMessage(); Or DWRUtils.useLoadingMessage(‘Waiting…’);
95
傑克: 你都沒有提到錯誤處理機制 :(
96
Error Handling Global Error (Exception) Handling Meta Data
function handler(msg) { alert(msg); } DWREngine.setErrorHandler(handler); Remote.method(params, { callback:function(data) { ... }, errorHandler:handler });
97
傑克: 哇, DWR/AJAX 真棒, 可是back/forward 鍵沒用了 :(
98
瀏覽器歷史紀錄問題 XHR 或是 <script> 都無法將連線網頁加入瀏覽器歷史紀錄內
Really Simple History
99
珍妮佛: 以上提到的方法所有瀏覽器都支援嗎?
100
瀏覽器支援 DWR 支援以下瀏覽器 IE 5.5+ Firefox 1.0+ Mozilla 1.7+ Safari 1.2+
Konqueor Opera (但現在不支援 Reverse AJAX)
101
傑克: 我已經有使用其他 framework 了, 那我該如何整合 DHR 呢?
102
DWR 與其它 AJAX Framework JavaScript Libraries 不會有影響
Dojo Toolkit Prototype Script.aculo.us AJAX Framework 則請使用原本提供的存取方式 GWT ZK 2:45
103
Thank you! 如果你流落荒島, 但是只能帶一個 AJAX Framework, 建議你帶 DWR 馮彥文
104
我想請教關於..
Similar presentations