Ajax Transportation Methods

You might also like

Download as ppt, pdf, or txt
Download as ppt, pdf, or txt
You are on page 1of 104

AJAX 的

client/server 溝通
機制探究

馮彥文
隨想行動科技
講師介紹

• 馮彥文
• 隨想行動科技
• Javaworld.tw: tempo
• Email:
yenwen.feng@willmobile.com
• Blog: http://
www.pocketshark.com/blog/page/t
2
這個故事 , 就從兩個技術人在
一次研討會中的偶然相遇開始…

3
傑克 : Hi 珍妮佛 ,
你知道這個 session 最主要
是講 ?

4
內容主題
• AJAX
– 利用 AJAX 提高網站與使用者的互動性
(Rich Internet Application)
– User Interface: DHTML
– 非同步傳輸 : XMLHttpRequest (XHR) 與
其他方式 , 與他們的黑暗面
• AJAX Framework
– 學習如何利用 DWR(Direct Web
Remoting) 來簡化 AJAX 與 Java 間的
網路存取 , 且為網站增添更多功能
– AJAX / Reverse AJAX
5
我們的目標
• 即時股市報價
– http://www.marketwatch.com
– http://localhost:8080/dwr-reverse/before.jsp
– http://localhost:8080/dwr-reverse/after.jsp

6
我們的目標
• Web 聊天室
– http://
gabbly.com/http://www.pocketshark.com/blog/page/temp
/
– http://localhost:8080/dwr-chat/before.jsp
– http://localhost:8080/dwr-chat/after.jsp

7
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
8
AJAX 非同步傳輸

1:35
珍妮佛 : 什麼是 AJAX?
什麼又是非同步傳輸 ?

10
AJAX

Asynchronous
JavaScript
And AJAX = DHTML
XHTML&CSS
+ XHR

XML DOM
JavaScript
XMLHttpRequest 11
Classic Web Applications

12
From: http://adaptivepath.com/publications/essays/archives/000385.php
AJAX Web Applications

13
From: http://adaptivepath.com/publications/essays/archives/000385.php
傑克 : 那我該如何利用
AJAX 存取遠端網站資料呢 ?

14
XHR(XMLHttpRequest)
• JavaScript 版的 HttpConnection
• 介面
– open(string url,string asynch): 開啟
網頁
– send(string): 傳送資料
– onreadystatechange: 狀態改變回呼
函式
– status: HTTP 狀態
– responseXML: 回傳的 XML DOM 15
XHR
• 使用者輸入觸動 XHR

// 建立 XHR
request = new XMLHttpRequest();
// 設定回 呼函 式
request.onreadystatechange=handleResponse;
// 開啟連 結
request.open("GET","http://abc.com",true);
// 傳送資 料
request.send(null);

16
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;
}
} 17
}
DEMO: Hello World
http://localhost:8080/xhr/index.jsp

18
Tips & Tricks
about XHR

1:40
珍妮佛 : 傑克 , 這真是太神奇
了 , 但傳輸的資料一定要是
XML 格式嗎 ?

