天天看點

DWR學習

< DOCTYPE html PUBLIC -WCDTD XHTML TransitionalEN httpwwwworgTRxhtmlDTDxhtml-transitionaldtd>

這段時間較閑,研究了一番dwr.發現dwr實作的AJAX有些地方确實很是先進.比如動态生成javascript代碼;隐藏的http協定;javascript于java代碼互動的是javascript對象(或字元串)等. 

以下是我臨時譯的一些東西.本來想全譯,發現dwr實在是簡單,就随便寫了.英文居差,現一把. 

1、DWR: Easy AJAX for JAVA

作為一個java open source library,DWR可以幫助開發人員完成應用AJAX技術的web程式。它可以讓浏覽器上的javascript方法調用運作在web伺服器上java方法。

DWR主要由兩部門組成。javascript與web伺服器通信并更新web頁;運作在web伺服器的Servlet處理請求并把響應發回浏覽器。

DWR采用新穎的方法實作了AJAX(本來也沒有确切的定義),在java代碼基礎上動态的生成javascript代碼。web開發者可以直接調用這些javascript代碼,然而真正的代碼是運作在web伺服器上的java code。出與安全考慮,開發者必須配置哪些java class暴露給DWR.(dwr.xml)

這種從(java到javascript)調用機制給使用者一種感覺,好象正常的RPC機制,或RMI or SOAP.但是它運作在web上,不需要任何浏覽器插件。

DWR不認為浏覽器和web伺服器之間協定重要,把系統界面放在首位。最大挑戰是java method call的同步特征與ajax異步特性之間的沖突。在異步模型裡,結果隻有在方法結束後才有效。DWR解決了這個問題,把回調函數當成參數傳給方法,處理完成後,自動調用回調方法。

這個圖表顯示了,通過javascript事件,DWR能改變select的内容,當然這些内容由java代碼傳回。 javascript函數Data.getOptions(populateList)由DWR動态生成,這個函數會調用java class Data類的方法。DWR處理如何遠端調用,包括轉換所有的參數和傳回的結果(javascript\java)。java方法執行完後,執行回調方法populateList。在整個過程中我們就想在用本地的方法一樣。

2、Getting Started

廢話少說,試試就ok了。 

web.xml

<?xml version="1.0" encoding="ISO-8859-1"?> 

<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app id="dwr"> 

<servlet> 

<servlet-name>dwr-invoker</servlet-name> 

<servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class> 

</servlet> 

<servlet-mapping> 

