最近閑暇時(shí),研究了一下DWR框架,個(gè)人感覺是一個(gè)很不錯(cuò)很好用的Ajax框架,封裝的很好
DWR入門
1.1 簡介
DWR是一個(gè)可以允許你去創(chuàng)建AJAX WEB站點(diǎn)的JAVA開源庫。它可以讓你在瀏覽器中的Javascript代碼調(diào)用Web服務(wù)器上的Java代碼,就像在Java
代碼就在瀏覽器中一樣。 DWR包含2個(gè)主要部分:
? 一個(gè)運(yùn)行在服務(wù)器端的Java Servlet,它處理請(qǐng)求并且向?yàn)g覽器發(fā)回響應(yīng)。
? 運(yùn)行在瀏覽器端的JavaScript,它發(fā)送請(qǐng)求而且還能動(dòng)態(tài)更新網(wǎng)頁。
DWR工作原理是通過動(dòng)態(tài)把Java類生成為Javascript。它的代碼就像Ajax魔法一樣,你感覺調(diào)用就像發(fā)生在瀏覽器端,但是實(shí)際上代碼調(diào)用發(fā)生
在服務(wù)器端,DWR負(fù)責(zé)數(shù)據(jù)的傳遞和轉(zhuǎn)換。這種從Java到JavaScript的遠(yuǎn)程調(diào)用功能的方式使DWR用起來有種非常像RMI或者SOAP的常規(guī)RPC機(jī)制
,而且DWR的優(yōu)點(diǎn)在于不需要任何的網(wǎng)頁瀏覽器插件就能運(yùn)行在網(wǎng)頁上。 Java從根本上講是同步機(jī)制,然而AJAX卻是異步的。所以你調(diào)用遠(yuǎn)程
方法時(shí),當(dāng)數(shù)據(jù)已經(jīng)從網(wǎng)絡(luò)上返回的時(shí)候,你要提供有反調(diào) (callback) 功能的DWR。
http://www.java3z.com/cwbwebhome/article/article2/img4/r_howitworks.png
1.2 第一個(gè)DWR程序:Hello World
1.2.1 將DWR放入你的工程
1) 從官方網(wǎng)站下載dwr.jar包。然后將它放在你webapp的WEB-INF/lib目錄下。
2) 將下載的dwr-版本號(hào)-src.zip \java\org\directwebremoting內(nèi)的engine.js和util.js放入WEB應(yīng)用中,比如js文件夾下。
1.2.2 編輯配置文件
1). ------------------web.xml---------------------------------------------
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
xmlns="
xmlns:xsi="
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
<servlet>
<servlet-name>dwr-invoker</servlet-name>
<servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>true</param-value>
</init-param>
<!-- 是servlet的加載順序 數(shù)字越小代表加載的優(yōu)先級(jí)越高 -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping> <dwr> <allow> <create creator="new" javascript="service"> </allow> </dwr> 后點(diǎn)擊“Execute”,如果發(fā)現(xiàn)確實(shí)是正確的返回結(jié)果,說明測(cè)試通過了,可以進(jìn)入下一步了。 2.2 常用<init-param>參數(shù)列表(web.xml中的) 2.2.1 安全參數(shù) --------------------------------------------------------dwr.xml配置---------------------------------------------- <?xml version="1.0" encoding="UTF-8"?> 3.2 <init>標(biāo)簽 3.3 <allow>標(biāo)簽 create元素是如下的結(jié)構(gòu): <allow> 1).new:Java用“new”關(guān)鍵字創(chuàng)造對(duì)象 是DWR默認(rèn)的creator,如下所示 <create id="new" class="org.directwebremoting.create.NewCreator"/> (v1.1+) none創(chuàng)建器不創(chuàng)建任何對(duì)象,它會(huì)假設(shè)你不須要?jiǎng)?chuàng)建對(duì)象。有2個(gè)使用的原因: 2. javascript屬性 <create creator="new" javascript="service"> <param name="class" value="helloWorld.Service" /> </create> <html> <head> … <script type='text/javascript' src='dwr/interface/service.js'> … 3. scope屬性 4. param元素 <create creator="new" javascript="Fred"> 你不需要在dwr.xml中<allow>部分的<convert>中定義。它們默認(rèn)支持。 1. 日期轉(zhuǎn)換器 2. 數(shù)組轉(zhuǎn)換器 <convert converter="bean" match="your.full.package.BeanName"/> 這就是說屬性要符合一下條件:有g(shù)etter和setter,setter有一個(gè)參數(shù),并且這個(gè)參數(shù)的類型是getter的返回類型。setter應(yīng)該返回void,getter應(yīng)該沒有任何參數(shù)。setter沒有重載。以上這些屬于常識(shí)。就在eclipse里自動(dòng)為每個(gè)屬性添加setter,getter那種類型,如果你用的不是JavaBean,那么你應(yīng)該用ObjectConverter. public void setPerson(Person p) { // ... } } public class Person { public void setName(String name) { ... } public void setAge(int age) { ... } // ... } 如果這個(gè)Remoted已經(jīng)被配置成Creator了,Persion類也定義了BeanConverter,那么你可以通過下面的方式調(diào)用Java代碼: var p = { name:"Fred", age:21 }; Remoted.setPerson(p); 4. 集合類型轉(zhuǎn)換器 <convert converter="collection" match="java.util.Collection"/> <convert converter="map" match="java.util.Map"/> 4.7 DWR與WebWork <create creator="none" javascript="DWRAction"> 這樣你AjaxWebWork Action調(diào)用返回一個(gè)action實(shí)例(而不是文字)。然后你必須包括action對(duì)象的轉(zhuǎn)換 ------------------------------------------DWR中的JavaScript簡介--------------------------------------------- DWR根據(jù)dwr.xml生成和Java代碼類似的Javascript代碼。 相對(duì)而言Java同步調(diào)用,創(chuàng)建與Java代碼匹配的Ajax遠(yuǎn)程調(diào)用接口的最大挑戰(zhàn)來至與實(shí)現(xiàn)Ajax的異步調(diào)用特性。 5.1 簡單的回調(diào)函數(shù) 假設(shè)你有一個(gè)這樣的Java方法: <script type='text/javascript' src='[WEBAPP]/dwr/engine.js'></script> 42是Java方法getData()的一個(gè)參數(shù)。 此外你也可以使用這種減縮格式: Remote.getData(42, function(str) { alert(str); }); 5.2 調(diào)用元數(shù)據(jù)對(duì)象 Remote.getData(42, { callback:function(str) { alert(str); } }); ---------------------------------------------------- util.js 功能----------------------------------------------------- 7.3 addRows and removeAllRows ? DWRUtil.addRows() 7.6 getValues 7.9 setValue 最簡單的做法時(shí)在onload事件中調(diào)用DWRUtil.useLoadingMessage,像這樣: <head> <script> function init() { DWRUtil.useLoadingMessage(); } </script> ... </head> <body onload="init();"> ... function useLoadingImage(imageSrc) { var loadingImage; if (imageSrc) loadingImage = imageSrc; else loadingImage = "ajax-loader.gif"; DWREngine.setPreHook(function() { var disabledImageZone = $('disabledImageZone'); if (!disabledImageZone) { disabledImageZone = document.createElement('div'); disabledImageZone.setAttribute('id', 'disabledImageZone'); disabledImageZone.style.position = "absolute"; disabledImageZone.style.zIndex = "1000"; disabledImageZone.style.left = "0px"; disabledImageZone.style.top = "0px"; disabledImageZone.style.width = "100%"; disabledImageZone.style.height = "100%"; var imageZone = document.createElement('img'); imageZone.setAttribute('id','imageZone'); imageZone.setAttribute('src',imageSrc); imageZone.style.position = "absolute"; imageZone.style.top = "0px"; imageZone.style.right = "0px"; disabledImageZone.appendChild(imageZone); document.body.appendChild(disabledImageZone); } else { $('imageZone').src = imageSrc; disabledImageZone.style.visibility = 'visible'; } }); DWREngine.setPostHook(function() { $('disabledImageZone').style.visibility = 'hidden'; }); } 7.13 Submission box 8.5 安全 完結(jié)。。
<servlet-name>dwr-invoker</servlet-name>
<url-pattern>/dwr/*</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
2).--------------------------dwr.xml----------------------------------------------
在web.xml的同一目錄下,創(chuàng)建dwr.xml,
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 2.0//EN" "
<param name="class" value="helloWorld.Service"/>
</create>
3)。 編寫---------------------------service.java--------------------------------
就像沒有dwr一樣,寫一個(gè)簡單類并加一個(gè)方法 是
package helloWorld;
public class Service
{ public String sayHello(String yourName)
{ //可以是訪問數(shù)據(jù)庫的復(fù)雜代碼
return "Hello World " + yourName;
}
}
4)。 -----------------------------------測(cè)試DWR-------------------------------------
將代碼放入應(yīng)用服務(wù)器(比如Tomcat),啟動(dòng)。
然后在地址欄輸入http://localhost:8080/你的工程/dwr 然后點(diǎn)擊service,會(huì)看到剛才寫的sayHello()的方法,輸入自己的名字然
5)。--------------------------------- 編寫一個(gè) index.jsp---------------------------------
<%@ page language="java" pageEncoding="UTF-8"%>
<html>
<head>
<title>My JSP 'first_dwr.jsp' starting page</title>
<script type='text/javascript' src="js/util.js"></script>
<script type='text/javascript' src="js/engine.js"></script>
<script type='text/javascript' src="js/service.js"> </script>
<script type="text/javascript">
function firstDwr()
{
service.sayHello("孤魂",callBackHello);
}
function callBackHello(data){
alert(data);
}
</script>
</head>
<body>
<input type="button" name="button" value="測(cè)試" onclick="firstDwr()">
</body>
</html>
allowGetForSafariButMakeForgeryEasier
開始版本:2.0
默認(rèn)值:false
描述:置成true使DWR工作在Safari 1.x , 會(huì)稍微降低安全性。
crossDomainSessionSecurity
開始版本:2.0
默認(rèn)值:true
描述:設(shè)置成false使能夠從其他域進(jìn)行請(qǐng)求。注意,這樣做會(huì)在安全性上有點(diǎn)冒險(xiǎn),參考一下這篇文章,在沒有理解這個(gè)后果前不要設(shè)置成為false。
debug
開始版本:1.0
默認(rèn)值:false
描述:設(shè)置成true使DWR能夠debug和進(jìn)入測(cè)試頁面
scriptSessionTimeout
開始版本:2.0
默認(rèn)值:1800000(30分鐘)
描述:script session 的超時(shí)設(shè)置
maxCallCount
開始版本:2.0rc2 和 1.1.4
默認(rèn)值:20
描述:一次批量(batch)允許最大的調(diào)用數(shù)量。(幫助保護(hù)Dos攻擊)
2.2.2 Ajax服務(wù)器加載時(shí)保護(hù)參數(shù)
pollAndCometEnabled
開始版本:2.0
默認(rèn)值:false
描述:設(shè)置成true能增加服務(wù)器的加載能力,盡管DWR有保護(hù)服務(wù)器過載的機(jī)制。
maxWaitingThreads
開始版本:2.0
默認(rèn)值:100
描述:最大等待線程數(shù)量。
preStreamWaitTime
開始版本:2.0
默認(rèn)值:29000(單位:毫秒)
描述:對(duì)一個(gè)打開流前的反應(yīng),等待的最大時(shí)間
postStreamWaitTime
開始版本:2.0
默認(rèn)值:1000(單位:毫秒)
描述:對(duì)一個(gè)打開流后的反應(yīng),等待的最大時(shí)間
2.3 日志配置
DWR工作在JDK1.3中不支持java.util.logging,但我們并不強(qiáng)迫任何人都去使用commons-logging或者log4j,所以在使用HttpServlet.log()方法時(shí)DWR將正常工作,如果沒有日志類的話。然而如果DWR可以使用,那么它將使用日志。
Commoms-Logging
由于大多數(shù)servlet容器都使用它,幾乎每個(gè)人都將使用commons-logging。所以如果你的webapp不明確使用commons-logging,它將被默認(rèn)設(shè)為可以使用。 在這些日志將被一些配置文件所約束,比如java.util.logging或者log4j,可以去查看他們各自的文檔獲得詳情。
HttpServlet.log()
如果你正在使用HttpServlet.log(), 以下的代碼用來控制DWR日志
<init-param>
<param-name>logLevel</param-name>
<param-value>DEBUG</param-value>
</init-param>
值可以是:FATAL,ERROR,WARN(默認(rèn)),INFO,DEBUG
DWR2.0插件
? org.directwebremoting.Container
? org.directwebremoting.WebContextFactory.WebContextBuilder
? org.directwebremoting.ServerContextFactory.ServerContextBuilder
? org.directwebremoting.servlet.UrlProcessor
? org.directwebremoting.extend.AccessControl
? org.directwebremoting.extend.AjaxFilterManager
? org.directwebremoting.extend.ConverterManager
? org.directwebremoting.extend.CreatorManager
? org.directwebremoting.extend.DebugPageGenerator
? org.directwebremoting.extend.HtmlCallMarshaller
? org.directwebremoting.extend.HtmlPollHandler
? org.directwebremoting.extend.PageNormalizer
? org.directwebremoting.extend.PlainCallMarshaller
? org.directwebremoting.extend.PlainPollHandler
? org.directwebremoting.extend.Remoter
? org.directwebremoting.extend.ScriptSessionManager
? org.directwebremoting.extend.ServerLoadMonitor
<!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 2.0//EN" "
<dwr>
<!-- 僅當(dāng)需要擴(kuò)展DWR時(shí)才需要 -->
<init>
<creator id="..." class="..." />
<converter id="..." class="..." />
</init><!-- 沒有它DWR什么也做不了 -->
<allow>
<create creator="..." javascript="..." />
<convert converter="..." match="..." />
</allow><!-- 有必要告訴DWR方法簽名 -->
<signatures>...</signatures>
</dwr>
這個(gè)初始化部分申明被用來創(chuàng)建遠(yuǎn)程beans而且這個(gè)類能被用來以某種過程轉(zhuǎn)換。大多數(shù)例子你將不需要用它,如果你想去定義一個(gè)新的Creator或者Converter,就要在此被申明。 在init部分里有了定義只是告訴DWR這些擴(kuò)展類的存在,給出了如何使用的信息。這時(shí)他們還沒有被使用。這種方式很像Java中的import語句。多數(shù)類需要在使用前先import一下,但是只有import語句并不表明這個(gè)類已經(jīng)被使用了。每一個(gè)creator和converter都用id屬性,以便后面使用。
allow部分定義了DWR能夠創(chuàng)建和轉(zhuǎn)換的類。
3.3.1 Creator
每一個(gè)在類中被調(diào)用的方法需要一個(gè)<create …>有若干類型的creator,使用“new”關(guān)鍵字或者Spring 框架等。
<create creator="..." javascript="..." scope="...">
<param name="..." value="..." />
<auth method="..." role="..." />
<exclude method="..." />
<include method="..." />
</create>
...
</allow>
沒有必要把它加入dwr.xml,它已經(jīng)在DWR內(nèi)部文件了。 這個(gè)creator將使用默認(rèn)構(gòu)造器創(chuàng)建類的實(shí)例,以下是用new創(chuàng)建器的好處
? 安全:DWR創(chuàng)造的對(duì)象生存的時(shí)間越短,多次調(diào)用中間的值不一致的錯(cuò)誤機(jī)會(huì)越少。
? 內(nèi)存消耗低: 如果你的站點(diǎn)用戶量非常大,這個(gè)創(chuàng)造器可以減少VM的內(nèi)存溢出。
2).none: 它不創(chuàng)建對(duì)象,看下面的原因。
? 你可能在使用的scope不是"page"(看上面),并在在前面已經(jīng)把這個(gè)對(duì)象創(chuàng)建到這個(gè)scope中了,這時(shí)你就不需要再創(chuàng)建對(duì)象了。
? 還有一種情況是要調(diào)用的方法是靜態(tài)的,這時(shí)也不需要?jiǎng)?chuàng)建對(duì)象。DWR會(huì)在調(diào)用創(chuàng)建器之前先檢查一下這個(gè)方法是不是靜態(tài)的。
在瀏覽器里給你創(chuàng)建的對(duì)象命名。避免使用JavaScript保留字。這個(gè)名字將在頁面里作為js被導(dǎo)入,就像第2章節(jié)的那個(gè)jsp: dwr.xml
html / jsp:
和定義在servlet的scope一樣大的范圍,它允許你指定哪個(gè)bean是可以獲得的。選項(xiàng)可以是:application, session, request和page。這些值應(yīng)該已經(jīng)被開發(fā)者們熟悉了。
被用來指定創(chuàng)造器的其他參數(shù),每種構(gòu)造器各有不同。例如,"new"創(chuàng)造器需要知道要?jiǎng)?chuàng)建的對(duì)象類型是什么。每一個(gè)創(chuàng)造器的參數(shù)在各自的文檔中能找到。
5. include和exclude元素
允許一個(gè)創(chuàng)造器去限制進(jìn)入類的方法。一個(gè)創(chuàng)造器必須指定include列表或exclude列表之一。如果是include列表則暗示默認(rèn)的訪問策略是"拒絕",include中的每個(gè)方法就是允許訪問的方法;如果是exclude列表則暗示默認(rèn)的訪問策略是"允許",exclude中的每個(gè)方法就是拒絕訪問的方法。 比如:
<param name="class" value="com.example.Fred" />
<include method="setWibble" />
</create>
3.3.2 Converter
我們需要確認(rèn)所有的參數(shù)能被轉(zhuǎn)換。許多JDK提供的類型使你能夠使用,但是你如果要轉(zhuǎn)換你自己的代碼,就必須告訴DWR。一般是指JavaBean的參數(shù)需要一個(gè)<convert…>標(biāo)簽作為入口。
? 所有主要的類型,boolean, int , double等等。
? 包裝類,Boolean, Integer等等。
? java.lang.String
? java.util.Date 和 java.sql.Times,java.sql.Timestamp。
? 數(shù)組(存放以上類型的)
? 集合類型 (List, Set, Map, Iterator等等) (存放以上類型的)
? DOM對(duì)象(來自于DOM, XOM, JDOM和DOM4J)
如果你有一個(gè)String(例如:“2001-02-11”)在Javascript,你想把它轉(zhuǎn)換成Java日期。那么你有2種選擇,一是使用Date.parse()然后使用DataConverter傳入服務(wù)器端,還有一種選擇是把該String傳入,然后用java的SimpleDateFormat(或者其他的)來轉(zhuǎn)換。 同樣,如果你有個(gè)Java的Date類型并且希望在HTML使用它。你可以先用SimpleDateFormat把它轉(zhuǎn)換成字符串再使用。也可以直接傳Date給Javascript,然后用Javascript格式化。第一種方式簡單一些,盡管浪費(fèi)了你的轉(zhuǎn)換器,而且這樣做也會(huì)是瀏覽器上的顯示邏輯受到限制。其實(shí)后面的方法更好,也有一些工具可以幫你
數(shù)組實(shí)體不太容易理解。默認(rèn)情況下DWR能轉(zhuǎn)換所有原生類型的數(shù)組,還有所有marshallable對(duì)象的數(shù)組。這些marshallable對(duì)象包括前面介紹的String和Date類型。match屬性看上去很怪。
3. bean和對(duì)象轉(zhuǎn)換器
兩個(gè)沒有默認(rèn)打開的轉(zhuǎn)換器是Bean 和 Object 轉(zhuǎn)換器。Bean轉(zhuǎn)換器可以把POJO轉(zhuǎn)換成Javascript的接合數(shù)組(類似與Java中的Map),或者反向轉(zhuǎn)換。這個(gè)轉(zhuǎn)換器默認(rèn)情況下是沒打開的,因?yàn)镈WR要獲得你的允許才能動(dòng)你的代碼。 Object轉(zhuǎn)換器很相似,不同的是它直接應(yīng)用于對(duì)象的成員,而不是通過getter和setter方法。下面的例子都是可以用object來替換bean的來直接訪問對(duì)象成員。 如果你有一個(gè)在 <create ...> 中聲明的遠(yuǎn)程調(diào)用Bean。它有個(gè)一參數(shù)也是一個(gè)bean,并且這個(gè)bean有一個(gè)setter存在一些安全隱患,那么攻擊者就可能利用這一點(diǎn)。 你可以為某一個(gè)單獨(dú)的類打開轉(zhuǎn)換器:
如果要允許轉(zhuǎn)換一個(gè)包或者子包下面的所有類,可以這樣寫: <convert converter="bean" match="your.full.package.*"/>
顯而易見,這樣寫是允許轉(zhuǎn)換所有的JavaBean: <convert converter="bean" match="*"/>
? BeanConverter 和 JavaBeans 規(guī)范 用于被BeanConverter轉(zhuǎn)換的Bean必須符合JavaBeans的規(guī)范,因?yàn)檗D(zhuǎn)換器用的是Introspection,而不是Reflection。
? 設(shè)置Javascript變量 DWR可以把Javascript對(duì)象(又名maps,或聯(lián)合數(shù)組)轉(zhuǎn)換成JavaBean或者Java對(duì)象。例子:
public class Remoted {
有個(gè)兩個(gè)默認(rèn)的轉(zhuǎn)換器,針對(duì)Map和Collection:
WebWork支持在DWR2.0m3以后才有。 要可以通過DWR調(diào)用WW的Action,要做兩件事。
4.7.1 配置dwr.xml
你必須在dwr的配置文件中加入這樣的配置:
<param name="class" value="org.directwebremoting.webwork.DWRAction" />
<include method="execute" />
</create>
<convert converter="bean"
match="org.directwebremoting.webwork.ActionDefinition">
<param name="include" value="namespace,action,method,executeResult" />
</convert>
<convert converter="bean"
match="org.directwebremoting.webwork.AjaxResult" />
<convert converter="bean" match="your_action_package.*"/>
器定義(package級(jí)別或單獨(dú)action)。
public class Remote {
public String getData(int index)
{ ... }
}
<script type='text/javascript' src='[WEBAPP]/dwr/interface/Remote.js'></script>
……
<script type="text/javascript">
function handleGetData(str) { alert(str); } Remote.getData(42,
handleGetData);
</script>
另外一種語法時(shí)使用"調(diào)用元數(shù)據(jù)對(duì)象"來指定回調(diào)函數(shù)和其他的選項(xiàng)。上面的例子可以寫成這樣:
util.js包含了一些工具函數(shù)來幫助你用javascript數(shù)據(jù)(例如從服務(wù)器返回的數(shù)據(jù))來更新你的web頁面。 你可以在DWR以外使用它,因?yàn)樗灰蕾囉贒WR的其他部分。你可以下載整個(gè)DWR或者單獨(dú)下載. 4個(gè)基本的操作頁面的函數(shù):getValue[s]()和setValue[s]()可以操作大部分HTML元素除了table,list和image。getText()可以操作select list。 要修改table可以用addRows()和removeAllRows()。要修改列表(select列表和ul,ol列表)可以用addOptions()和removeAllOptions()。 還有一些其他功能不是DWRUtil的一部分。但它們也很有用,它們可以用來解決一些小問題,但是它們不是對(duì)于所有任都通用的。
7.1 $()
$() 函數(shù)(它是合法的Javascript名字) 是從Protoype偷來的主意。 大略上的講: $ = document.getElementById。 因?yàn)樵贏jax程序中,你會(huì)需要寫很多這樣的語句,所以使用 $() 會(huì)更簡潔。 通過指定的id來查找當(dāng)前HTML文檔中的元素,如果傳遞給它多個(gè)參數(shù),它會(huì)返回找到的元素的數(shù)組。所有非String類型的參數(shù)會(huì)被原封不動(dòng)的返回。這個(gè)函數(shù)的靈感來至于prototype庫,但是它可以在更多的瀏覽器上運(yùn)行。 可以看看DWRUtil.toDescriptiveString的演示。 從技術(shù)角度來講他在IE5.0中是不能使用的,因?yàn)樗褂昧薃rray.push,盡管如此通常它只是用來同engine.js一起工作。如果你不想要engine.js并且在IE5.0中使用,那么你最好為Array.push找個(gè)替代品。
7.2 addOptions and removeAllOptions
DWR的一個(gè)常遇到的任務(wù)就是根據(jù)選項(xiàng)填充選擇列表。下面的例子就是根據(jù)輸入填充列表。 下面將介紹 DWRUtil.addOptions() 的幾種是用方法。 如果你希望在你更新了select以后,它仍然保持運(yùn)來的選擇,你要像下面這樣做: var sel = DWRUtil.getValue(id); DWRUtil.removeAllOptions(id); DWRUtil.addOptions(id, ...); DWRUtil.setValue(id, sel);
55 / 92
如果你想加入一個(gè)初始的"Please select..." 選項(xiàng)那么你可以直接加入下面的語句: DWRUtil.addOptions(id, \["Please select ..."]);
DWRUtil.addOptions有5種模式
? 數(shù)組: DWRUtil.addOptions(selectid, array) 會(huì)創(chuàng)建一堆option,每個(gè)option的文字和值都是數(shù)組元素中的值。
? 對(duì)象數(shù)組 (指定text): DWRUtil.addOptions(selectid, data, prop) 用每個(gè)數(shù)組元素創(chuàng)造一個(gè)option,option的值和文字都是在prop中指定的對(duì)象的屬性。
? 對(duì)象數(shù)組 (指定text和value值): DWRUtil.addOptions(selectid, array, valueprop, textprop) 用每個(gè)數(shù)組元素創(chuàng)造一個(gè)option,option的值是對(duì)象的valueprop屬性,option的文字是對(duì)象的textprop屬性。
? 對(duì)象: DWRUtil.addOptions(selectid, map, reverse)用每個(gè)屬性創(chuàng)建一個(gè)option。對(duì)象屬性名用來作為option的值,對(duì)象屬性值用來作為屬性的文字,這聽上去有些不對(duì)。但是事實(shí)上卻是正確的方式。如果reverse參數(shù)被設(shè)置為true,那么對(duì)象屬性值用來作為選項(xiàng)的值。
? 對(duì)象的Map: DWRUtil.addOptions(selectid, map, valueprop, textprop) 用map中的每一個(gè)對(duì)象創(chuàng)建一個(gè)option。用對(duì)象的valueprop屬性做為option的value,用對(duì)象的textprop屬性做為option的文字。
? ol 或 ul 列表: DWRUtil.addOptions(ulid, array) 用數(shù)組中的元素創(chuàng)建一堆li元素,他們的innerHTML是數(shù)組元素中的值。這種模式可以用來創(chuàng)建ul和ol列表。
這是網(wǎng)上的例子
DWR通過這兩個(gè)函數(shù)來幫你操作table: DWRUtil.addRows() 和 DWRUtil.removeAllRows() 。這個(gè)函數(shù)的第一個(gè)參數(shù)都是table、tbody、thead、tfoot的id。一般來說最好使用tbody,因?yàn)檫@樣可以保持你的header和footer行不變,并且可以防止Internet Explorer的bug。
? DWRUtil.removeAllRows()
DWRUtil.removeAllRows(id);
描述: 通過id刪除table中所有行。 參數(shù): id: table元素的id(最好是tbody元素的id)
DWRUtil.addRows(id, array, cellfuncs, [options]);
描述: 向指定id的table元素添加行。它使用數(shù)組中的每一個(gè)元素在table中創(chuàng)建一行。然后用cellfuncs數(shù)組中的沒有函數(shù)創(chuàng)建一個(gè)列。單元格是依次用cellfunc根據(jù)沒有數(shù)組中的元素創(chuàng)建出來的。 DWR1.1開始,addRows()也可以用對(duì)象做為數(shù)據(jù)。如果你用一個(gè)對(duì)象代替一個(gè)數(shù)組來創(chuàng)建單元格,這個(gè)對(duì)象會(huì)被傳遞給cell函數(shù)。 參數(shù): id: table元素的id(最好是tbody元素的id) array: 數(shù)組(DWR1.1以后可以是對(duì)象),做為更新表格數(shù)據(jù)。 cellfuncs: 函數(shù)數(shù)組,從傳遞過來的行數(shù)據(jù)中提取單元格數(shù)據(jù)。 options: 一個(gè)包含選項(xiàng)的對(duì)象(見下面) 選項(xiàng)包括: rowCreator: 一個(gè)用來創(chuàng)建行的函數(shù)(例如,你希望個(gè)tr加個(gè)css). 默認(rèn)是返回一個(gè)document.createElement("tr") cellCreator: 一個(gè)用來創(chuàng)建單元格的函數(shù)(例如,用th代替td). 默認(rèn)返回一個(gè)document.createElement("td")
這是網(wǎng)上的例子
7.4 getText
getText(id)和getValue(id)很相似。出了它是為select列表設(shè)計(jì)的。你可能需要取得顯示的文字,而不是當(dāng)前選項(xiàng)的值。
這是網(wǎng)上的例子
7.5 getValue
DWRUtil.getValue(id)是 setValue()對(duì)應(yīng)的"讀版本"。它可以從HTML元素中取出其中的值,而你不用管這個(gè)元素是select列表還是一個(gè)div。 這個(gè)函數(shù)能操作大多數(shù)HTML元素包括select(去處當(dāng)前選項(xiàng)的值而不是文字)、input元素(包括textarea)、div和span。
這是網(wǎng)上的例子
getValues()和getValue()非常相似,除了輸入的是包含name/value對(duì)的javascript對(duì)象。name是HTML元素的ID,value會(huì)被更改為這些ID對(duì)象元素的內(nèi)容。這個(gè)函數(shù)不會(huì)返回對(duì)象,它只更改傳遞給它的值。 從DWR1.1開始getValues()可以傳入一個(gè)HTML元素(一個(gè)DOM對(duì)象或者id字符串),然后從它生成一個(gè)reply對(duì)象。
7.7 onReturn
當(dāng)按下return鍵時(shí),得到通知。 當(dāng)表單中有input元素,觸發(fā)return鍵會(huì)導(dǎo)致表單被提交。當(dāng)使用Ajax時(shí),這往往不是你想要的。而通常你需要的觸發(fā)一些Javscript。 不幸的是不同的瀏覽器處理這個(gè)事件的方式不一樣。所以DWRUtil.onReturn修復(fù)了這個(gè)差異。如果你需要一個(gè)同表單元素中按回車相同的特性,你可以用這樣代碼實(shí)現(xiàn): <input type="text" onkeypress="DWRUtil.onReturn(event,submitFunction)"/> <input type="button" onclick="submitFunction()"/>
你也可以使用onkeypress事件或者onkeydown事件,他們做同樣的事情。 一般來說DWR不是一個(gè)Javascript類庫,所以它應(yīng)該試圖滿足這個(gè)需求。不管怎樣,這是在使用Ajax過程中一個(gè)很有用函數(shù)。 這個(gè)函數(shù)的工作原理是onSubmit()事件只存在于<FORM ...>元素上
這是網(wǎng)上的例子
7.8 selectRange
選擇一個(gè)輸入框中的一定范圍的文字。 你可能為了實(shí)現(xiàn)類似"Google suggest"類型的功能而需要選擇輸入框中的一定范圍的文字,但是不同瀏覽器間選擇的模型不一樣。這DWRUtil函數(shù)可以幫你實(shí)現(xiàn)。 DWRUtil.selectRange(ele, start, end)
這是網(wǎng)上的例子
DWRUtil.setValue(id, value)根據(jù)第一個(gè)參數(shù)中指定的id找到相應(yīng)元素,并根據(jù)第二個(gè)參數(shù)改變其中的值。 這個(gè)函數(shù)能操作大多數(shù)HTML元素包括select(去處當(dāng)前選項(xiàng)的值而不是文字)、input元素(包括textarea)、div和span。
這是網(wǎng)上的例子
7.10 setValues
setValues()和setValue()非常相似,除了輸入的是包含name/value對(duì)的javascript對(duì)象。name是HTML元素的ID,value是你想要設(shè)置給相應(yīng)的元素的值。
這是網(wǎng)上的例子
7.11 toDescriptiveString
DWRUtil.toDescriptiveString()函數(shù)比默認(rèn)的toString()更好。第一個(gè)參數(shù)是要調(diào)試的對(duì)象,第二個(gè)參數(shù)是可選的,用來指定內(nèi)容深入的層次: 0: 單行調(diào)試 1: 多行調(diào)試,但不深入到子對(duì)象。 2: 多行調(diào)試,深入到第二層子對(duì)象 以此類推。一般調(diào)試到第二級(jí)是最佳的。 還有第三個(gè)參數(shù),定義初始縮進(jìn)。這個(gè)函數(shù)不應(yīng)該被用于調(diào)式程序之外,因?yàn)橐院罂赡軙?huì)有變化。
這是網(wǎng)上的例子
7.12 useLoadingMessage
這個(gè)方法將來可能被廢棄,因?yàn)檫@個(gè)實(shí)現(xiàn)實(shí)在太專斷了。為什么是紅色,為什么在右上角,等等。唯一的真正答案就是:抄襲GMail。這里的建議是以本頁面中的代碼為模板,根據(jù)你的需求自定義。 你必須在頁面加載以后調(diào)用這個(gè)方法(例如,不要在onload()事件觸發(fā)之前調(diào)用),因?yàn)樗獎(jiǎng)?chuàng)建一個(gè)隱藏的div來容納消息。
可能有些情況下你是不能容易的編輯header和body標(biāo)簽(如果你在使用CMS,這很正常),在這樣的情況下你可以這樣做: <script> function init() { DWRUtil.useLoadingMessage(); } if (window.addEventListener) { window.addEventListener("load", init, false); } else if (window.attachEvent) { window.attachEvent("onload", init); } else { window.onload = init; } </script>
下面這些是這個(gè)函數(shù)的代碼,它對(duì)于你要實(shí)現(xiàn)自己的加載消息很有用。這個(gè)函數(shù)的主要內(nèi)容是動(dòng)態(tài)創(chuàng)建一個(gè)div(id是disabledZone)來容納消息。重要的代碼是當(dāng)遠(yuǎn)程調(diào)用時(shí)使它顯示和隱藏: DWREngine.setPreHook(function() { $('disabledZone').style.visibility = 'visible'; }); DWREngine.setPostHook(function() { $('disabledZone').style.visibility = 'hidden'; }); This is fairly simple and makes it quite easy to implement your own "loading" message.
然后你就可以這樣使用:useLoadingImage("images/loader.gif");
h1 非util.js中的功能 這里有一些功能不適合加入到DWRUtil中。它們?cè)诮鉀Q一下特殊問題是很有用,但是他們還不夠通用以適用任何場(chǎng)合。
62 / 92
修補(bǔ)瀏覽器事件 如果你創(chuàng)建了一個(gè)DOM元素,然后用addAttribute在這個(gè)元素上創(chuàng)建了一個(gè)事件,那么他們不能被正常的觸發(fā)。你可以使用下面的腳本來遍歷一個(gè)DOM樹,并重新為他們綁定事件,這樣他們就能正常的觸發(fā)了。 把'click'改成你希望的事件。 DWREngine._fixExplorerEvents = function(obj) { for (var i = 0; i < obj.childNodes.length; i++) { var childObj = obj.childNodes [i]; if (childObj.nodeValue == null) { var onclickHandler = childObj.getAttribute('onclick'); if (onclickHandler != null) { childObj.removeAttribute('onclick'); // If using prototype: // Event.observe(childObj, 'click', new Function(onclickHandler)); // Otherwise (but watch out for memory leaks): if (element.attachEvent) { element.attachEvent("onclick", onclickHandler); } else { element.addEventListener("click", onclickHandler, useCapture); } } DWREngine._fixExplorerEvents(childObj); } }
我們很謹(jǐn)慎的對(duì)待DWR的安全問題,并且認(rèn)為有必要解釋一下避免錯(cuò)誤要做的事情。 首先DWR讓你明確哪些是被遠(yuǎn)程調(diào)用的,是如何被遠(yuǎn)程調(diào)用。原則就是DWR必須調(diào)用那些你明確允許的代碼。 dwr.xml要求你為每一個(gè)遠(yuǎn)程類定義一個(gè)'create'項(xiàng)。你還可以通過指定include和exclude元素來更精確的控制遠(yuǎn)程調(diào)用Bean中可以被調(diào)用的方法。 除此之外如果你希望允許DWR在轉(zhuǎn)換你的JavaBean到Javascript或者從Javascript轉(zhuǎn)換到JavaBean時(shí)有一定的許可限制,同樣可以精確控制哪些Bean的屬性可以被轉(zhuǎn)換。 一個(gè)很明顯但又必須指出的 – 不要在生產(chǎn)環(huán)境中打開test/debug模式控制臺(tái)。如何打開或關(guān)閉debug控制臺(tái)在配置web.xml部分可以找到詳細(xì)描述。
? 審查 - DWR帶來的最大好處
很值得對(duì)比一下DWR和Servlet、JSP或周圍的其他web框架。 如果你要審查基于DWR的功能,那是非常簡單的。看看dwr.xml你就能得到一個(gè)哪些方法被暴露到外面的描述了。你也可以俯視全局用DWR可以訪問哪些資源。 但是要在其他系統(tǒng)里做這件事可不是這么容易。如果是Servlet你需要檢查WEB-INF/web.xml文件,然后檢查寫在Servlet中的request.getParameter(...)。如果是Struts和其他Framework你需要檢查配置文件,然后順著流程檢查代碼,看請(qǐng)求信息出了什么問題。
? 訪問控制
DWR允許你通過兩種基于J2EE的機(jī)制來進(jìn)行訪問控制。首先你可以基于J2EE角色定義DWR的訪問。其次你可以在DWR里面定義訪問方法的角色。
? 其他方面
DWR不允許你定義任何內(nèi)部類的create和convert。這樣設(shè)計(jì)是為了不出現(xiàn)意外的攻擊來操作DWR的核心文件以提升訪問權(quán)限。
? 風(fēng)險(xiǎn)
有什么機(jī)會(huì)可以讓攻擊者窺視你的系統(tǒng)呢?使用DWR你攻擊者可以使服務(wù)器創(chuàng)建任何你在dwr.xml中指定的Java對(duì)象的實(shí)例。并且(如果你用BeanConverter)Java類的任何方法、以及方法任何參數(shù)都是可見的。這些類的任何一個(gè)屬性都有可能是攻擊者需要的。 如果你知道DWR是怎么工作的,這些都是很顯而易見的結(jié)論,但是往往粗心會(huì)造成問題。如果你創(chuàng)建了一個(gè)有appendStringToFile()方法的FileBean的類,而且用DWR把它暴露出去,那么你就給了攻擊者一個(gè)機(jī)會(huì)來填滿你的文件系統(tǒng)。
69 / 92
你必須時(shí)刻注意用了DWR以后,有沒有給攻擊者什么機(jī)會(huì)。 一般來說這樣的情景讓人感覺使用DWR是有風(fēng)險(xiǎn)的,但是這樣的問題在所有的傳統(tǒng)web架構(gòu)中都存在,只是在那些架構(gòu)中這些不明顯,所以就很難被修復(fù)。
? 保證更加安全
這已經(jīng)很安全了,那么你還能做什么來保證更加安全了?首先記住上面這些關(guān)于審查的內(nèi)容,當(dāng)web應(yīng)用的其他地方不安全時(shí),即使它看上去很安全,過多的關(guān)注DWR是很愚蠢的。如果DWR讓人感覺恐懼,那是因?yàn)樗膯栴}都在明處。所以第一步是多檢查幾遍傳統(tǒng)架構(gòu)的問題。 你可以通過把可遠(yuǎn)程訪問的類放到不同的包里,并且使用代理來防止DWR訪問機(jī)制出問題。如果你愿意還可以再次檢查基于角色的安全控制。這些內(nèi)容只是在檢查DWR已經(jīng)為你做的事情。 比多檢查幾次更好的方法是檢查DWR的源碼,保證它是在正確的工作。這些代碼已經(jīng)被很多人檢查過了,但多雙眼睛總是有好處的。
? 整合Acegi
DWR可以整合Acegi security framework。更多的信息見整合DWR和Acegi.