程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> DWR的Converter實現原理簡單分析及應用

DWR的Converter實現原理簡單分析及應用

編輯:關於JAVA

我們在應用 DWR 調用遠程方法時涉及到 JS 與 JAVA 之間參數和返回值的數據轉換,例如:

JS 的 123 與 Java 的 int或 Integer、long 間的轉換

JS 的 "2009-06-23" 與 Java 的 java.util.Date 之間的轉換

JS 的 "[1,2,3]" 與 Java 的 int[] 間的轉換

JS 的 "{id:123, name: 'Unmi'}" 與 Java 的 Class Person{int id; String name} 間的轉換

或者更復雜的嵌套類型( "{id:123, name: 'Unmi', blogs: ['http://unmi.blogjava.net','http://blog.csdn.net/kypfos']}" ) 與 Java 類型間的轉換,等等。 那麼這一切是怎麼進行的呢?其實我們見識過很多組件的類型映射,如 Java 的 PropertyEditor、 Hibernate(UserType)、iBatis(TypeHandler) 的類型映射,Struts1/2 中 Form/Model 用的 Converter 等。

這裡我來稍稍分析 DWR 的 Converter 實現,以及說明如何定制自己的 Converter。本文所用 DWR 是 2.0.5 版。

1. DWR 內置的 Converter 及應用類型

名稱 應用類型 轉換器 null void,java.lang.Void NullConverter enum   EnumConverter primitive boolean,byte,short,int,
long,float,double,char,

java.lang.Boolean,java.lang.Byte,
java.lang.Short,

java.lang.Integer,java.lang.Long,
java.lang.Float,

java.lang.Double,java.lang.Character

