ajax transportation methods

Preview:

Citation preview

AJAX 的 client/server 溝通機制探究

馮彥文隨想行動科技

2

講師介紹

•馮彥文•隨想行動科技•Javaworld.tw: tempo•Email: yenwen.feng@willmobile.com•Blog: http://www.pocketshark.com/blog/page/tempo

3

這個故事 , 就從兩個技術人在一次研討會中的偶然相遇開始…

4

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

5

內容主題• AJAX

–利用 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– http://localhost:8080/dwr-reverse/before.jsp– http://localhost:8080/dwr-reverse/after.jsp

7

我們的目標• Web 聊天室

– http://gabbly.com/http://www.pocketshark.com/blog/page/tempo/

– http://localhost:8080/dwr-chat/before.jsp– http://localhost:8080/dwr-chat/after.jsp

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

AJAX 非同步傳輸

1:35

10

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

11

AJAX

AsynchronousJavaScriptAndXML

XHTML&CSSDOM

JavaScriptXMLHttpRequest

AJAX = DHTML + XHRAJAX = DHTML + XHR

12

Classic Web Applications

From: http://adaptivepath.com/publications/essays/archives/000385.php

13

AJAX Web Applications

From: http://adaptivepath.com/publications/essays/archives/000385.php

14

傑克 : 那我該如何利用 AJAX 存取遠端網站資料呢 ?

15

XHR(XMLHttpRequest)

• JavaScript 版的 HttpConnection• 介面

– open(string url,string asynch): 開啟網頁– send(string): 傳送資料– onreadystatechange: 狀態改變回呼函式– status: HTTP 狀態– responseXML: 回傳的 XML DOM– responseText: 回傳的文字內容

16

XHR

• 使用者輸入觸動 XHR

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

17

XHR

• 接收資料後立刻更新 UIfunction 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

http://localhost:8080/xhr/index.jsp

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 支援以下瀏覽器

– 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, 若此網頁的網址為 http://www.abc.com/test.jsp, 則 XHR:– 不可存取 : test.abc.com/*, abc.com/*– 可存取 : www.abc.com/*

• AJAX SOA?

27

傑克 : 少來了 tempo, 明明除了 XHR 之外 , 還有其它方式來存取網站資料

28

<iframe> 與 <script>• 是的 , 利用 <iframe> 與 <script> 也可以

達到相同的功能 , 但需要轉幾個彎

29

<iframe> 與 <script> 使用• <iframe>

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

var sObj = document.createElement('iframe');sObj.src = ‘http://www.abc.com’;sObj.onload = function() { iframe_loaded( sObj ); };document.body.appendChild( sObj );

30

<iframe> 與 <script> 資料接收• <iframe>

– 回傳資料為 HTML 格式• <script>

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

avaScript

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

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: http://getahead.ltd.uk/dwr/overview/dwr

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

<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>

• 修改 web.xml, 新增 DwrServlet

45

Step 3: dwr.xml

<dwr>

<allow>

<create creator="new" javascript="JDate"> <param name="class" value="java.util.Date"/> </create>

</allow>

</dwr>

• 將遠端 Java 物件註冊到 dwr.xml

46

DEMO: Installation

http://localhost:8080/dwr-minimal/dwr/

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> <allow> <create creator="new“ javascript="HelloWorld" scope="page"> <param name="class" value="com.willmobile.ajaxtm.HelloWorld" /> </create> </allow></dwr>

• 在 dwr.xml 的 <allow> 內建立 <create>

51

Step3: 在網頁中 include JavaScript

<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>

• engine.js 與 util.js 是 dwr 的公用 script• HelloWorld.js 是我們註冊的遠端物件 script

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/http://localhost:8080/dwr-helloworld/dwr/

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: http://getahead.ltd.uk/dwr/overview/dwr

60

Converters

•自動轉換– Primitive Type ( 與他們對應的 class 型態 )– String– Date

•預設 Converters– Bean/Object Converter– Array/Collection Converter– Dom Objects– Enum Converter

61

Converters設定

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

• 在 dwr.xml 的 <allow> 內建立 <convert>

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 scriptfunction 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

http://localhost:8080/dwr-form/

Reverse AJAX

2:25

70

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

71

Reverse AJAX

• AJAX( 與一般 WEB 應用 )–由瀏覽器發動每個需求 , 伺服器不能主動傳給瀏覽器任何資料

– Pull Model• Reverse AJAX

–伺服器可主動傳送資訊至瀏覽器顯示或執行– Push Model ( 但其實是用 pull 模擬 )

•Polling•Comet(Long Live HTTP)

72

Polling瀏覽器 伺服器

N秒送出一個 request

1. 新資料到

2. 新資料傳至瀏覽器

3. 顯示

req1

req2

req3

req4

73

Comet瀏覽器 伺服器

1. 新資料到2. 新資料傳至瀏覽器

3. 顯示

req1

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.jsphttp://localhost:8080/dwr-chat/after.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 http://localhost:8080/dwr-reverse/after.jsp

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>

其他的功能

2:40

91

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

92

Batching

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

beginBatch();…endBatch();

93

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

94

Loading Message

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

DWRUtils.useLoadingMessage();OrDWRUtils.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– http://

codinginparadise.org/projects/dhtml_history/README.html

99

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

100

瀏覽器支援• DWR 支援以下瀏覽器

– IE 5.5+– Firefox 1.0+– Mozilla 1.7+– Safari 1.2+– Konqueor– Opera 7.5.4+ ( 但現在不支援 Reverse AJAX)

101

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

102

DWR 與其它 AJAX Framework

• JavaScript Libraries 不會有影響– Dojo Toolkit– Prototype– Script.aculo.us

• AJAX Framework 則請使用原本提供的存取方式– GWT– ZK

2:45

Thank you!

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

104

我想請教關於 ..

Recommended