20
XHR 接受的資料型態
• 不 , XHR 除了 XML 資料之外 ,
還可以傳送 text, 所以也包括了
HTML, JavaScript (JSON)
[{author:‘tempo’, title:‘ 智者的 對談 '},
{author:‘browser,koji’, title:‘JSP 技術手 冊 '},
{author:‘caterpillar’, title:‘Spring 技術手 冊 '},
{author:‘piggy’, title:’Java2 全方位 學習 ’ ];

21
傑克 : 那所有的瀏覽器都有
支援 XHR 嗎 ?

22
瀏覽器支援
• XHR 支援以下瀏覽器
– IE 5.0+
– Mozilla 1.0+
– Safari 1.2
– Konqueor
– Opera 8.0
• 但不同的瀏覽器 XHR 建立方式不同
– IE: ActiveX
– Others: JavaScript
23
瀏覽器支援
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!");
}
}
24
珍妮佛 : 真奇怪 , 我使用
XHR, 瀏覽器卻一直跳出安
全性問題 ?

25
跨網域支援
• 有可能是其他問題 , 但 XHR 限制僅
能存取該網站上的資料 , 無法存取其
他網站的資料
• For example, 若此網頁的網址為
http://www.abc.com/test.jsp, 則
XHR:
– 不可存取 : test.abc.com/*,
abc.com/*
– 可存取 : www.abc.com/*
• AJAX SOA? 26
傑克 : 少來了 tempo, 明
明除了 XHR 之外 , 還有其
它方式來存取網站資料

27
<iframe> 與 <script>
• 是的 , 利用 <iframe> 與
<script> 也可以達到相同的功能 ,
但需要轉幾個彎

28
<iframe> 與 <script> 使用
• <iframe>
var sObj = document.createElement('iframe');
sObj.src = ‘http://www.abc.com’;
sObj.onload = function()
{ iframe_loaded( sObj ); };
document.body.appendChild( sObj );

• <script>
var sObj = document.createElement('script');
sObj.src = ‘http://www.abc.com’;
document.body.appendChild( sObj );
29
<iframe> 與 <script> 資料接

• <iframe>
– 回傳資料為 HTML 格式
• <script>
– 回傳資料為 JavaScript 格式
• 但都可以經過額外的步驟轉換為 XML 或
JavaScript

30
<iframe> 與 <script> 優缺點
• 優點
– 可以跨網域存取資料 , 不像 XHR 有限制
– <iframe> 瀏覽過的網頁會被加入瀏覽器的歷
史紀錄內
– 支援較多的瀏覽器
• 缺點
– 使用起來較繁瑣
– 僅支援 HTTP GET

31
tempo: 那我來做個整理吧

32
各種方法比較

33
小細節需要注意
• 三種傳輸方式
– XHR, <iframe>, <script>
• 三種資料格式
– XML, HTML, JavaScript
• 跨網域問題
• 瀏覽器支援問題
• 上一頁 / 下一頁與書籤問題 *

34
珍妮佛 : 好吧 tempo, 這
太複雜了 , 我只是想要存取
網站上的資料而已

35
透過 AJAX Framework 來
做非同步傳輸
• XHR, <iframe>, <script> 各有不同的
優點與缺點
• 瀏覽器有不同的 bugs 與標準
• 自行維護非同步傳輸底層不容易

36
透過 AJAX Framework 來
做非同步傳輸
• 現有的 AJAX Framework 都有提供自己的
XHR Utility 或包裝
– Framework: Google Web Toolkit, ZK,
Dojo, …
– RPC: DWR, JSON-RPC, …
– Libraries: Prototype, …
• DWR 是其中最專業也是支援最廣的 AJAX
非同步傳輸 Framework
37
Direct Web Remoting

1:50
傑克 : 什麼是 DWR 呢 ?

39
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

40
DWR

41
From: http://getahead.ltd.uk/dwr/overview/dwr
珍妮佛 : 我也想試試 DWR,
我該如何安裝呢 ?

42
Step 1: Download
• 從網站下載 DWR: http://
getahead.ltd.uk/dwr/download
• Copy dwr.jar into WEB-INF/lib

43
2:00
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>
<servlet-name>dwr-invoker</servlet-name>
<url-pattern>/dwr/*</url-pattern>
</servlet-mapping> 44
Step 3: dwr.xml
• 將遠端 Java 物件註冊到 dwr.xml
<dwr>

<allow>

<create creator="new" javascript="JDate">


<param name="class" value="java.util.Date"/>
</create>

</allow>

</dwr>

45
DEMO: Installation
http://localhost:8080/dwr-minimal/dwr/

46
DWR 除錯視窗
• 在 web.xml 設定 init-param,
‘debug’ = true
<init-param>
<param-name>debug</param-name>
<param-value>true</param-value>
</init-param>

• 顯示註冊在 dwr.xml 的物件與提供


直接測試用
• 請不要在正式環境使用 !!! 47
建民 : 那 tempo, 你應該
要講怎麼做 Hello World
了吧 ?

48
2:05
Step1: 建立伺服器端的 Java
物件
package com.willmobile.ajaxtm;

public class HelloWorld {


public String sayHelloWorldTo(String name) {
return "Hello World " + name + "!";
}
}

49
Step2: 在 dwr.xml 中註冊
類別
• 在 dwr.xml 的 <allow> 內建立
<create>
<dwr>
<allow>
<create creator="new“
javascript="HelloWorld" scope="page">
<param name="class"
value="com.willmobile.ajaxtm.HelloWorld" />
</create>
</allow>
</dwr>

50
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‘/>
<script type='text/javascript‘
src='/dwr-helloworld/dwr/util.js‘/>
</script>
</head>

51
Step4: 撰寫 client 端
JavaScript
<head>
<script type="text/javascript">
window.onload = function() {
functon callback(str) {
$('output').innerHTML = str;
}
HelloWorld.sayHelloWorldTo("JavaTwo 2006", callback);
}
</script>
</head>

52
遠端物件方法呼叫方式
• 參數與一般呼叫方式相同
• 回傳值使用 callback function, 放在最後
一個參數
• 用 Meta-data Object 定義 callback
function
public class Remote {
public String getData(int index) { ... }
}

function handleGetData(str) {
alert(str);
}

Remote.getData(42, handleGetData);
53
Demo: Hello World
http://localhost:8080/dwr-helloworld/
http://localhost:8080/dwr-helloworld/dwr/

54
Tips & Tricks
about DWR

2:15
傑克 : 可以讓遠端 Java
物件存放在 session 或
application scope 嗎 ?

56
設定遠端物件的 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>
57
珍妮佛 : 參數可以是自訂的
類別嗎 ?

58
Converters
• 定義在 dwr.xml 中描述 remote 物

Uses a
Converter

• var r = Remote.method(param);
Uses a
Creator

59
From: http://getahead.ltd.uk/dwr/overview/dwr
Converters
• 自動轉換
– Primitive Type ( 與他們對應的 class
型態 )
– String
– Date
• 預設 Converters
– Bean/Object Converter
– Array/Collection Converter
– Dom Objects
– Enum Converter 60
Converters 設定
• 在 dwr.xml 的 <allow> 內建立
<convert>
<dwr>
<allow>
<create>

</create>
<convert converter="bean“
match="com.willmobile.ajaxtm.User">
</convert>
</allow>
</dwr>

61
傑克 : 任何遠端 Java 物
件上的方法都可以呼叫嗎 ?

62
<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> 63
tempo: 那該輪到做一個
Web Form 來試試看

64
2:20
Step1: 建立伺服器端的 Java
物件
public class User {
private String id;
private String password;
private String name;
private String title;

}

65
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);
}
}

66
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); 67
Demo: DWR Form
http://localhost:8080/dwr-form/

68
Reverse AJAX

2:25
珍妮佛 : 我也會做 jsp 的聊
天室呀 , 你前面的 Demo 有
比較好嗎 ?

70
Reverse AJAX
• AJAX( 與一般 WEB 應用 )
– 由瀏覽器發動每個需求 , 伺服器不能主動傳
給瀏覽器任何資料
– Pull Model
• Reverse AJAX
– 伺服器可主動傳送資訊至瀏覽器顯示或執行
– Push Model ( 但其實是用 pull 模擬 )
• Polling
• Comet(Long Live HTTP)
71
Polling
瀏覽器 伺服器

N 秒送出一個 req1
request

req2

1. 新資料到
req3

2. 新資料傳至瀏覽器
req4
3. 顯示

72
Comet
瀏覽器 伺服器

req1

2. 新資料傳至瀏覽器
1. 新資料到
3. 顯示 req2

73
Reverse AJAX
• DWR
– 將這些複雜的操作隱藏起來
– Comet(Long Live HTTP)
– Polling
– Server Push JavaScript 至 Client
ScriptSession.addScript("alert('Hi')");

74
Reverse AJAX
• 適合需要即時回應的網路應用
– 股市資訊
– 線上遊戲
– 聊天交友
– 會員客戶服務

75
珍妮佛 : 我也想做像前面
Demo 那樣的聊天室 ~~

76
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");
}

77
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>
78
Demo: DWR Chat
http://localhost:8080/dwr-chat/before.jsp
http://localhost:8080/dwr-chat/after.jsp

79
傑克 : 那你之前 Demo 的
股市報價 , 也是用同一種技
術囉?

80
2:30
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));
}
} 81
Demo: DWR Reverse
http://localhost:8080/dwr-reverse/before.jsp
http://localhost:8080/dwr-reverse/after.jsp

82
Web Framework
Integration

2:35
珍妮佛 : 我不想呼叫物件 ,
我想把整個網頁 include
進來 , 這可以嗎 ?

84
AJAX Includes
• 可以 , DWR 提供 Server-side Include
• Server
public String getInclude() {
return WebContextFactory.get()
.forwardToString("/forward.jsp");
}

• Browser
function update() {
Demo.getInclude(function(html) {
DWRUtil.setValue("somediv", html);
}
); 85
傑克 : 這樣也行 , 那我想要
呼叫我伺服器上的 spring
beans, 不會也可以吧 ?

86
Spring Integration
• SpringCreator
<allow>
<create creator="spring" javascript="Fred">
<param name="beanName" value="Shiela"/>
</create>
</allow>

• web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/classes/beans.xml</param-value>
</context-param>

87
珍妮佛 : 好吧 , 那像
Struts, Webwork 應該也
不是問題囉?

88
Struts Integration
• StrutsCreator
<allow>
<create creator="struts" javascript="Fred">
<param name="beanName" value="Shiela"/>
</create>
</allow>

• Webwork
– 整合至 Action 層 , 可透過 JavaScript 直接
將 form 丟給 Action
89
其他的功能

2:40
傑克 : 我想要連續呼叫三個
遠端函式 , 這樣使用者會等
比較久嗎 ?

91
Batching
• 會的 , 所以若需要將數個 dwr 功能一次
送出 , 請將需要在同一個交易內的功能放
到 Batch 中
beginBatch();

endBatch();

92
珍妮佛 : 我看你的網頁右上
方都有像 gmail 一樣的
loading message, 我也

93
Loading Message
• 請在網頁 onLoad 時呼叫
useLoadingMessage() 即可

DWRUtils.useLoadingMessage();
Or
DWRUtils.useLoadingMessage(‘Waiting…’);

94
傑克 : 你都沒有提到錯誤處
理機制 :(

95
Error Handling
• Global Error (Exception) Handling
function handler(msg) {
alert(msg);
}

DWREngine.setErrorHandler(handler);

• Meta Data
Remote.method(params, {
callback:function(data) { ... },
errorHandler:handler
});

96
傑克 : 哇 , DWR/AJAX 真
棒 , 可是 back/forward
鍵沒用了 :(

97
瀏覽器歷史紀錄問題
• XHR 或是 <script> 都無法將連線網頁
加入瀏覽器歷史紀錄內
• Really Simple History
– http://
codinginparadise.org/projects/dhtml_history/

98
珍妮佛 : 以上提到的方法所
有瀏覽器都支援嗎 ?

99
瀏覽器支援
• DWR 支援以下瀏覽器
– IE 5.5+
– Firefox 1.0+
– Mozilla 1.7+
– Safari 1.2+
– Konqueor
– Opera 7.5.4+ ( 但現在不支援 Reverse
AJAX)

100
傑克 : 我已經有使用其他
framework 了 , 那我該如
何整合 DHR 呢 ?

101
DWR 與其它 AJAX
Framework
• JavaScript Libraries 不會有影響
– Dojo Toolkit
– Prototype
– Script.aculo.us
• AJAX Framework 則請使用原本提供的存
取方式
– GWT
– ZK

102
2:45
Thank you!

如果你流落荒島 , 但是只能帶
一個 AJAX Framework, 建議
你帶 DWR 
馮彥文
yenwen.feng@willmobile.com
我想請教關於 ..

104

You might also like