非常詳細介紹了DWR和ajax標籤的使用。及真實配置
分爲兩個部分:dwr的原理和應用/真實環境使用(在文章的最後面)。基本上適合所有人查閱
DWR的作用:DWR是一個可以允許你去創建AJAX WEB站點的JAVA開源庫。它可以讓你在瀏覽器中的Javascript代碼調用Web服務器上的Java代碼,就像在Java代碼就在瀏覽器中一樣。
在使用dwr前,先介紹下我們遠程調用的方法,以方便下文解說
其中的KnowDAO類是實現了CRUD方法的dao類,返回一個字符串,內容是當前時間和數據庫中的數據數量。注:別忘了寫getter,setter方法。
DWR的配置:
web.xml:首先要在你的web.xml中加入dwr的配置代碼,代碼如下:.
其中<init-param>中配置了debug的值,表示可以進入調試模式,其他都是必須有的
dwr.xml:要建立一個dwr.xml的配置文件,這個文件放在你的項目的根目錄下。和你的web.xml放在一起。在demo中我的代碼如下:
其中<dwr>中的部分就是dwr的配置,<dwr>中<allow>標籤中定義了DWR能夠創建和轉換的類.<create>中的create屬性有很多類型,這裏使用的是spring表示整合spring。
javascript屬性的值是DwrTime是在js的頁面中使用的,類似於beans.xml中,bean id的作用
不同的是bean id的值作爲一個對象的實例,可以直接使用在java中,而javascript屬性是直接使用在js中。
<param>標籤中的值表示的是與beans.xml注入的哪個實例相對應,name屬性是固定的表示這個屬性是與bean id相關,value屬性和bean id的值是相同的.beans.xml中的注入文件如下:
<include>標籤表示的是類中那些方法可以在js中使用,如果不想讓某些方法在js被調用,
那麼就不要include它,注意method屬性的值可以是”*”,用來表示所有方法.
PS:除了include標籤以外,還可以用exclude 標籤來聲明, exclude表示的是不能使用的方法,凡是沒聲明的就可以使用, exclude不推薦使用。
beans.xml中的配置:
在beans.xml中將要遠程調用的類作爲bean來注入,如上圖所示。它與drw.xml中的相關屬性對應不再重複
js文件中的使用
做完以上工作我們可以在js中使用它遠程調用的方法瞭如下所示:
圖中前3行代碼的意思分別是:
<script type='text/javascript' src='/somcdemo/dwr/interface/DwrTime.js'></script>
表示引入/somcdemo/dwr/interface/DwrTime.js 這個js是根據你所寫的類自動生成的,也是必須引入的。
<script type='text/javascript' src='/somcdemo/dwr/engine.js'></script>
表示引入/somcdemo/dwr/engine.js 這個js是dwr的jar文件中自帶的,如果你想程序正常運行就必須引入。
<script type='text/javascript' src='/somcdemo/dwr/util.js'></script>
表示引入/somcdemo/dwr/util.js,這個js也是dwr的jar文件中自帶的,它提供了一些好用的方法,如果你想使用也要引入.
接下來定義了3個方法:
第1個方法CreateWindow與dwr無關。
第2個方法是getTime方法,在調用的時候使用了DwrTime(它就是dwr.xml中javascript屬性中那個),它就是DwrTime類的實例。DwrTime.currentlyTime("本次查詢時間:",callBackTime);就是調用了DwrTime的currentlyTime方法, currentlyTime方法有兩個參數, 第一個參數是”本次查詢時間”,這個字符串,它是作爲currentlyTime方法的參數使用的。
第2個參數callBackTime是回調方法的名字,當 currentlyTime方法運行完畢後,返回一個值,把這個值作爲參數,調用callBackTime方法(所以callBackTime方法必須有個參數). callBackTime方法就是回調方法。
注意:回調方法名不是固定的.自己定義
PS:本文檔主要講了DWR與SPRING的整合使用(初步), DWR還有很多別的標籤,和高深的應用技巧,技術淺薄不能一一介紹,推薦觀看DWR中文文檔.pdf
11.1.2 DWR使用入門
有兩種方式可以開始DWR的應用。一種是直接從其官方網站下載DWR的Web應用示範包,這是一個war的部署包,從中可以對DWR的應用效果及其部署方式有一個大概的瞭解。不過這種方式無法詳細掌握如何將DWR與Web應用程序緊密集成。另外一種方式是根據DWR官方開發文檔的講解,通過一步步的部署和配置,將DWR集成到Web應用程序中。本節通過簡單的示範和一個例子來講述DWR的部署和集成。
DWR採用一個Java Servlet來處理請求並將響應結果發送給瀏覽器,這個Java Servlet需要加入到Java Web應用程序的部署描述文件web.xml。其次,它通過一個自定義的部署描述文件dwr.xml來控制Java對象與Javascript的轉化。下面通過五步簡單的配置,將DWR部署到2.4節創建的開發項目中。
第一步:安裝jar開發包。
從DWR官方網站http://www.getahead.ltd.uk/dwr/下載DWR的開發包。這裏採用DWR1.0,它是一個簡單的名爲dwr1.0.jar開發包。將這個開發包放到{APPLICATION_ WEB_HOME} /WEB-INF/lib目錄下。如果使用DWR1.1,則下載的應該是DWR1.1的開發包。這個開發包中包含了DWR運行所需的全部Java類及相應的API。dwr1.0.jar也可以從隨書光盤jar lib目錄中找到。
第二步:修改web.xml,添加Servlet映射。
修改{APPLICATION_WEB_HOME}/WEB-INF目錄下的web.xml,將下列代碼添加到web.xml的適當位置。
例程11-1 爲web.xml添加DWR映射
<servlet>
<servlet-name>dwr-invoker</servlet-name>
<display-name>DWR Servlet</display-name>
<servlet-class>uk.ltd.getahead.dwr.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>
<servlet>映射部分應該緊隨web.xml中的其他<servlet>映射,<servlet-mapping>則緊隨<servlet-mapping>部分。
這段部署描述告訴Web應用程序,全部以“/dwr/”起始的URL所指向的請求都交給uk.ldt.getahead.dwr.DWRServlet這個Java Servlet來處理。
第三步:創建dwr.xml
在{APPLICATION_WEB_HOME}/WEB-INF目錄下創建dwr.xml部署描述文件,其代碼例程11-2所示。
例程11-2 DWR部署描述文件dwr.xml
<!DOCTYPE dwr PUBLIC
"-//GetAhead Limited//DTD Direct Web Remoting 1.0//EN"
"http://www.getahead.ltd.uk/dwr/dwr10.dtd">
<dwr>
<allow>
<create creator="new" javascript="JDate">
<param name="class" value="java.util.Date"/>
</create>
</allow>
</dwr>
這個XML文檔中用到了其對應的DTD文檔,頂部的文檔聲明指明當前用到的是DWR1.0版本。如果使用DWR1.1,則應該相應地修改這個XML文檔的文檔聲明。
這個部署描述文件定義什麼樣的Java 類可以被DWR應用創建並通過Javascript遠程調用。在上面的部署描述中,定義了可以被DWR創建的Java類java.util.Date,並給這個類賦予一個Javascript名稱JDate。通過修改dwr.xml,也可以將自定義的Java類暴露給Javascript遠程調用。
需要注意的是,dwr部署描述爲遠程Java類擬定的Javascript名稱還是有些限制的。
— 避免使用Javascript關鍵字或者保留字,因爲這些用Javascript關鍵字或者保留字命名的方法會自動執行。大部分的Javascript關鍵字或者保留字也是Java的關鍵字或者保留字,比如,“try()”不是一個合法的命名。不過還是有一部分的Javascript關鍵字或者保留字在Java中不被限制,比如“delete()”。
— 避免使用方法重載。有時候,在調用這些重載的方法會引起麻煩,因爲Javascript沒有像Java那樣的包命名機制來支持方法重載。
第四步:測試URL,查看部署效果。
在瀏覽器地址欄中輸入http://localhost:8080/ajaxlab/dwr,其頁面效果如圖11-2所示。通常,這個頁面會顯式在dwr.xml部署描述文件中定義的全部Java類,並且顯式可以查看所有其可供遠程調用的方法的列表的鏈接。這個頁面由DWR動態創建。在本例中,頁面上有一個JDate的鏈接,列出暴露給DWR的JDate類可供Javascript遠程調用的方法。
圖11-2 DWR部署效果
單擊“JDate”鏈接,查看Javascript能夠調用的java.util.JDate類的方法,其效果如圖11-3所示。單擊每個方法後面的“Execute”按鈕,嘗試執行這些方法。
圖11-3 能夠被Javascript遠程調用的方法
第五步:使用Javascript遠程調用Java類的方法。
java.util.Date類的相關方法已經暴露出來供Javascript遠程調用。將以下的Javascript引用代碼添加到JSP或者HTML文件中,就可以在JSP或者HTML文件中直接調用第四步配置所暴露的java.util.Date類的方法了。
<script language="javascript" src="/ajaxlab/dwr/interface/JDate.js"> </script>
<script language="javascript" src='/ajaxlab/dwr/engine.js'></script>
<script language="javascript" src='/ajaxlab/dwr/util.js'></script>
例程11-3展示了這個過程,調用java.util.Date類的toString()方法將當前時間打印出來。這個例子包含一個普通按鈕控件和兩個Javascript函數,其中一個函數doTest通過JDate.toString()調用,取得java.util.Date所表示的當前時間。第二個函數responseDate將第一個函數所取得的當前時間以彈出窗口的形式顯式出來。第二個函數的名稱作爲第一個函數的參數,這與第5章所說的回調函數類似。具體代碼如例程11-3所示,其運行效果如圖11-4所示。
例程11-3 sample12_1.jsp
<%@ page contentType="text/html; charset=gb2312" errorPage="" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>Ch11--DWR使用入門</title>
<script language="javascript" src="/ajaxlab/dwr/interface/JDate.js"></s cript>
<script language="javascript" src='/ajaxlab/dwr/engine.js'></script>
<script language="javascript" src='/ajaxlab/dwr/util.js'></script>
<script language="javascript">
function doTest() {
JDate.toString(load);
}
function load(data) {
window.alert("Current Time:"+data);
}
</script>
</head>
<body>
<input type="button" name="count" value="cont" onClick="doTest()">
</body>
</html>
圖11-4 調用JDate的Javascript方法顯示當前時間
通過簡單的配置,Javascript可以自由地遠程調用Java對象的方法。接下來看看DWR是怎麼實現上述設計的。DWR使用dwr.xml部署描述文檔來定義Javascript對象和Java類之間的映射轉化。首先了解一下dwr.xml這個DWR定義的部署描述文件的結構。從dwr.xml對應的DTD(http://www.getahead.ltd.uk/dwr/dwr10.dtd,版本1.0)文件中很容易知道dwr.xml的具體結構。從DWR的官方網站可以找到關於這個DTD的說明文檔(http://get ahe ad.ltd.uk/dwr-demo/dtddoc/)。
所有部署描述文件的頂級根元素爲dwr,其按照順序可以包含以下三個子元素之一。
— init:此元素定義那些在應用程序啓動時作爲DWR運行庫所需的類自動加載並初始化的類。
— allow:此元素定義那些允許客戶端Javascript遠程調用的Java類。
— signatures:此元素簽名必要的方法,當使用集合的時候,爲轉換器指定Java反射機制外的類別信息。
表11-1顯示了dwr.xml的各個組成元素及其父元素、屬性、子元素、用途等信息。
表11-1 dwr.xml組成元素及其屬性和用途
元素名稱 |
屬性名稱 |
父 元 素 |
用 途 |
dwr |
|
|
dwr.xml文檔的根元素 |
init |
|
dwr |
定義那些在應用程序啓動時作爲DWR運行庫所需的類自動加載並初始化的類 |
creator |
|
init |
定義供Javascript調用的新建對象的方法,即對象的構造方法 |
|
id |
creator |
用來惟一標識creator所創建的對象。必需屬性 |
|
class |
creator |
應用creator元素定義的Java對象的完整名稱。必需屬性 |
converter |
|
init |
定義Javascript對象和Java對象之間新的轉換方法。有些類有默認的轉換機制,但有些類需要自定義轉換機制 |
|
id |
converter |
用來惟一標識converter所創建的對象。必需屬性 |
|
class |
converter |
應用converter元素定義的Java對象的完整名稱。必需屬性 |
allow |
|
dwr |
定義那些允許客戶端Javascript遠程調用的Java類 |
create |
|
allow |
定義允許創建的Java類,併爲其指定一個Javascript名稱,並定義DWR應當如何獲得要進行遠程的類的實例 |
|
creator |
create |
create元素所使用的構造方法名稱。必需屬性 |
續表
元素名稱 |
屬性名稱 |
父 元 素 |
用 途 |
|
javascript |
create |
Java類暴露給瀏覽器調用的Javascript名稱。必需屬性 |
|
scope |
create |
create元素所創建的類的可用範圍,默認爲page。可選屬性 |
param |
|
create |
指定create元素所需要的參數,比如其允許創建的Java類的名稱 |
|
name |
param |
param元素所指定的參數名稱。必需屬性 |
|
value |
param |
param元素所指定的參數值。必需屬性 |
include |
|
create |
指定應當公開的方法的名稱。必需屬性 |
exclude |
|
create |
指定那些想防止被訪問的方法 |
auth |
|
create |
爲暴露給瀏覽器的方法指定允許訪問的角色 |
|
method |
auth |
指定需要訪問角色限制的方法。必需屬性 |
|
role |
auth |
指定允許訪問的角色。必需屬性 |
convert |
|
allow |
告訴DWR在服務器端 Java對象表示和序列化的 Javascript之間如何轉換數據類型 |
|
converter |
convert |
指定所使用的轉換器的標識。必需屬性 |
|
match |
convert |
與轉換器所匹配的類名稱。必需屬性 |
param |
|
convert |
指定轉換器所要包含的參數 |
|
name |
param |
param元素所指定的參數名稱。必需屬性 |
|
value |
param |
param元素所指定的參數值。必需屬性 |
signatures |
|
dwr |
簽名必要的方法,當使用集合的時候,爲轉換器指定Java反射機制之外的類別信息 |
create元素告訴DWR應當公開給Ajax請求的服務器端類,並定義DWR應當如何獲得要進行遠程的類的實例。這裏的creator屬性被設置爲值new,這意味着DWR應當調用類的默認構造函數(無任何參數)來獲得實例。其他的可能通過代碼段用Bean腳本框架(Bean Scripting Framework,BSF)來創建實例,或者通過與IOC容器Spring進行集成來獲得實例。默認情況下,到DWR的Ajax請求會調用creator,實例化的對象處於頁面範圍內,因此請求完成之後就不再可用。本節的例子中,在無狀態的JDate情況下,這樣很好。
create的javascript屬性指定從Javascript代碼訪問對象時使用的名稱。嵌套在create元素內的param元素指定creator 要創建的Java類。最後,include元素指定應當公開的方法的名稱。顯式地說明要公開的方法是避免偶然間允許訪問有害功能的良好實踐(如果漏了這個元素,類的所有方法都會公開給遠程調用)。反過來,則可以用exclude元素指定那些想防止被訪問的方法。
create元素的creator屬性可有三種選擇值:new,scripted,spring。最常見的是new選擇值,它代表將使用Java類默認的無參數構造方法創建類的實例對象。scripted選擇值則代表允許使用一些腳本語言,比如用BeanShell來創建Java類的實例對象,這在類無法通過配置遠程調用的時候特別有用。spring選擇值則允許遠程調用spring Bean。當需要調用包含靜態(static)方法的Java類時,建議使用new選擇值。DWR會自動跳過(skip)靜態方法。表11-2列出了當creator屬性採用不同的選擇值時,其對應param子元素的param和value的值及其含義。
表11-2 creator元素選擇值及其含義
creator值 |
param值 |
value值 |
new |
class |
允許遠程調用的類名稱,包括完整的包名稱 |
scripted |
language |
BSF支持的語言名稱 |
scripted |
script |
返回供遠程調用的對象的腳本 |
spring |
location* |
任何以location起始的參數名稱。每個參數代表一個spring配置文件 |
spring |
beanName |
可從配置文件中讀取的Bean的名稱 |
爲了安全考慮,將所有的Java類無選擇地暴露給客戶端Javascript是不理智的,所以必須加以控制和選擇。create元素的include,exclude兩個子元素用來對暴露給客戶端Javascript的方法進行篩選,auth則能夠將方法訪問權限授予相應的角色對象(需要用到J2EE安全機制等)。注意,本節的示例第五步用到了一個src屬性爲“/ajaxlab/dwr/interface/ JDate.js”的Javascript文件。這個文件是DWR動態生成的。DWR根據dwr.xml的配置,將相應的Java類方法和屬性轉化爲Javascript供客戶端調用。所以在用戶看來,就好像Javascript在調用本地對象一樣。這些調用通過XMLHttpRequest對象轉化爲對uk.ltd.getahead.dwr.DWRServlet的請求,繼而請求服務器響應。
create元素的creator屬性負責公開用於Web遠程的類和類的方法,convert元素的convertor屬性則負責這些方法的參數和返回類型。convert元素的作用是告訴DWR在服務器端Java對象表示和序列化的Javascript之間如何轉換數據類型。DWR自動地在Java和Javascript表示之間調整簡單數據類型。這些類型包括Java原生類型和它們各自的類表示,還有String、Date、數組和集合類型。DWR也能把JavaBean轉換成Javascript表示,但是爲了安全考慮,做這件事要求顯式的配置。
DWR應用中,所有的“/dwr/*”的請求都由這個DWRServlet來處理。當Web服務器啓動的時候,DWRServlet調用init()方法完成初始化,設置日誌級別、實例化DWRServlet用到的單例類、讀取包括dwr.xml在內的配置文件。當“/dwr/*”請求送達的時候,DWRServlet的doGet,doPost方法調用processor.handle(req,res)方法,根據請求的URL完成如下事務。
— 請求URL爲“/dwr/”根請求:將請求轉向“/dwr/index.html”;
— 請求URL爲“/dwr/index.html”:列出當前客戶端可遠程調用的全部Java類,頁面僅供調試的時候使用;
— 請求URL爲“/dwr/text/*”:爲單獨的Java類創建測試頁面,頁面僅供調試的時候使用;
— 請求URL爲“/dwr/engine.js”或者“/dwr/uril.js”或者“/dwr/deprecated.js”:從dwr.jar包中讀取相應Javascript文件的文件流,顯示在頁面上;
— 請求URL爲“/dwr/interface/*”:將在dwr.xml中定義的Java類及其方法轉化爲Javascript函數;
— 請求URL爲“/dwr/exec/”:處理遠程Javascript請求;
— 請求URL爲其他:設置http請求狀態碼爲404,返回錯誤信息爲“Page not found. In debug/test mode try viewing /[WEB-APP]/dwr/”。
既定的Java類已經通過DWR轉化成可供客戶端使用Javascript調用的方法和對象了。接下來就是使用Javascript調用這些暴露的方法和對象了。DWR最大的挑戰在於如何將Java同步調用執行的特性與Ajax的異步特性結合起來。
DWR採用了XMLHttpRequest對象的回調機制來解決上述矛盾,即當響應數據從服務器返回是調用用戶指定的回調函數。DWR提供兩種方式爲Javascript指定回調函數,即將回調函數名稱加入參數列表,或者在參數列表中增加一個包含數據對象的調用。
將回調函數名稱加入參數列表是最簡單最常用的方式,本節的案例就使用了這種方式。假設Java類Remote提供的方法簽名如下:
public class Remote() {
public String getData(int data) {……}
}
則可以在Web頁面中使用如下方法調用:
<script language="javascript" src="{webapp}/dwr/interface/Remote.js" > </script>
<script language="javascript" src="{webapp}/dwr/engine.js"></script>
function handleData(str) {window.alert(str);} //創建回調函數
Remote.getData(100,handleData); //調用Javascript,100是Remote類方法getData本身的參數。
如果採用第二種方法,上面的調用代碼可以這樣書寫:
Remote.getData(100,{callback:function(str){window.alert(str);}});
這種方法有時候具有比較好的可讀性,也可以添加額外的調用,還可以爲回調函數定時並設置錯誤處理函數:
Remote.getData(100,{
callback:function(str){window.alert(str);},
timeout:5000,
errorHandler:function(message){window.alert("No options:"+messag
e);}
});
11.1.3 試用DWR
上一節的介紹中,Java自帶類java.util.Date被用來示範如何將服務器端Java類暴露給瀏覽器端Javascript遠程調用。這一節將使用自定義的類來展示DWR框架的具體應用。
接下來的例子採用了基於網上商店的模型,包含一個基本的產品表示類Item和一個數據存儲查詢訪問對象CatalogDAO類。Item是一個普通的Java類,包含id,name,description,price四個屬性及相應的geter,setter方法;CatalogDAO則包含getItem,findItems兩個方法,getItem方法通過輸入id參數取得特定的Item,findItems則以List形式返回當前全部的Item。在實際案例中,CatalogDAO的getItem和findItems方法所取得的數據一般來自持久化介質,如數據庫。這裏僅爲示範及測試所需,所以返回硬編碼,其大致代碼如例程11-4所示。
例程11-4 Item
package com.ajaxlab.ajax;
public class Item {
private String id = "";
private String name = "";
private String description = "";
private int price = 0;
public Item() {
}
public Item(String id) {
this.id = id;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public String getFormattedPrice() {
return "$"+String.valueOf(price);
}
}
例程11-5 CatalogDAO
package com.ajaxlab.ajax;
import java.util.List;
import java.util.ArrayList;
public class CatalogDAO {
public CatalogDAO() {
}
public Item getItem(String id) {
Item item = new Item("產品-"+id);
item.setName("新品-"+id);
item.setPrice(100);
item.setDescription("中國製造.");
return item;
}
public List findItems(String expression) {
List list = new ArrayList();
Item item1 = new Item("產品-001");
item1.setName("新品-001");
item1.setDescription(expression);
item1.setPrice(10);
Item item2 = new Item("產品-002");
item2.setName("新品-002");
item2.setDescription(expression);
item2.setPrice(15);
Item item3 = new Item("產品-003");
item3.setName("新品-003");
item3.setDescription(expression);
item3.setPrice(35);
list.add(item1);
list.add(item2);
list.add(item3);
return list;
}
}
由於要將Item和CatalogDAO暴露給瀏覽器端Javascript遠程調用,所以Item和CatalogDAO都提供了無參數的構造方法。這個例子將演示兩個簡單的用例:一是在文本框中輸入產品ID,搜索對應的產品;二是單擊“瀏覽產品”按鈕,返回當前全部庫存產品。
接下來設置DWR部署描述文件dwr.xml。create元素部分將CatalogDAO類的getItem,findItems方法暴露出來,convert元素則將Item類轉化爲普通的Javascript對象。DWR自動在Java和Javascript表示之間調整簡單數據類型。這些類型包括Java基本類型及其各自的類表示,比如int和Integer,以及String、Date、數組和集合類型。在Item類中,爲了顯示格式化後的產品價格,增加了getFormattedPrice方法。dwr.xml的代碼如例程11-6所示。
例程11-6 dwr.xml
<!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 1.0//EN" "http://www.getahead.ltd.uk/dwr/dwr10.dtd">
<dwr>
<allow>
<create creator="new" javascript="CatalogDAO">
<param name="class" value="com.ajaxlab.ajax.CatalogDAO"/>
<include method="getItem"/>
<include method="findItems"/>
</create>
<convert converter="bean" match="com.ajaxlab.ajax.Item">
<param name="include" value="id,name,description,formatted- Price" />
</convert>
</allow>
</dwr>
確保Web應用程序下的web.xml已經按照12.4.3節第二步添加了相應的Servlet映射,將dwr.xml拷貝到{APPLICATION_WEB_HOME}/WEB-INF目錄下。啓動Tomcat,打開瀏覽器,導航到http://localhost:8080/ajaxlab/dwr/index.html就能夠看到CatalogDAO暴露出來的方法了,如圖11-5和圖11-6所示。
圖11-5 暴露給Javascript的Java類
圖11-6 CatalogDAO供Javascript遠程調用的方法
在getItem,findItems兩個方法後面的文本框的雙引號中輸入任何字符,單擊“Execute”按鈕。服務器返回的數據以彈出對話框的形式顯示出來。getItem返回一個Javascript對象,findItems則返回一個數組直接量,如圖11-7和圖11-8所示。
Java類方法已經按照預定設想暴露給Javascript了,按照DWR的設計思想,在Web頁面中,可以使用CatalogDAO.methodName(parameter1,parameter2…,callback)的方式調用CatalogDAO的方法。其中,callback是回調函數的名稱。DWR並未嚴格的檢查是否傳送parameter參數給CatalogDAO方法。
圖11-7 CatalogDAO返回的Javascript對象 圖11-8 CatalogDAO返回的數組直接量
本例的Web頁面包含兩個文本框和兩個按鈕。文本框分別用來輸入產品編號和產品描述,兩個普通按鈕則用來根據輸入顯示單個產品細節和全部產品列表。頁面中還包括兩個事件響應函數和兩個回調函數,分別用來響應按鈕單擊事件和處理響應數據。
事件響應函數doSearch將輸入框item_id的值連同回調函數showItem的名稱作爲參數傳遞給CatalogDAO.getItem方法。而事件響應函數doList則將輸入框item_description的值連同回調函數showList的名稱作爲參數傳遞給CatalogDAO.findItems方法。
在回調函數showItem和showList中,使用到了名爲$()的Javascript函數。這個函數是在DWR的util.js定義的,其功能與“document.getElementById()”相當。util.js中還定義了大量方便開發人員操作的便捷函數,具體可以參考util.js源碼。sample12_2.jsp的Javascript部分代碼如下所示,相應的運行效果如圖11-9所示。
圖11-9 使用DWR實現產品搜索
例程11-7 sample12_2.jsp
<script language="javascript">
function doSearch() {
var item_id = document.form1.item_id.value;
if(item_id!="") CatalogDAO.getItem(item_id,showItem);
else document.getElementById("item_detail").innerHTML = "請輸入產品編號。";
}
function showItem(data) {
var element = $("item_detail");
var str = "";
str = "<table width='600' cellspacing='0' cellpadding='4' border= '1'>";
str = str + "<caption>產品信息</caption>";
str = str + "<thead><td width='100'>編號</td><td width='100'>名稱</td><td width='100'>價格</td><td width='300'>描述</td></thead>/r/n";
str = str + "<tbody><td width='100'>"+data.id+"</td><td width= '100'>"+data.name+"</td><td width='100'>"+data.formattedPrice+"</td><td width='300'>"+data.description+"</td></tbody>/r/n";
str = str + "</table>";
element.innerHTML = str;
}
function doList() {
CatalogDAO.findItems("中國製造。",showList);
}
function showList(data) {
var root = $("item_list");
var str = "<table width='600' cellspacing='0' cellpadding='4' border='1'>";
str = str + "<caption>全部產品</caption>";
str = str + "<thead><td width='100'>編號</td><td width='200'>名稱</td><td width='100'>價格</td><td width='200'>描述</td></thead>/r/n";
str = str + "<tbody>/r/n";
for(var i=0;i<data.length;i++) {
str = str + "<thead><td width='100'>"+data[i].id+"</td><td width='200'>"+data[i].name+"</td><td width='100'>"+data[i].formattedPrice+"</td><td width='200'>"+data[i].description+"</td></thead>/r/n";
}
str = str + "</tbody></table>";
root.innerHTML = str;
}
</script>
11.1.4 DWR的適用範圍
通過以上的介紹和試用可以看到DWR提供了許多東西,它允許迅速而簡單地創建到服務器端Java對象的Ajax接口,而無須編寫任何Servlet代碼、對象序列化代碼或客戶端XMLHttpRequest代碼。使用DWR部署到Web應用程序極爲簡單,而且DWR的安全特性可以與J2EE基於角色的驗證系統集成。與手工編寫Ajax應用程序相比,DWR通過Java映射機制、Java類對象與Javascript對象轉換等方式,將服務器端Java類屬性及其方法有選擇地暴露給瀏覽器客戶端,並應用一系列的擴展函數簡化了Ajax應用程序開發,減少了開發量,提高開發效率。
但是,同任何RPC一樣,對遠程對象的每一個調用都要比本地函數調用來得昂貴,所以應該儘可能減少對遠程對象的調用次數。與某些Java類、方法設計方式相比,DWR遠程調用返回的數據應該儘量保持粗粒度,以防止多次頻繁的調用遠程對象。DWR在封裝和隱藏Ajax機械性方面做的很好,但是這在一定程度上降低了Ajax的自由度。
實際上,使用DWR框架的Ajax應用將是一個高耦合的應用,因爲DWR在客戶端和服務器端代碼之間形成了緊密的耦合。具體表現在:遠程方法API的變化必須在DWR存根調用的Javascript上反映出來,必要時也必須修改dwr.xml部署描述文件,這點明顯與當前廣受推崇的MVC模式相悖。而這種考覈會將客戶端的調用考慮滲入到服務器端類方法等代碼編寫。典型的是,由於轉換器的侷限,某些Java方法和屬性不能順利轉化爲Javascript,所以常常有必要爲這些方法特別添加額外的處理方法。所以,基於方便轉換及其他的考慮,JavaBean的設計不再那麼單純和簡單。同樣,DWR的數據傳輸是採用異步方式,不要期望多個調用按照分派的順序依次返回。
綜上所述,如果讀者希望能夠將服務器端Java對象暴露給瀏覽器端Javascript,快速地創建Ajax應用程序,而且目標應用程序並不追求視圖與控制器、模型層之間的低耦合,那麼就可以考慮採用DWR來實現Ajax應用。由於篇幅的關係,本書並未涉及到DWR的全部特性。讀者如果想深入學習DWR或者瞭解更多的內容,惟一的方式就是從其官方網站下載最新的文檔和開發包,自己動手實踐。
11.2.1 Ajax Tags簡介
Ajax Tags是位於sourceforge.net上面的一個開源Ajax項目,其出發點在於應用標籤封裝的思想,實現一些常用的Ajax應用,提高開發效率。Ajax Tags提供一系列的標籤,簡化在JSP頁面中使用Ajax的過程。Javascript在Ajax中佔很大的比重,但實際上不少服務器端的開發人員掌握的Javascript知識並不完整(按照正常分工,頁面構建應該是網頁設計人員或者前端開發人員的職責)。Ajax Tags提供的標籤能夠讓開發人員將JSP頁面與Ajax應用快速的集成整合。
Ajax Tags支持如下情況下的無刷新頁面更新:
— 基於文本框的輸入自動完成(autocomplete based on character input to an input field),類似Google Suggestion的搜索建議功能。
— 下拉列表級聯選擇(select box population based on selections made from another field),即當選擇一個下拉列表時,另一個下拉列表的列表項則根據上一個下拉列表的情況自動更新。
— 文本高顯提示(callout or balloon popups for highlighting content),即當單擊某個鏈接的時候,在其周圍彈出文本框,顯示相關提示信息。
— 更新表單域內容,包括文本標籤及全部控件。
— 圖像關聯(toggling images)。
— 表單域狀態開啓和關閉(form field states on/off)。
Ajax Tags的實現包含Javascript和Java類,其中,Java類基於JDK1.4編譯,需要Servlet容器支持,而Javascript文件可以在Firefox1.1+和IE5.0以上版本環境下運行。
在編寫本書的時候,Ajax Tags發佈了其1.1版本。從Ajax Tags的官方網站http://ajaxtags.sourceforge.net/可以下載全部可用版本及相關文檔。特別要注意的是,從其官方網站下載到的demo包,需要JSP2.0和Servlet2.4支持,Tomcat5.5可以滿足要求。
像所有的Java標籤庫一樣,Ajax Tags安裝需要經歷幾個必要的步驟。下面的7步內容示範如何將Ajax Tags加入到2.4節創建的Java Web應用程序中。
第一步:確認運行環境,下載運行包。
Ajax Tags運行需要JDK1.4,以及支持Servlet2.3和JSP1.0的Web服務器,客戶端需要Fireword1.1+或者IE5.0以上版本的瀏覽器。
從Ajax Tags的官方網站下載最新版本的運行包。本文使用其1.1.5版本,它是一個名爲ajaxtags-1.1.5.zip的壓縮包。讀者也可以在本書的隨書光盤software目錄中找到。
下載Prototype framework,版本爲1.3.1,下載地址爲http://prototype.conio.net/。它是一個Javascript運行框架,用來簡化動態Web的編程開發。
如果讀者已經按照本書2.4節的要求創建了開發目錄和工程,並下載了Ajax Tags運行包,則可以跳過這一步。
第二步:複製jar運行包及TLD文件。
複製下載後的jar運行包在{APPLICATION_WEB_HOME}/WEB-INF/lib目錄下。這裏採用1.1.5版本,故運行包名稱爲ajaxtags-1.1.5.jar。開發包內包含Ajax Tags運行所需的API及TLD等文件。
複製TLD文件ajaxtags.tld到{APPLICATION_WEB_HOME}/WEB-INF目錄下。
由於Ajax Tags所使用的標籤必須經過org.apache.taglibs包的解析,所以必須確保Tomcat的ClassLoad路徑中有standard-1.0.6.jar或者其他包含org.apache.taglibs包的jar文件。
第三步:定義TLD映射。
對於JSP1.x的用戶,修改web.xml部署描述文件,將下面這段代碼添加到web.xml文件的標籤庫部分。
<taglib>
<taglib-uri> http://ajaxtags.org/tags/ajax </taglib-uri>
<taglib-location>/WEB-INF/ajaxtags.tld</taglib-location>
</taglib>
第四步:創建服務器端處理程序。
創建必要的服務器端響應處理程序,用來接受並處理瀏覽器發出的Ajax請求。這些處理程序可以是Java Servlet,JSP,Struts Action或者其他不是Java的服務器端組件。惟一的要求是,這些處理程序必須根據Ajax請求返回XML文檔格式的結果列表,如例程11-8所示。
例程11-8 Ajax返回的XML文檔格式
<?xml version="1.0" encoding="UTF-8"?>
<ajax-response>
<response>
<item>
<name>Record 1</name>
<value>1</value>
</item>
<item>
<name>Record 2</name>
<value>2</value>
</item>
<item>
<name>Record 3</name>
<value>3</value>
</item>
</response>
</ajax-response>
第五步:在JSP中定義TLD映射。
在每個需要使用Ajax Tags的JSP文件頭部,添加如下的TLD映射:
<%@ taglib uri="http://ajaxtags.org/tags/ajax" prefix="ajax" %>
第六步:添加Javascript庫文件。
Ajax Tags封裝了必要的Javascript操作,部分支撐函數由Prototype framework提供。將prototype-1.3.1.js和ajaxtags-1.1.5.js兩個js文件複製到{APPLICATION_WEB_HOME}目錄下,同時將以下兩行代碼加入到JSP文件的<head>標籤部分,注意,src的屬性值必須與存放兩個js文件的路徑對應。
<script type="text/javascript" src="prototype-1.3.1.js"></script>
<script type="text/javascript" src="ajaxtags-1.1.5.js"></script>
第七步:定義CSS樣式。
部分Ajax Tags標籤需要CSS樣式支持才能展現良好的效果,比如,ajax:autocomplete標籤就使用了無序列表(UL,LI)樣式來顯示一個下拉的列表。Ajax Tags建議開發人員定義必要的CSS樣式表,之前下載的ajaxtags-1.1.5.zip中包含了一個供示範的CSS樣式表文件。
對於第四步需要生成的XML文檔,Ajax Tags提供了一個名爲org.ajaxtags.helpers. Ajax XmlBuilder的幫助類來協助開發人員生成形式良好的XML文檔,並將這份文檔返回給瀏覽器,而這個過程只須傳入一個列表(List)或者集合(Collection)對象。以返回一個類似第四步的XML文檔爲例,這個文檔表示一個轎車品牌和型號,name值代表品牌,value值代表相應的型號。CarService類的getModelsByName()方法接受一個代表品牌的字符串,返回相應的型號列表。其代碼段如下,modelName將輸出爲XML文檔的name元素值,modelType將輸出爲對應的value值。
CarService service = new CarService();
List list = service.getModelsByName(modelName);
return new AjaxXmlBuilder().addItems(list,"modelName","modelType");
也可以調用AjaxXmlBuilder類的addItem()方法來單獨添加列表:
CarService service = new CarService();
List list = service.getModelsByName(modelName);
AjaxXmlBuilder builder = new AjaxXmlBuilder();
for (Iterator iter = list.iterator(); iter.hasNext();) {
Car car = (Car) iter.next();
builder.addItem(car.getModelName(), car.getModelType());
}
return builder.toString();
由於AjaxXmlBuilder輸出XML文檔時需要用到org.apache.common.beanutils包,所以要確保ClassLoad路徑中能夠找到commons-beanutils.jar,commons-lang-2.1.jar。
Ajax Tags還提供了兩個供參考的Ajax請求處理程序類,這兩個類是針對Java Servlet和Struts Action。org.ajaxtags.servlets.BaseAjaxServlet類是一個抽象類,其他處理類只要繼承這個類並實現getXmlContent(HttpServletRequest, HttpServletResponse)方法。org.ajaxtags. servlets.BaseAjaxAction類與org.ajaxtags.servlets.BaseAjaxServlet類似,只是它是基於Struts Action構建的。
11.2.2 Ajax Tags標籤及其使用方法
目前,Ajax Tags標籤包括ajax:auchors,ajax:area,ajax:autocomplete,ajax:callout,ajax:displayTag,ajax:htmlContent,ajax:portlet,ajax:select,ajax:tabPane,ajax:toggle。先來看看這些標籤的共同屬性及其含義。
1.Ajax Tags標籤的共同屬性及其含義
— baseUrl。
baseUrl是每個Ajax Tags都用到的屬性,用來指定標籤所發出的http請求的目標處理程序的URL地址。例外的是,對於ajax:ajaxPanel標籤,baseUrl只是其子標籤ajax:tab的一個屬性。baseUrl屬性值所指向的目標處理程序必須返回XML文檔格式的結果列表。
— parameters。
parameters也是每個Ajax Tags都用到的屬性,用來爲該標籤發起的http請求添加請求參數和值,這些參數和值將發送到baseUrl屬性所指定的Url地址。這些參數和值以成對的形式出現,多個參數和值之間用逗號隔開。對於每對參數和值,可以指定參數值來自表單的某個域,這種情況的參數值用大括號{}包裹起來,大括號內是其對應的表單域ID,實際值則在事件被觸發的時候取得。比如:
Parameters="modelName={modelId},modelType=A7VM"
— postFunctions。
在某些情況下,需要將兩個Ajax Tags標籤關聯起來,比如,後一個標籤的值根據前一個標籤的情況而改變,這就是postFunction所要做的事情。這個屬性的值是一個Javascript函數的名稱。當前一個標籤的觸發事件已經處理完畢,這個Javascript函數隨即就會被調用。
— errorFunction和emptyFunction。
Ajax Tags支持異常和空對象處理機制。當標籤的errorFunction屬性被指定的時候,如果Ajax發出的請求不能正常執行,則errorFunction屬性值所對應的Javascript函數將被調用。當標籤的emptyFunction屬性被指定的時候,如果Ajax發出的請求返回內容爲空,則emptyFunction屬性值所對應的Javascript函數將被調用。
接下來看看Ajax Tags所定義的各個標籤的含義及其屬性值。
2.ajax:auchors標籤
這個標籤能夠將HTML的<a>鏈接標記包裹的全部內容轉換成Ajax鏈接,向服務器發起異步http請求。實際上,原來的<a>鏈接已經被onClick事件所取代,強制http請求通過Ajax發起。服務器所返回的http請求響應內容將顯示面內任何已經定義的地方,其用法如例程11-9所示。
例程11-9 使用ajax:authors標籤
<ajax:anchors target="ajaxFrame" ajaxFlag="ajaxFrame">
<!-- Ajax this link -->
Refresh first area <a href="${contextPath}/pagearea.jsp" class= "conten tLink"> </a>
</ajax:anchors>
<div id="ajaxFrame"></div>
ajax:auchors標籤包含target和ajaxFlag兩個屬性。其中,target屬性指定http請求響應數據將顯示的頁面區域,通常是一個DIV浮動層的ID。ajaxFlag屬性代表一個布爾值(true/false),用來指定頁面的其餘部分是否應該被Ajax調用忽略,默認值爲false。
3.ajax:area標籤
ajax:area標籤包裹的內容中,全部的<a>等鏈接將被重寫。這些鏈接請求返回響應數據的時候,頁面的某一部分會被更新,而不是刷新整個頁面,其用法如例程11-10所示。
例程11-10 使用ajax:area標籤
<ajax:area id="ajaxFrame"
style="width:300px; min-height:100px; height:100px;"
styleClass="textArea"
ajaxAnchors="true" ajaxFlag="ajaxFrame">
This is the first area and should be refreshed only when the first link or
the link inside itself is clicked:
It may include a link to <a href="${contextPath}/pagearea.jsp"> itse lf </a>
</ajax:area>
ajax:area標籤常用的屬性及其含義如表11-3所示。
表11-3 ajax:area標籤常用的屬性及其含義
屬 性 |
含 義 |
是否必需 |
id |
http請求響應數據將顯示的閉合DIV頁面區域的ID |
是 |
ajaxFlag |
指定頁面的其餘部分是否應該被Ajax調用忽略,布爾值類型,默認值爲false |
否 |
style |
頁面樣式屬性,類似style=”…” |
否 |
styleClass |
頁面樣式標籤名稱,類似class=”…” |
否 |
ajaxAuchors |
是否將區域內的<a>等鏈接全部轉化成onClick事件 |
否 |
ajax:auchors和ajax:area標籤的應用效果如11-10所示,當單擊“itself”鏈接的時候,Date字符串所代表的字符串修改爲當前日期。
圖11-10 ajax:auchors和ajax:area標籤的應用效果
4.ajax:autocomplete標籤
ajax:autocomplete標籤允許從服務器端Servlet提取一個值列表,以下拉列表的顯示在HTML文本框下方,用戶可以從中選擇一項作爲文本框輸入值,即類似Google Suggestion的搜索建議功能。另外,這個標籤還允許第二個區域的值用下拉列表項的值填充。其用法如例程11-11所示。
例程11-11 使用ajax:autocomplete標籤
<form>
Make: <input id="model" name="model" type="text" size="30" class=" form- autocomplete" />
Model: <input id="make" name="make" type="text" size="30" />
</form>
<ajax:autocomplete
baseUrl="${pageContext.request.contextPath}/GetModel.view"
source="make"
target="model"
parameters="model={model}"
className="form-autocomplete"
progressStyle="throbbing"
minimumCharacters="1" />
ajax:autocomplete標籤常用的屬性及其含義如表11-4所示。
表11-4 auto:complete標籤常用的屬性及其含義
屬 性 |
含 義 |
是否必需 |
baseUrl |
搜索並返回一個值列表供下拉列表使用的服務器端Servlet或者Action所對應的URL。支持表達式語言EL |
是 |
source |
用戶輸入搜索內容的文本框,即觸發autocomplete標籤事件的文本框 |
是 |
target |
將用autocomplete標籤下拉列表項的值填充的文本框,可以與source屬性值相同 |
是 |
parameter |
用逗號分隔的傳遞給服務器Servlet/Action的參數列表 |
是 |
className |
下拉列表將使用的樣式標籤名稱 |
是 |
progressStyle |
定義在輸入文本框顯示icon標誌的樣式表 |
否 |
forceSelection |
|
否 |
minimumCharacters |
在autocomplete執行前限制所需最小字符數 |
否 |
appendValue |
指定是把從下拉列表項的值加入文本框中還是簡單的替換,布爾值類型,默認爲false |
否 |
appendSeparator |
當appendValue選擇把從下拉列表項的值加入文本框中時,指定文本框原值和加入值之間的分隔符。如果appendValue屬性值爲false,則此屬性無效 |
否 |
ajax:autocomplete標籤的應用效果如圖11-11和11-12所示,當在文本框Name中輸入字母R的時候,會彈出下拉列表。從該列表中任意選擇一項,該項所對應的值即可填充到文本框Name和Make中。
圖11-11 初始化後的ajax:autocomplete標籤效果
圖11-12 ajax:autocomplete標籤的使用效果
11.2.2 Ajax Tags標籤及其使用方法
目前,Ajax Tags標籤包括ajax:auchors,ajax:area,ajax:autocomplete,ajax:callout,ajax:displayTag,ajax:htmlContent,ajax:portlet,ajax:select,ajax:tabPane,ajax:toggle。先來看看這些標籤的共同屬性及其含義。
1.Ajax Tags標籤的共同屬性及其含義
— baseUrl。
baseUrl是每個Ajax Tags都用到的屬性,用來指定標籤所發出的http請求的目標處理程序的URL地址。例外的是,對於ajax:ajaxPanel標籤,baseUrl只是其子標籤ajax:tab的一個屬性。baseUrl屬性值所指向的目標處理程序必須返回XML文檔格式的結果列表。
— parameters。
parameters也是每個Ajax Tags都用到的屬性,用來爲該標籤發起的http請求添加請求參數和值,這些參數和值將發送到baseUrl屬性所指定的Url地址。這些參數和值以成對的形式出現,多個參數和值之間用逗號隔開。對於每對參數和值,可以指定參數值來自表單的某個域,這種情況的參數值用大括號{}包裹起來,大括號內是其對應的表單域ID,實際值則在事件被觸發的時候取得。比如:
Parameters="modelName={modelId},modelType=A7VM"
— postFunctions。
在某些情況下,需要將兩個Ajax Tags標籤關聯起來,比如,後一個標籤的值根據前一個標籤的情況而改變,這就是postFunction所要做的事情。這個屬性的值是一個Javascript函數的名稱。當前一個標籤的觸發事件已經處理完畢,這個Javascript函數隨即就會被調用。
— errorFunction和emptyFunction。
Ajax Tags支持異常和空對象處理機制。當標籤的errorFunction屬性被指定的時候,如果Ajax發出的請求不能正常執行,則errorFunction屬性值所對應的Javascript函數將被調用。當標籤的emptyFunction屬性被指定的時候,如果Ajax發出的請求返回內容爲空,則emptyFunction屬性值所對應的Javascript函數將被調用。
接下來看看Ajax Tags所定義的各個標籤的含義及其屬性值。
2.ajax:auchors標籤
這個標籤能夠將HTML的<a>鏈接標記包裹的全部內容轉換成Ajax鏈接,向服務器發起異步http請求。實際上,原來的<a>鏈接已經被onClick事件所取代,強制http請求通過Ajax發起。服務器所返回的http請求響應內容將顯示面內任何已經定義的地方,其用法如例程11-9所示。
例程11-9 使用ajax:authors標籤
<ajax:anchors target="ajaxFrame" ajaxFlag="ajaxFrame">
<!-- Ajax this link -->
Refresh first area <a href="${contextPath}/pagearea.jsp" class= "conten tLink"> </a>
</ajax:anchors>
<div id="ajaxFrame"></div>
ajax:auchors標籤包含target和ajaxFlag兩個屬性。其中,target屬性指定http請求響應數據將顯示的頁面區域,通常是一個DIV浮動層的ID。ajaxFlag屬性代表一個布爾值(true/false),用來指定頁面的其餘部分是否應該被Ajax調用忽略,默認值爲false。
3.ajax:area標籤
ajax:area標籤包裹的內容中,全部的<a>等鏈接將被重寫。這些鏈接請求返回響應數據的時候,頁面的某一部分會被更新,而不是刷新整個頁面,其用法如例程11-10所示。
例程11-10 使用ajax:area標籤
<ajax:area id="ajaxFrame"
style="width:300px; min-height:100px; height:100px;"
styleClass="textArea"
ajaxAnchors="true" ajaxFlag="ajaxFrame">
This is the first area and should be refreshed only when the first link or
the link inside itself is clicked:
It may include a link to <a href="${contextPath}/pagearea.jsp"> itse lf </a>
</ajax:area>
ajax:area標籤常用的屬性及其含義如表11-3所示。
表11-3 ajax:area標籤常用的屬性及其含義
屬 性 |
含 義 |
是否必需 |
id |
http請求響應數據將顯示的閉合DIV頁面區域的ID |
是 |
ajaxFlag |
指定頁面的其餘部分是否應該被Ajax調用忽略,布爾值類型,默認值爲false |
否 |
style |
頁面樣式屬性,類似style=”…” |
否 |
styleClass |
頁面樣式標籤名稱,類似class=”…” |
否 |
ajaxAuchors |
是否將區域內的<a>等鏈接全部轉化成onClick事件 |
否 |
ajax:auchors和ajax:area標籤的應用效果如11-10所示,當單擊“itself”鏈接的時候,Date字符串所代表的字符串修改爲當前日期。
圖11-10 ajax:auchors和ajax:area標籤的應用效果
4.ajax:autocomplete標籤
ajax:autocomplete標籤允許從服務器端Servlet提取一個值列表,以下拉列表的顯示在HTML文本框下方,用戶可以從中選擇一項作爲文本框輸入值,即類似Google Suggestion的搜索建議功能。另外,這個標籤還允許第二個區域的值用下拉列表項的值填充。其用法如例程11-11所示。
例程11-11 使用ajax:autocomplete標籤
<form>
Make: <input id="model" name="model" type="text" size="30" class=" form- autocomplete" />
Model: <input id="make" name="make" type="text" size="30" />
</form>
<ajax:autocomplete
baseUrl="${pageContext.request.contextPath}/GetModel.view"
source="make"
target="model"
parameters="model={model}"
className="form-autocomplete"
progressStyle="throbbing"
minimumCharacters="1" />
ajax:autocomplete標籤常用的屬性及其含義如表11-4所示。
表11-4 auto:complete標籤常用的屬性及其含義
屬 性 |
含 義 |
是否必需 |
baseUrl |
搜索並返回一個值列表供下拉列表使用的服務器端Servlet或者Action所對應的URL。支持表達式語言EL |
是 |
source |
用戶輸入搜索內容的文本框,即觸發autocomplete標籤事件的文本框 |
是 |
target |
將用autocomplete標籤下拉列表項的值填充的文本框,可以與source屬性值相同 |
是 |
parameter |
用逗號分隔的傳遞給服務器Servlet/Action的參數列表 |
是 |
className |
下拉列表將使用的樣式標籤名稱 |
是 |
progressStyle |
定義在輸入文本框顯示icon標誌的樣式表 |
否 |
forceSelection |
|
否 |
minimumCharacters |
在autocomplete執行前限制所需最小字符數 |
否 |
appendValue |
指定是把從下拉列表項的值加入文本框中還是簡單的替換,布爾值類型,默認爲false |
否 |
appendSeparator |
當appendValue選擇把從下拉列表項的值加入文本框中時,指定文本框原值和加入值之間的分隔符。如果appendValue屬性值爲false,則此屬性無效 |
否 |
ajax:autocomplete標籤的應用效果如圖11-11和11-12所示,當在文本框Name中輸入字母R的時候,會彈出下拉列表。從該列表中任意選擇一項,該項所對應的值即可填充到文本框Name和Make中。
圖11-11 初始化後的ajax:autocomplete標籤效果
圖11-12 ajax:autocomplete標籤的使用效果
9.ajax:select標籤
ajax:select標籤允許從後臺Servlet或者Action取得一個值列表,填充到另外一個下拉列表框中,形成下拉列表級聯選擇,其用法如例程11-16所示。
圖11-16 ajax:portlet標籤的應用效果
例程11-16 使用ajax:select標籤
<form>
Make:
<select id="make" name="make">
<option value="">Select make</option>
<c:forEach items="${makes}" var="make">
<option value="${make}">${make}</option>
</c:forEach>
</select>
Model:
<select id="model" name="model">
<option value="">Select model</option>
</select>
</form>
<ajax:select
baseUrl="${pageContext.request.contextPath}/GetCarModel.view"
source="make"
target="model"
parameters="make={make}"
postFunction="doOtherThings" />
需要注意的是,ajax:select標籤必須包含在HTML的form標記內部。ajax:select標籤常用的屬性及其含義如表11-9所示。
表11-9 ajax:select標籤常用的屬性及其含義
屬 性 |
含 義 |
是否必需 |
baseUrl |
指定處理請求的服務器端Servlet或者Action的URL |
是 |
source |
形成Ajax搜索請求的初始下拉列表框的ID |
是 |
target |
Ajax請求返回數據將填充的目標下拉列表框的ID |
是 |
parameters |
用逗號分隔的傳遞給服務器Servlet/Action的參數列表 |
是 |
eventType |
指定目標元素觸發ajax行爲填充頁面的事件類型 |
否 |
ajax:select標籤的應用效果如圖11-17和圖11-18所示。當選擇Make下拉列表框的項時,其頂部的圖片被修改,其下方的Model下拉列表框的數據會被更新。
圖11-17 ajax:select標籤初始化後的效果
圖11-18 ajax:select標籤的應用效果
10.ajax:tabPanel標籤
ajax:tabPanel允許創建多個面板頁,各個面板頁的內容來源不同。ajax:tabPanel標籤允許包含一個或者多個ajax:tab子標籤,其用法如例程11-17所示。
例程11-17 使用ajax:tabPanel標籤
<ajax:tabPanel
panelStyleId="tabPanel"
contentStyleId="tabContent"
currentStyleId="ajaxCurrentTab">
<ajax:tab caption="Ford"
baseUrl="${pageContext.request.contextPath}/htmlcontent. view?make=ford"
defaultTab="true"/>
<ajax:tab caption="Honda"
baseUrl="${pageContext.request.contextPath}/htmlcontent.view"
parameters="make=honda"/>
<ajax:tab caption="Mazda"
baseUrl="${pageContext.request.contextPath}/htmlcontent.view"
parameters="make=mazda"/>
</ajax:tabPanel>
ajax:tabPanel標籤主要包含panelStyleId,contentStyleId,currentStyleId三個屬性,分別用來控制面板、面板內容、活動面板的顯示樣式。ajax:tab標籤則主要包含baseUrl,caption,defaultTab,parameters四個屬性,其中baseUrl指定處理請求的服務器端Servlet或者Action的URL;caption屬性指定面板的caption提示信息;defaultTab爲布爾值,指定當前面板爲默認面板;parameters則爲用逗號分隔的傳遞給服務器Servlet/Action的參數列表。
ajax:tabPanel標籤的應用效果如圖11-19所示,其效果類似桌面應用程序的選項卡。這個效果需要定義必要的樣式表。
圖11-19 ajax:tabPanel標籤的應用效果
11.ajax:toggle標籤
ajax:toggle允許修改表單隱藏域的值爲true或者false,或者通過改變圖片的來源替換圖片,或者改變HTML標記innerHTML值,如DIV,其用法如例程11-18所示。
例程11-18 使用ajax:toggle標籤
<img id="watched" src="images/watched_false.gif" />
<div id="watchedResponseContainer">Status is currently:
<span id="watchedResponse">off</span>
</div>
<form>
<input type="hidden" id="watchedStatus" />
</form>
<script type="text/javascript">
function populateResponseContent(xml) {
var root = xml.documentElement;
var respNode = root.getElementsByTagName("response")[0];
var content = getValueForNode(respNode, "toggleContent");
$('watchedResponse').innerHTML = content;
}
</script>
<ajax:toggle
baseUrl="${pageContext.request.contextPath}/ToggleSwitch.view"
image="watched"
stateId="watchedStatus"
stateXmlName="toggleState"
imagePattern="${pageContext.request.contextPath}/img/watched_ {0}.gif"
postFunction="populateResponseContent" />
需要注意的是,ajax:toggle標籤必須包含在HTML的form標記內部。此標籤常用的屬性及其含義如表11-10所示。
表11-10 ajax:toggle標籤常用的屬性及其含義
屬 性 |
含 義 |
是否必需 |
baseUrl |
指定處理請求的服務器端Servlet或者Action的URL |
是 |
image |
開啓toggle功能的圖片的ID |
是 |
state |
用於保存當前狀態的表單隱藏域的ID |
是 |
stateXmlName |
返回的XML文檔中與將顯示到頁面的狀態對應的屬性的名稱 |
是 |
imagePattern |
供替換的圖片的URL地址 |
是 |
parameters |
用逗號分隔的傳遞給服務器Servlet/Action的參數列表 |
否 |
eventType |
指定目標元素觸發toggle行爲的事件類型 |
否 |
ajax:toggle標籤的應用效果如圖11-20所示。當單擊“Toggle Me”左邊的五角星圖像時,其下方的DIV標籤內容會被更改。
圖11-20 ajax:toggle標籤的應用效果
12.ajax:updateField標籤
ajax:updateField標籤允許根據一個表單域的值修改另外一個或者多個表單域的值,其用法如例程11-19所示。
例程11-19 使用ajax:updateField標籤
<form>
<fieldset>
<legend>Velocity Conversion</legend>
<label for="mph">Miles/Hour (mph)</label>
<input type="text" id="mph" />
<input id="action" type="button" value="Go"/>
<label for="kph">Kilometers/Hour (kph)</label>
<input type="text" id="kph" />
<label for="mps">Meters/Second (m/s)</label>
<input type="text" id="mps" />
</fieldset>
</form>
<ajax:updateField
baseUrl="${pageContext.request.contextPath}/ConvertMPH.view"
source="mph"
target="kph,mps"
action="action"
parameters="mph={mph}" />
ajax:updateField標籤常用的屬性及其含義如表11-11所示。
表11-11 ajax:updateField標籤常用的屬性及其含義
屬 性 |
含 義 |
是否必需 |
baseUrl |
指定處理請求的服務器端Servlet或者Action的URL |
是 |
source |
指定持有將傳遞給服務器的參數值的表單域的ID |
是 |
續表
屬 性 |
含 義 |
是否必需 |
target |
將用服務器返回的結果更新值內容的表單域名稱,多個名稱之間用逗號隔開 |
是 |
action |
指定將觸發更新事件的圖片或者按鈕的ID |
是 |
parameters |
用逗號分隔的傳遞給服務器Servlet/Action的參數列表 |
是 |
eventType |
指定目標元素觸發toggle行爲的事件類型 |
|
ajax:updateField標籤的應用效果如圖11-21所示。在“Miles/Hour(mph)”文本框中輸入一個整數值,單擊“Calculate”按鈕,Miles/Hour數值將被計算,結果在其下方的兩個文本框中顯示。
圖11-21 ajax:updateField標籤的應用效果
13.表單域關聯
在Ajax Tags中,多個表單域可以通過標籤關聯起來,形成依賴關係。最常用的方式是使用單個或者多個ajax:select標籤。比如,在接下來的例子中,用戶需要先後選擇製造商、型號、生產年月,其表單域的HTML代碼如例程11-20所示。其中,make下拉列表框使用JSTL的c:forEach標籤來完成option值的循環迭代。
例程11-20 表單域關聯的HTML代碼
<form>
Make:
<select id="make" name="make">
<option value="">Select make</option>
<c:forEach items="${makes}" var="make">
<option value="${make}">${make}</option>
</c:forEach>
</select>
Model:
<select id="model" name="model" disabled="true">
<option value="">Select make</option>
</select>
Year:
<select id="year" name="year" disabled="true">
<option value="">Select model</option>
</select>
</form>
這個例子並未設置model和year兩個下拉列表框的option初始值,它是通過用戶選擇make下拉列表框後由Ajax Tags標籤來獲取並填充。所以,需要使用兩個ajax:select標籤,第一個ajax:select標籤將make和model兩個下拉列表框關聯起來,第二個ajax:select標籤將model和year兩個下拉列表框關聯起來,其代碼如例程11-21所示。
例程11-21 使用ajax:select標籤實現表單域關聯
<ajax:select
fieldId="make"
targetId="model"
baseUrl="${pageContext.request.contextPath}/GetCarModel.view"
paramName="make"
postFunc="doOtherThings"/>
<ajax:select
fieldId="model"
targetId="year"
baseUrl="${pageContext.request.contextPath}/GetCarYear.view"
paramName="model"
postFunc="doOtherThings"/>
因此,當選擇下拉列表框make的時候,服務器返回的數據被用來填充下拉列表框model;當選擇下拉列表框model的時候,服務器返回的數據則被用來填充下拉列表框year。這種方式很容易構成多級級聯的下拉列表框。
DWR是一個框架,簡單的說就是能夠在javascript直接調用java方法,而不必去寫一大堆的javascript代碼。它的實現是基於ajax的,可以實現無刷新效果。
網上有不少DWR的例子,但大都只是某種方法的調用,本文只在使用層面上介紹DWR,並不涉更多的技術與設計,其目的是讓初學者能夠很快的學會各種java方法在javascript中是如何調用的。
本文以DWR 1.1爲基礎,對於DWR 2.0,因爲還沒有正式發佈版,故不做介紹。
一、dwr配置篇之web.xml
1 、最小配置
<servlet>
<servlet-name>dwr-invoker</servlet-name>
<servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>dwr-invoker</servlet-name>
<url-pattern>/dwr/*</url-pattern>
</servlet-mapping>
2、當我們想看DWR自動生成的測試頁(Using debug/test mode)時,可在servlet配置中加上
<init-param>
<param-name>debug</param-name>
<param-value>true</param-value>
</init-param>
這個參數DWR默認是false。如果選擇true,我們可以通過http://localhost:port/app/dwr看到你部署的每個DWR class。並且可以測試java代碼的每個方法是否運行正常。爲了安全考慮,在正式環境下你一定把這個參數設爲false。
3、多個dwr.xml文件的配置
可能有幾種情況,我們一一列舉。一個servlet,多個dwr.xml配置文件;多個servlet,每個servlet對應一個或多個dwr.xml配置文件。
3.1、一個servlet,多個dwr.xml配置文件
<servlet>
<servlet-name>dwr-invoker</servlet-name>
<servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class>
<init-param>
<param-name>config-1</param-name>
<param-value>WEB-INF/dwr1.xml</param-value>
</init-param>
<init-param>
<param-name>config-2</param-name>
<param-value>WEB-INF/dwr2.xml</param-value>
</init-param>
</servlet>
在這種配置下,param-name的值必須以config開頭。param-name可以有>=0個。如果沒有param-name,那麼將會讀取 WEB-INF/dwr.xml。如果有大於零個param-name,那麼WEB-INF/dwr.xml文件將不會被讀取。
3.2 、多個 servlet,每個 servlet 對應一個或多個 dwr.xml
<servlet>
<servlet-name>dwr-invoker</servlet-name>
<servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>dwr-invoker1</servlet-name>
<servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class>
<init-param>
<param-name>config-admin</param-name>
<param-value>WEB-INF/dwr1.xml</param-value>
</init-param>
<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>
<servlet-mapping>
<servlet-name>dwr-invoker1</servlet-name>
<url-pattern>/dwr1/*</url-pattern>
</servlet-mapping>
在這種情況下,我們可以根據J2EE security來控制權限,針對不同url,加不同的角色。
二、dwr使用篇
1、調用沒有返回值和參數的JAVA方法
1.1、dwr.xml的配置
<dwr>
<allow>
<create creator="new" javascript="testClass" >
<param name="class" value="com.dwr.TestClass" />
<include method="testMethod1"/>
</create>
</allow>
</dwr>
<allow>標籤中包括可以暴露給 javascript訪問的東西。
<create>標籤中指定 javascript中可以訪問的 java 類,並定義 DWR 應當如何獲得要進行遠程的類的實例。 creator="new"屬性指定 java 類實例的生成方式, new 意味着 DWR應當調用類的默認構造函數來獲得實例,其他的還有 spring方式,通過與 IOC 容器 Spring 進行集成來獲得實例等等。 javascript=" testClass "屬性指定 javascript代碼訪問對象時使用的名稱。
<param>標籤指定要公開給 javascript的 java 類名。
<include>標籤指定要公開給 javascript的方法。不指定的話就公開所有方法。
<exclude>標籤指定要防止被訪問的方法。
1.2、javascript中調用
首先,引入 javascript腳本
<script src='dwr/interface/ testClass.js'></script>
<script src='dwr/engine.js'></script>
<script src='dwr/util.js'></script>
其中 TestClass.js是 dwr 根據配置文件自動生成的, engine.js 和 util.js 是 dwr自帶的腳本文件。
其次,編寫調用 java方法的 javascript 函數
Function callTestMethod1(){
testClass.testMethod1();
}
2、調用有簡單返回值的java方法
2.1、dwr.xml的配置
配置同1.1
<dwr>
<allow>
<create creator="new" javascript="testClass" >
<param name="class" value="com.dwr.TestClass" />
<include method="testMethod2"/>
</create>
</allow>
</dwr>
2.2、javascript中調用
首先,引入 javascript腳本
其次,編寫調用 java方法的 javascript 函數和接收返回值的回調函數
Function callTestMethod2(){
testClass.testMethod2(callBackFortestMethod2);
}
Function callBackFortestMethod2(data){
//其中 date接收方法的返回值
//可以在這裏對返回值進行處理和顯示等等
alert("the return value is " + data);
}
其中 callBackFortestMethod2是接收返回值的回調函數
3、調用有簡單參數的java方法
3.1、dwr.xml的配置
配置同1.1
<dwr>
<allow>
<create creator="new" javascript="testClass" >
<param name="class" value="com.dwr.TestClass" />
<include method="testMethod3"/>
</create>
</allow>
</dwr>
3.2、javascript中調用
首先,引入 javascript腳本
其次,編寫調用 java方法的 javascript 函數
Function callTestMethod3(){
//定義要傳到 java方法中的參數
var data;
//構造參數
data = “test String”;
testClass.testMethod3(data);
}
4、調用返回JavaBean的java方法
4.1、dwr.xml的配置
<dwr>
<allow>
<create creator="new" javascript="testClass" >
<param name="class" value="com.dwr.TestClass" />
<include method="testMethod4"/>
</create>
<convert converter="bean" match=""com.dwr.TestBean">
<param name="include" value="username,password" />
</convert>
</allow>
</dwr>
<creator>標籤負責公開用於 Web遠程的類和類的方法, <convertor>標籤則負責這些方法的參數和返回類型。 convert元素的作用是告訴 DWR 在服務器端 Java 對象表示和序列化的 JavaScript之間如何轉換數據類型。 DWR自動地在 Java 和 JavaScript 表示之間調整簡單數據類型。這些類型包括 Java原生類型和它們各自的封裝類表示,還有 String、 Date 、數組和集合類型。 DWR 也能把 JavaBean轉換成 JavaScript 表示,但是出於安全性的原因,要求顯式的配置, <convertor>標籤就是完成此功能的。 converter="bean"屬性指定轉換的方式採用 JavaBean命名規範, match=""com.dwr.TestBean"屬性指定要轉換的 javabean名稱, <param> 標籤指定要轉換的 JavaBean 屬性。
4.2、javascript中調用
首先,引入 javascript腳本
其次,編寫調用 java方法的 javascript 函數和接收返回值的回調函數
Function callTestMethod4(){
testClass.testMethod4(callBackFortestMethod4);
}
Function callBackFortestMethod4(data){
//其中 date接收方法的返回值
//對於 JavaBean返回值,有兩種方式處理
//不知道屬性名稱時,使用如下方法
for(var property in data){
alert("property:"+property);
alert(property+":"+data[property]);
}
//知道屬性名稱時,使用如下方法
alert(data.username);
alert(data.password);
}
其中 callBackFortestMethod4是接收返回值的回調函數
5、調用有JavaBean參數的java方法
5.1、dwr.xml的配置
配置同4.1
<dwr>
<allow>
<create creator="new" javascript="testClass" >
<param name="class" value="com.dwr.TestClass" />
<include method="testMethod5"/>
</create>
<convert converter="bean" match="com.dwr.TestBean">
<param name="include" value="username,password" />
</convert>
</allow>
</dwr>
5.2、javascript中調用
首先,引入 javascript腳本
其次,編寫調用 java方法的 javascript 函數
Function callTestMethod5(){
//定義要傳到 java方法中的參數
var data;
//構造參數, date實際上是一個 object
data = { username:"user", password:"password" }
testClass.testMethod5(data);
}
6、調用返回List、Set或者Map的java方法
6.1、dwr.xml的配置
配置同4.1
<dwr>
<allow>
<create creator="new" javascript="testClass" >
<param name="class" value="com.dwr.TestClass" />
<include method="testMethod6"/>
</create>
<convert converter="bean" match="com.dwr.TestBean ">
<param name="include" value="username,password" />
</convert>
</allow>
</dwr>
注意:如果 List、 Set 或者 Map 中的元素均爲簡單類型(包括其封裝類)或 String、 Date 、數組和集合類型,則不需要<convert>標籤。
6.2、javascript中調用(以返回List爲例,List的元素爲TestBean)
首先,引入 javascript腳本
其次,編寫調用 java方法的 javascript 函數和接收返回值的回調函數
Function callTestMethod6(){
testClass.testMethod6(callBackFortestMethod6);
}
Function callBackFortestMethod6(data){
//其中 date接收方法的返回值
//對於 JavaBean返回值,有兩種方式處理
//不知道屬性名稱時,使用如下方法
for(var i=0;i<data.length;i++){
for(var property in data){
alert("property:"+property);
alert(property+":"+data[property]);
}
}
//知道屬性名稱時,使用如下方法
for(var i=0;i<data.length;i++){
alert(data.username);
alert(data.password);
}
}
7、調用有List、Set或者Map參數的java方法
7.1、dwr.xml的配置
<dwr>
<allow>
<create creator="new" javascript="testClass" >
<param name="class" value="com.dwr.TestClass" />
<include method="testMethod7"/>
</create>
<convert converter="bean" match="com.dwr.TestBean ">
<param name="include" value="username,password" />
</convert>
</allow>
<signatures>
<![CDATA[
import java.util.List;
import com.dwr.TestClass;
import com.dwr.TestBean;
TestClass.testMethod7(List<TestBean>);
]]>
</signatures>
</dwr>
<signatures>標籤是用來聲明 java方法中 List 、 Set 或者 Map參數所包含的確切類,以便 java代碼作出判斷。
7.2、javascript中調用(以返回List爲例,List的元素爲TestBean)
首先,引入 javascript腳本
其次,編寫調用 java方法的 javascript 函數
Function callTestMethod7(){
//定義要傳到 java方法中的參數
var data;
//構造參數, date實際上是一個 object 數組,即數組的每個元素均爲 object
data= [
{
username:"user1",
password:"password2"
},
{
username:"user2",
password:" password2"
}
];
testClass.testMethod7(data);
}
注意:
1、對於第 6種情況,如果 java 方法的返回值爲 Map ,則在接收該返回值的 javascript回調函數中如下處理:
function callBackFortestMethod(data){
//其中date接收方法的返回值
for(var property in data){
var bean = data[property];
alert(bean.username);
alert(bean.password);
}
}
2、對於第 7種情況,如果 java 的方法的參數爲 Map (假設其 key爲 String , value 爲 TestBean),則在調用該方法的 javascript函數中用如下方法構造要傳遞的參數:
function callTestMethod (){
//定義要傳到java方法中的參數
var data;
//構造參數,date實際上是一個object,其屬性名爲Map的key,屬性值爲Map的value
data = {
"key1":{
username:"user1",
password:"password2"
},
"key2":{
username:"user2",
password:" password2"
}
};
testClass.testMethod(data);
}
並且在dwr.xml中增加如下的配置段
<signatures>
<![CDATA[
import java.util.List;
import com.dwr.TestClass;
import com.dwr.TestBean;
TestClass.testMethod7(Map<String,TestBean>);
]]>
</signatures>
3、由以上可以發現,對於 java方法的返回值爲 List(Set)的情況, DWR 將其轉化爲 Object 數組,傳遞個 javascript;對於 java 方法的返回值爲 Map 的情況, DWR將其轉化爲一個 Object ,其中 Object 的屬性爲原 Map的 key 值,屬性值爲原 Map 相應的 value值。
4、如果 java方法的參數爲 List(Set)和 Map 的情況, javascript 中也要根據 3 種所說,構造相應的 javascript數據來傳遞到 java 中。
轉自他處,
http://blog.csdn.net/zhaizhanpo/article/details/2988512