<url-pattern>/dwr/*</url-pattern> 

</servlet-mapping> 

</web-app>

dwr.xml 與web.xml同目錄 

<?xml version="1.0" encoding="UTF-8"?> 

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

index.html 

<html> 

<head> 

<title>DWR - Test Home</title> 

<script type='text/javascript' src='dwr/interface/JDate.js'></script> 

<script type='text/javascript' src='dwr/engine.js'></script> 

<script> 

function init(){ 

JDate.getYear(load); 

function load(data){ 

alert(data+1900+'年') 

</script> 

</head> 

<body onload="init()"> 

</body> 

</html>

dwr.jar 下載下傳放lib下

完了,什麼,夠了,就這些。通路ok! 

3、Examples 

http://www.aboutmyhealth.org/ 這不是Google Suggest嗎!ok. 

4、源碼淺析 

dwr的設計很象webwork2的設計,隐藏http協定,擴充性,相容性及強。

通過研究uk.ltd.getahead.dwr.DWRServlet這個servlet來研究下dwr到底是如何工作滴。

代碼

web.xml配置    

<servlet>   

    <servlet-name>dwr-invoker</servlet-name>   

    <servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class>   

  </servlet>   

  <servlet-mapping>   

    <url-pattern>/dwr/*</url-pattern>   

</servlet-mapping>   

這樣所有的/dwr/*所有請求都由這個servlet來處理,它到底處理了些什麼能。我們還以上面最簡單的例子來看。 

1、 web伺服器啟動,DWRServlet init()方法調用,init主要做了以下工作。 

設定日志級别、執行個體化DWR用到的單例類(這些類在jvm中隻有一個執行個體對象)、讀去配置檔案(包括dwr.jar包中的dwr.xml,WEB-INF/dwr.xml. config*.xml)。 

2、請求處理 

DWRServlet.doGet, doPost方法都調用processor.handle(req, resp)方法處理。Processor對象在init()方法中已經初始化了。 

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

        if(pathinfo != null && pathinfo.startsWith("/test/"))    

            doTest(req, resp);    

        if(pathinfo != null && pathinfo.equalsIgnoreCase("/engine.js"))    

            doFile(resp, "engine.js", "text/javascript");    

        if(pathinfo != null && pathinfo.equalsIgnoreCase("/util.js"))    

            doFile(resp, "util.js", "text/javascript");    

        if(pathinfo != null && pathinfo.equalsIgnoreCase("/deprecated.js"))    

            doFile(resp, "deprecated.js", "text/javascript");    

        if(pathinfo != null && pathinfo.startsWith("/interface/"))    

            doInterface(req, resp);    

        if(pathinfo != null && pathinfo.startsWith("/exec"))    

            doExec(req, resp);    

            log.warn("Page not found. In debug/test mode try viewing /[WEB-APP]/dwr/");    

            resp.sendError(404);    

        }    

    }   

哦。這些恍然大悟。dwr/*處理的請求也就這幾種。 

(1)dwr/index.html,dwr/test/這種隻能在debug模式下使用,調試用。 

dwr/engine.js,dwr/util.js,dwr/deprecated.js當這個請求到達,從dwr.jar包中讀取檔案流,響應回去。(重複請求有緩存) 

(2)當dwr/interface/這種請求到來,(例如我們在index.html中的 <script type='text/javascript' src='dwr/interface/JDate.js'></script>)DWR做一件偉大的事。把我們在WEB-INF/dwr.xml中的 

java.util.Date轉化為javascript函數。 

http://localhost:port/simpledwr/dwr/interface/JDate.js看看吧。 

細節也比較簡單,通過java反射,把方法都寫成javascript特定的方法。(我覺得這些轉換可以放到緩存裡,下次調用沒必要再生成一遍,不知道作者為什麼沒這樣做)。 

(3)dwr/exec 

javascript調用方法時發送這種請求,可能是XMLHttpRequest或IFrame發送。 

當然,javascript調用的方法簽名與java代碼一緻,包括參數,還有javascript的回調方法也傳到了伺服器端,在伺服器端很容易實作。回調方法的java的執行結果 傳回類似 <script>callMethod(結果)<script>的javascript字元串,在浏覽器執行。哈,一切就這麼簡單,巧妙。  

dwr的設計構思很是巧妙。 

第一、把java類轉化為javascript類由dwr自動完成,隻需簡單的配置。 

第二、應用起來極其簡單。開發者不要該伺服器代碼就可以內建。 

第三、容易測試。和webwork一樣,隐藏的http協定。 

第四、及強擴充性。例如與spring內建,隻需修改一點代碼。 

第五、性能。就我與jason,等簡單比較,dwr性能可能是最好的。 

第六、自動把java對象轉化為javascript對象,并且及易擴充。[/code]

simpledwr.rar  描述:  最簡單的一個例子. 

   檔案名:  simpledwr.rar  檔案大小:  137 KB  下載下傳過的:  檔案被下載下傳或檢視 1202 次howitworks.png  描述:     檔案大小:  31 KB  看過的:  檔案被下載下傳或檢視 1046 次

1、最小配置 

<servlet>  

  <servlet-name>dwr-invoker</servlet-name>  

  <servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class>  

</servlet>  

<servlet-mapping>  

  <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.我們可以通過url http://localhost:port/app/dwr ,你就可以看到你部署的每個DWR class。并且可以測試java代碼的每個方法是否運作正常。為了安全考慮,在正式環境下你一定把這個參數設為false. 

3、logging資訊配置。 

在無java.util.logging的jdk1.3下運作DWR,我們不希望強制使用者加一個logging包,而是用HttpServlet.log()方法來輸出日志。如果classpath中包括logging jar包,DWR自動切換用logging輸出日志。 

如果用HttpServlet.log()方法,以下配置是有效的。 

 <param-name>logLevel</param-name>  

 <param-value>DEBUG</param-value>  

有效的值是 FATAL, ERROR, WARN (the default), INFO and DEBUG 

我是喜歡用log4j輸出日志,那麼在log4j.properties下加,log4j.logger.uk.ltd.getahead.dwr = debug。這樣可以看DWR的調試日志。 

4、多dwr.xml檔案的配置 

可能有幾種情況,我們一一列舉。 一個servlet,多個dwr.xml配置檔案;多個servlet,每個servlet對應一個或多個dwr.xml. 

一個servlet,多個dwr.xml配置檔案; 

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

      <param-name>config-2</param-name>  

      <param-value>WEB-INF/dwr2.xml</param-value>  

在這種配置下,param-name的值必須以config開頭。param-name可以有>=0個。如果沒有param-name,那麼将會讀取WEB-INF/dwr.xml。如果有大于零個param-name,那麼WEB-INF/dwr.xml檔案将不會被讀取。 

多個servlet,每個servlet對應一個或多個dwr.xml 

   <servlet-name>dwr-invoker</servlet-name>  

<!--用classes/dwr.xml-->  

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

     <param-name>debug</param-name>  

     <param-value>true</param-value>  

   <url-pattern>/dwr/*</url-pattern>  

   <url-pattern>/dwr1/*</url-pattern>  

在這種情況下,我們可以根據J2EE security來控制權限,針對不同url,加不同的角色。 

5、dwr的幾個擴充點(Plug-ins) 

DWR對以下接口提供的預設的實作,使用者可以繼承DWR的預設實作類來達到我們想要的效果。但這至少需要我們讀了DWR源碼才能做這些工作(dwr源碼很是清晰,有興趣可以學習一下),以後可能補存這部分。 

uk.ltd.getahead.dwr.AccessControl       

uk.ltd.getahead.dwr.Configuration    

uk.ltd.getahead.dwr.ConverterManager    

uk.ltd.getahead.dwr.CreatorManager    

uk.ltd.getahead.dwr.Processor    

uk.ltd.getahead.dwr.ExecutionContext   

本文轉自 netcorner 部落格園部落格,原文連結:http://www.cnblogs.com/netcorner/archive/2007/02/15/2912425.html  ,如需轉載請自行聯系原作者