PrimitiveConverter bignumber java.math.BigInteger,java.math.BigDecimal BigNumberConverter string java.lang.String StringConverter array [Z,[B,[S,[I,[J,[F,[D,[C,[L* ArrayConverter map java.util.Map MapConverter collection java.util.Collection CollectionConverter date java.util.Date,java.sql.Date,
java.sql.Time,

java.sql.Timestamp,
java.util.Calendar

DateConverter dom org.w3c.dom.Node,org.w3c.dom.Element,
org.w3c.dom.Document DOMConverter dom4j org.dom4j.Document,org.dom4j.Element,
org.dom4j.Node DOM4JConverter jdom org.jdom.Document,org.jdom.Element JDOMConverter xom nu.xom.Document,nu.xom.Element,
nu.xom.Node XOMConverter servlet javax.servlet.ServletConfig,
javax.servlet.ServletContext,

javax.servlet.http.HttpServletRequest,

javax.servlet.http.HttpServletResponse,

javax.servlet.http.HttpSession

ServletConverter bean   BeanConverter object   ObjectConverter hibernate2   H2BeanConverter hibernate3   H3BeanConverter url java.net.URL URLConverter exception   ExceptionConverter miniException java.lang.Throwable MinimalistExceptionConverter

它們是應用啟動的時候,通過 org.directwebremoting.servlet.DwrServlet 初始化 dwr- 2.0.5.jar!/org/directwebremoting/dwr.xml 文件加載進來的。例如:

<converter id="date" class="org.directwebremoting.convert.DateConverter"/> 注冊了 date 轉換器

<convert converter="date" match="java.util.Date"/> 應用注冊的 date 轉換器應用到 java.util.Date 類型

看到上面,你也許會驚訝一下,我們平時可能也就用下 bean 轉換器,其他用內置就行。然而 DWR 確 為我們考慮的很周到的,包括 hibernate 相關的,URL、Servlet、Dom 等相關類型的轉換器。

2. DWR 如何確定用哪個 Converter?

DWR 是根據方法參數來確定入口參數的 Converter、根據返回值類型確定傳向 JS 的出口參數的 Converter。總之是以 Java 方法原型為基准來決定每一參數或返回值各自用哪個 Converter 來轉換數據 。

在 BaseCallMarshaller.marshallInbound(HttpServletRequest request, HttpServletResponse response) 方法中,使用

Class paramType = method.getParameterTypes()[j] 來獲得參數的類型,然後從已加載的 Converter Map 中找到 Converter 名稱,進而確定 Converter 類名。

而確定返回值類型就不是直接用反射的 method.getReturnType()。而是以反射方式調用方法後,根據 具體返回值的類型來確定的。見:

Replay DefaultRemoter.execute(Call) 方法中的

Object reply = chain.doFilter(object, method, call.getParameters()); 再進入到

Object ExecuteAjaxFilter.doFilter(Object obj, Method method, Object[] params Ajax FilterChain){

return method.invoke(obj, params);

}

就是根據上面的返回值,然後在

DefaultConverterManager.convertOutbound(Object, OutboundContext) 方法中的

Converter converter = getConverter(object);  //根據返回值 object  確定該用的 Converter 。

3. DWR Converter 的調用

多留意下 DWR 自帶的 Converter,可以看到所有的 Converter 直接或簡接的 extends BaseV20Converter implements Converter,其實 BaseV20Converter(DWR 1.x 中對應為 BaseV10Converter) 本身就實現了 Converter。在 BaseV20Converter 抽象類中默認實現了 Converter 的方法

public void setConverterManager(ConverterManager config)  {  }

具體的 Converter 只要專心去實現接口 Converter 中的另兩個方法:

Object convertInbound(Class paramType, InboundVariable data, InboundContext inctx) throws MarshallException;

OutboundVariable convertOutbound(Object data, OutboundContext outctx) throws MarshallException;

運行時,它們相應的被 ConvertManager(默認為 DefaultConvertManager) 的

Object convertInbound(Class paramType, InboundVariable iv, InboundContext inctx, TypeHintContext incc) throws MarshallException

OutboundVariable convertOutbound(Object object, OutboundContext outctx) throws MarshallException

來調用。

DWR 對每個參數或返回值至少會應用一次 Converter,但對於復雜的類型會遞歸的調用 Converter, 比如,要完成

JS "{id:123, name: 'Unmi', blogs: ['http://unmi.blogjava.net','http://blog.csdn.net/kypfos']}"  到 Java 的 Person{int id, String name, String[] blogs;} 的轉換,就會使用到 bean->primitive->array 三個 Converter 。

4. 定制自己的 Converter

基本上 DWR  內置的 Converter 就夠用的,但也有可能需要定定自己的 Converter。從 DWR 的 Converter 實現來看,一般會用兩種方式:

1) extends BaseV20Converter implements Converter,實現 Converter 的 converterInbound() 和 converterOutbound() 方法

2) extends BasicObjectConverter implements Converter,或繼承 BeanConverter,實現 BasicObjectConverter 的 getPropertyMapFromObject(),getPropertyMapFromObject() 和 createTypeHintContext() 方法。

前一種方式,請參照 org.directwebremoting.convert.DateConverter 的源碼實現:

convertInbound() 由 JS 的字符串轉換成要求的 Date、Time、Timestamp 或 Calender 對像。

convertOubound() 把 Java 的類型轉換成 JS 的 new Date() 類型,注意返回值的寫法:

return new SimpleOutboundVariable("new Date(" + millis + ")", outctx, true);

第二種繼承 BasicObjectConverter 或是 BeanConverter 的做法,可參考 BeanConverter  的源碼 實現。表現在 JSON 和 Java 對象間的轉換,要是引入解析 JSON 的 JAR 包或許能有不少幫助。

定制 Converter 的內容講的很少,主要是真有這方面的需要的時候請參考 DWR  的相關源碼,實際 中理解各個接口方法參數的意義,及返回值的要求。對待開源組件還是要保持閱讀源碼的好習慣。

好啦,自己的 Converter 寫好,需要注冊,需要應用。我們還是參考 DWR 的做法,寫在自己的 dwr.xml 中。例如定制了 com.unmi.dwr.converter.SpecialConverter,要對 com.unmi.model.SpecialObject 進行出入類型的轉換,就這麼寫:

<converter id="special" class="com.unmi.dwr.converter.SpecialConverter"/> 注冊了  special 轉換器

<convert converter="special" match="com.unmi.model.SpecialObject"/> 應用注冊的 special 轉換器應用到 com.unmi.model.SpecialObject  類型

5. 小結

用 DWR 其實也有段時日了,未曾系統的學,總是遇一問題、掃除一個,不免也會去找找相關更系統 的資料。然而著下此篇的動機是上周六在書城翻了下 《 DWR 實戰》,它實際講 DWR 本身的較少。最後 我第一個想了解了是 DWR 能完成 JS 與 Java 間什麼類型的轉換,第一手的資料網上也沒搜索到,於是 進到源碼中去,親身歷練,也更加深了印象。

讀者也許和我一樣目的,只想看看內置的轉換器有哪些,能轉換哪些類型,那就只需看最為搶眼的那 張表格吧。需要定制 Converter 應該很少,就像我們很少定制 Struts 的 Converter、Hibernate 的 UserType 和 iBatis 的 TypeHandler 一樣。因此也就對定制 DWR 的 Converter 所用篇幅不多。

對待開源,自己總有個習慣就是必須有相關的源代碼伴隨在它身邊。開源組件的使用一般不難,碰到 問題,既然源碼都掌握了,我想總能從源碼中找出原因來。尚且,對這樣的知名組件越發深入,就更能嚼 出許多味多。

參考:DWR 2.0.5 的源代碼,對 DWR 項目進行單步調試

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved