Ajax是時(shí)下比較流行的一種web界面設(shè)計(jì)新思路,其核心思想是從瀏覽器獲取XMLHttp對(duì)象與服務(wù)器端進(jìn)行交互. DWR(Direct Web Remoting)就是實(shí)現(xiàn)了這種Ajax技術(shù)的一種web框架. 最近做的項(xiàng)目中我也將它用上了,感覺很是方便,比如動(dòng)態(tài)生成javascript代碼,隱藏的http協(xié)議,java代碼和javascript交互的是javascript的對(duì)象(或字符串). 下面是我整理的文檔.
DWR主要由兩部門組成。javascript與web服務(wù)器通信并更新web頁;運(yùn)行在web服務(wù)器的Servlet處理請(qǐng)求并把響應(yīng)發(fā)回瀏覽器。
1 . 配置web.xml
<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 當(dāng)我們想看dwr自動(dòng)生成的測(cè)試頁時(shí),可在java代碼
servlet中加
<init-param>
<param-name>debug</param-name>
<param-value>true</param-value>
</init-param>
這個(gè)參數(shù)DWR默認(rèn)是false.如果選擇true.我們可以通過url http://localhost:port/app/dwr ,你就可以看到你部署的每個(gè)DWR class。并且可以測(cè)試java代碼的每個(gè)方法是否運(yùn)行正常。為了安全考慮,在正式環(huán)境下你一定把這個(gè)參數(shù)設(shè)為false.
3 log信息配置
我喜歡用log4j輸出日志,那么在log4j.properties下加,log4j.logger.uk.ltd.getahead.dwr = debug。這樣可以看DWR的調(diào)試日志。
4 配置dwr.xml (和web.xml同目錄)
<create creator="new" javascript="JDate">
<param name="class" value="java.util.Date"/>
</create>
這里的多數(shù)元素都是可選的 - 你真正必須知道的是指定一個(gè)creator和一個(gè)javascript名字。
creator屬性 是必須的 - 它用來指定使用那種創(chuàng)造器。
默認(rèn)情況下DWR1.1有8種創(chuàng)造器。它們是:
- new: 用Java的new關(guān)鍵字創(chuàng)造對(duì)象。
- none: 它不創(chuàng)建對(duì)象,看下面的原因。 (v1.1+)
- scripted: 通過BSF使用腳本語言創(chuàng)建對(duì)象,例如BeanShell或Groovy。
- spring: 通過Spring框架訪問Bean。
- jsf: 使用JSF的Bean。 (v1.1+)
- struts: 使用Struts的FormBean。 (v1.1+)
- pageflow: 訪問Beehive或Weblogic的PageFlow。 (v1.1+)
javascript屬性 用于指定瀏覽器中這個(gè)被創(chuàng)造出來的對(duì)象的名字。你不能使用Javascript的關(guān)鍵字。
scope屬性 非常類似servlet規(guī)范中的scope。 它允許你指定這個(gè)bean在什么生命范圍。選項(xiàng)有"application", "session", "request" 和"page"。這些值對(duì)于Servlet和JSP開發(fā)者來說應(yīng)該相當(dāng)熟悉了。
scope屬性是可選的。默認(rèn)是"page"。如果要使用"session"需要cookies。當(dāng)前的DWR不支持ULR重寫。
param元素 被用來指定創(chuàng)造器的其他參數(shù),每種構(gòu)造器各有不同。例如,"new"創(chuàng)造器需要知道要?jiǎng)?chuàng)建的對(duì)象類型是什么。每一個(gè)創(chuàng)造器的參數(shù)在各自的文檔中能找到。請(qǐng)查看上面的鏈接。
include和exclude元素 允許創(chuàng)造器來限制類中方法的訪問。一個(gè)創(chuàng)造器必須指定include列表或exclude列表之一。如果是include列表則暗示默認(rèn)的訪問策略是"拒絕";如果是exclude列表則暗示默認(rèn)的訪問策略是"允許"。
5 dwr.jar下載后放lib下
源碼淺析
dwr的設(shè)計(jì)很象webwork2的設(shè)計(jì),隱藏http協(xié)議,擴(kuò)展性,兼容性及強(qiáng)。
通過研究uk.ltd.getahead.dwr.DWRServlet這個(gè)servlet來研究下dwr到底是如何工作的。
<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>
這樣/dwr/*下的所有的請(qǐng)求都是由這個(gè)servlet來處理,到底生理了什么呢,我們還是以例子來說明吧.
1 web服務(wù)器啟動(dòng),DWRServlet init()方法調(diào)用,init主要做了以下工作。
設(shè)置日志級(jí)別、實(shí)例化DWR用到的單例類(這些類在jvm中只有一個(gè)實(shí)例對(duì)象)、讀去配置文件(包括dwr.jar包中的dwr.xml,WEB-INF/dwr.xml. config*.xml)。
2 請(qǐng)求處理
DWRServlet.doGet, doPost方法都調(diào)用processor.handle(req, resp)方法處理。Processor對(duì)象在init()方法中已經(jīng)初始化了。
代碼
public void handle(HttpServletRequest req, HttpServletResponse resp)
throws IOException
{
String pathinfo = req.getPathInfo();
if(pathinfo == null || pathinfo.length() == 0 || pathinfo.equals("/"))
{
resp.sendRedirect(req.getContextPath() + req.getServletPath() + '/' + "index.html");
} else
if(pathinfo != null && pathinfo.equalsIgnoreCase("/index.html"))
{
doIndex(req, resp);
} else
if(pathinfo != null && pathinfo.startsWith("/test/"))
{
doTest(req, resp);
} else
if(pathinfo != null && pathinfo.equalsIgnoreCase("/engine.js"))
{
doFile(resp, "engine.js", "text/javascript");
} else
if(pathinfo != null && pathinfo.equalsIgnoreCase("/util.js"))
{
doFile(resp, "util.js", "text/javascript");
} else
if(pathinfo != null && pathinfo.equalsIgnoreCase("/deprecated.js"))
{
doFile(resp, "deprecated.js", "text/javascript");
} else
if(pathinfo != null && pathinfo.startsWith("/interface/"))
{
doInterface(req, resp);
} else
if(pathinfo != null && pathinfo.startsWith("/exec"))
{
doExec(req, resp);
} else
{
log.warn("Page not found. In debug/test mode try viewing /[WEB-APP]/dwr/");
resp.sendError(404);
}
}
dwr/*處理的請(qǐng)求也就這幾種。
(1)dwr/index.html,dwr/test/這種只能在debug模式下使用,調(diào)試用。
dwr/engine.js,dwr/util.js,dwr/deprecated.js當(dāng)這個(gè)請(qǐng)求到達(dá),從dwr.jar包中讀取文件流,響應(yīng)回去。(重復(fù)請(qǐng)求有緩存)
(2)當(dāng)dwr/interface/這種請(qǐng)求到來,(例如我們?cè)趇ndex.html中的 <script type='text/javascript' src='dwr/interface/JDate.js'></script>)DWR做一件偉大的事。把我們?cè)赪EB-INF/dwr.xml中的
<create creator="new" javascript="JDate">
<param name="class" value="java.util.Date"/>
</create>
java.util.Date轉(zhuǎn)化為javascript函數(shù)。
http://localhost:port/simpledwr/dwr/interface/JDate.js看看吧。
細(xì)節(jié)也比較簡(jiǎn)單,通過java反射,把方法都寫成javascript特定的方法。(我覺得這些轉(zhuǎn)換可以放到緩存里,下次調(diào)用沒必要再生成一遍,不知道作者為什么沒這樣做)。
(3)dwr/exec
javascript調(diào)用方法時(shí)發(fā)送這種請(qǐng)求,可能是XMLHttpRequest或IFrame發(fā)送。
當(dāng)然,javascript調(diào)用的方法簽名與java代碼一致,包括參數(shù),還有javascript的回調(diào)方法也傳到了服務(wù)器端,在服務(wù)器端很容易實(shí)現(xiàn)。回調(diào)方法的java的執(zhí)行結(jié)果 返回類似 <script>callMethod(結(jié)果)<script>的javascript字符串,在瀏覽器執(zhí)行。哈,一切就這么簡(jiǎn)單,巧妙。
我這里還有DWR中文文檔. http://www.tkk7.com/Files/LiuTing/DWR中文文檔.rar