張文江,何政偉,李旭龍
(1.成都理工大學地質災害防治與地質環境保護國家重點實驗室,四川成都610059;2.成都理工大學地球物理學院,四川成都610059)
數據采集實現屏幕顯示元素數據到數據對象屬性的轉換,而數據顯示則實現數據對象屬性到屏幕顯示元素數據的轉換,二者統稱界面元素與數據對象之間的數據交換。界面元素與數據對象之間的數據交換是各類系統的普遍功能,當前有多種技術模式實現這些功能,比如“拷貝—粘貼—修改”模式、基于框架的模式、基于委托與事件方法的技術等。對于數據項少、界面簡單的系統,可以采用“拷貝—粘貼—修改”的編程模式;典型的框架,如Struts、Spring,都提供了表現層 (界面)和業務層 (數據對象)之間的自動數據交換功能,并被廣泛用于Web系統的開發[1-3];也有采用基于委托與事件方法的數據交換模式系統[4],但這類系統比較少。上述這些方法都具有比較大的局限性:在人機交互界面復雜、屏幕顯示的數據項很多的情況下,“拷貝—粘貼—修改”模式產生的代碼冗長、相似度高,造成程序調試疲勞,隱含錯誤難于發現,調試、維護工作量大;而struts、spring是基于web系統的,不支持winform,另外,對單選、多選等復雜數據項,struts、spring的支持較弱;基于委托與事件的方法太過復雜。
基于反射技術實現數據交換的公共函數,各個窗體界面通過對公共函數的調用,完成winfrom窗體或web頁面的顯示界面元素與數據對象之間的數據交換。這種方法能夠極大減少復雜界面在數據顯示、數據修改方面的程序代碼,減少程序調試工作量,提高工作效率,提高系統的可靠性。
反射是本文提出的數據交換技術的基礎,下面先從反射的概念開始。
反射就是程序在運行時刻能夠查詢類型的信息,包括類型狀態 (屬性)、類型行為 (方法)、事件、構造函數等信息。它本質上是分析程序集中的元數據表的過程,發現程序集的類型和類型成員的信息[4]。它是一種晚綁定機制,程序員在寫代碼的時候還不知道或不能確定的一些信息,由代碼在運行的時候確定。當前軟件開發的兩大體系,Java和.Net都具有強大的Reflection機制,并且得到了廣泛的應用[5-10]。
下面以一個簡單的例子,說明反射的基本思想。設系統中有一個StudentClass類,其定義如圖1所示。

圖1 學生類
對象obj是程序運行過程中自動生成的,其類型在編譯的時候未知,所以程序代碼不知道obj的屬性、方法,也就不能直接訪問obj的屬性和方法。但是程序在運行時通過反射可以獲得obj的類型、屬性、方法等信息,通過屬性和方法的名稱實現對obj的管理。如果obj的類型為Student-Class,就可以通過 StudentClass類的屬性名稱“No”、“Name”讀寫obj的No屬性值,通過“GetAge”方法訪問obj的GetAge函數,獲得學生的年齡信息。
由于本文實現的系統是基于C#的B/S系統,因此,本文提供的算法將以基于C#語言的Asp.Net為例,實現Web頁面可視控件與C#數據對象之間的數據交換。數據庫中的數據與可視控件之間的數據交換問題,可用類似的方式實現,或者通過建立數據庫記錄與C#數據對象之間的映射關系,實現數據庫記錄與C#數據對象、C#數據對象與可視控件之間的雙層數據交換。
ASP.Net頁面對象,不管是標準的HTML對象,還是Asp.net封裝對象,只要加上Runat=Server,C#代碼就能訪問該控件的屬性,在系統運行的過程中動態獲取頁面控件類型、對象嵌套關系等信息。實際上,C#能夠全面操控整個ASP.Net文檔:遍歷整個DOM文檔,并對DOM文檔的任意對象進行控制。
另一方面,對于C#數據對象,采用反射技術,按封裝的原則,通過屬性的getter、setter方法,實現屬性字段值的讀、寫操作。
由此可見,ASP.Net頁面特點和C#反射技術,為頁面元素與數據對象屬性之間的數據交換提供了可能。關鍵是如何在頁面元素與數據對象之間建立起通信的橋梁。
本文使用“名稱關聯法”建立頁面控件與數據對象屬性之間的關聯,使Web頁面可視控件的ID與數據對象屬性名稱相同 (或者其它類似的規則),從而建立起它們之間的對應關系。程序在遍歷Web頁面可視控件的時候,根據可視控件的ID,找到數據對象的屬性名稱,再通過C#提供的反射機制,查詢數據對象該屬性的相關信息,讀取、或設置該屬性的值,從而實現可視控件顯示值與數據對象屬性值之間的相互數據交換。
圖2是這種基于名稱對應關系的簡化圖示說明,其中界面元素ID=Property1對應類ObjectClass的屬性Property1,界面元素ID=Property2對應類ObjectClass的屬性Property2,界面元素 ID=Property3對應類ObjectClass的屬性Property3。

圖2 基于名稱對應的顯示元素與數據對象關系
在闡述原理后,下面首先詳細分析各種顯示控件的處理方法,然后給出實現算法。
(1)簡單控件
簡單控件是指直接顯示數據屬性值的控件,這類控件使用最廣,如TextBox、HtmlInputText、Label等,這種顯示控件與數據對象之間的數據交換簡單、直接。
顯示控件命名規則:ID名稱就是數據對象的屬性名稱。
如果屬性數據類型為字符串型,可以通過設置Max-Length屬性來限制顯示長度。如果未設置MaxLength,或MaxLength設置為0,表示長度不受限制。
如果屬性數據類型為小數,可以通過設置精度屬性Precision來設置小數位數。
顯示對象事例:
<asp:TextBox ID="V1"runat="server"Max-Length="30" ></asp:TextBox>
<asp:TextBox ID="V2"runat="server"Precision="5.2"></asp:TextBox>
<asp:TextBox ID="V3"runat="server" ></asp:TextBox>
其中顯示對象ID名稱對應數據對象屬性名稱。
(2)單選控件
單選控件也是常用的顯示控件,在屏幕上表現為一組單選按鈕,對應一個數據對象屬性。與簡單控件不一樣的是,簡單控件與數據對象屬性是1對1的關系,而單選一般是多對1的關系:多個單選框對應于一個數據對象屬性。
為了簡化編程代碼,本方案用一個DIV容器包含這一組單選按鈕,由DIV容器代表這一組單選框。
該DIV命名規則:DIV的ID名稱設置為數據對象屬性名稱,同時,為了標識該DIV包含的是單選按鈕,該DIV增加一個固定屬性:groupClass="radiogroup"。
C#遍歷Web頁面時,一旦發現屬性groupClass=radiogroup,就用DIV的ID作為數據對象屬性名稱,然后通過反射查找數據對象相應屬性的值val,再遍歷DIV的radio子對象集,如果找到某radio的值與val相同,設置該單選按鈕的checked狀態為true。
顯示對象事例:
<div id="hazardType"runat="server"group-Class="radioGroup" >
<asp:RadioButton ID="sel1"Text="滑坡" runat="server"/>
<asp:RadioButton ID="sel2"Text="崩塌"runat="server"/>
<asp:RadioButton ID="sel3"Text="泥石流"runat="server"/>
</div>
要點:
1)Div對應數據對象屬性,單選按鈕作為div的子對象;
2)div的id名稱與數據對象的屬性名稱1:1對應;
3)groupClass="radioGroup"是固定屬性;
4)單選按鈕的ID命名沒有限制
(3)多選控件
與單選類似,一組多選按鈕對應一個數據對象屬性,因此,在進行Web頁面設計時,也要用一個DIV容器把多個多選按鈕組織在一起,并且該DIV的ID名稱為數據對象屬性的名稱,該DIV也要增加一個固定變屬性:groupClass="checkgroup"。
C#遍歷Web頁面時,一旦發現屬性groupClass=checkgroup,就用DIV的ID來查找數據對象的相應屬性值val,再遍歷DIV的checkbotton子對象,如果該按鈕的值在val中,則設置該按鈕的Checked屬性為true,否則為false。
顯示對象事例:
<div id="scope"runat="server"groupClass="checkGroup" >
<asp:CheckBox ID="居民點" runat="server"/>
<asp:CheckBox ID="工廠"runat="server"/>
<asp:CheckBox ID="農田"runat="server"/>
<asp:CheckBox ID="水利工程"runat="server"/>
</div>
要點:
1)Div對應數據對象屬性,多選按鈕作為div的子對象;
2)div的id名稱一定要與數據對象的屬性名稱對應;
3)groupClass="checkGroup"是固定屬性;
4)單選按鈕的ID命名沒有限制
(4)下拉列表
下拉列表是一種填充了數據的列表,填充的數據類型是一種“代碼—名稱”數據結構,其特點是下拉列表顯示名稱,數據對象保存代碼。
如果數據對象中保存的值就是顯示名稱,可以認為是“代碼—名稱”的一種特殊情況:即代碼與名稱相同。
下拉列表可以在設計時通過人工輸入建立,也可以在程序運行時由代碼動態生成。
下拉列表與數據對象屬性具有1:1關系,下拉列表的ID名稱與對應的數據對象屬性名稱相同。顯示對象事例:
<asp:DropDownList ID="scale"runat="server" >
<asp:ListItem Value="01" >特大型</asp:ListItem>
<asp:ListItem Value="02" >大型</asp:ListItem>
<asp:ListItem Value="03" >中小型</asp:ListItem>
</asp:DropDownList>
要點:
(5)下拉列表的id名稱與數據對象的屬性名稱對應;
在本系統中,單選結果以單選按鈕顯示的名稱以字符串的形式保存在數據對象中,多選結果以多選按鈕顯示的名稱保存,并以逗號 (,)分割多選值。為了算法敘述的方便,引入“規范子串”的概念,嚴格定義多選值的存儲格式。
定義1:字符串 s是字符串 f的規范子串的充要條件是:
f以 s結尾或者 s加逗號 (,)形成的新串是 f的子串。
入口參數:
WebControl:頁面控件,子控件命名規則符合上面提出的要求。
Obj:C#數據對象。
Function WebPageToEntity(WebControl,Obj)
{
通過反射,獲得數據對象Obj的類型T;
獲得WebControl的ID,并賦到變量pname;
如果ID不符號上面定義的規則
{
對WebControl的子對象,遞歸調用本函數
Return
}
取WebControl表示的數據類型,dataType;
如果dataType不是預定義的處理的數據類型,返回;
Case dataType是簡單數據:
取WebControl的值,并賦到val;
通過反射,把val保存到Obj的pname屬性;
Case dataType是單選數據:
查詢WebControl的單選子控件,取選中的單選按鈕的值,并賦到val;
通過反射,把val保存到Obj的pname屬性;
Case dataType是多選數據:
查詢WebControl的多選子控件,組合所有選中的多選按鈕的值,并賦到val;
通過反射,把val保存到Obj的pname屬性;
Case dataType是下拉列表數據:
取下拉列表選擇的值,并賦到val;
通過反射,把val保存到Obj的pname屬性;
Case其它:
不予處理;
}
入口參數:
WebControl:頁面控件,子控件命名規則符合上面提出的要求。
Obj:C#數據對象。
Function EntityToWebPage(WebControl,Obj)
{
通過反射,獲得數據對象Obj的類型T;
獲得WebControl的ID,并賦到變量pname;
如果ID不符號上面定義的規則
{
對WebControl的子對象,遞歸調用本函數
Return
}
取WebControl表示的數據類型,dataType;
如果dataType不是預定義的處理的數據類型,返回;
Case dataType是簡單數據:
通過反射,取Obj的pname屬性值,并賦值到val
把val設置WebControl控件;Case dataType是單選數據:
通過反射,取Obj的pname屬性值,并賦值到val
查詢WebControl的單選子控件,如果某子控件的text屬性值與val相等,設置該子控件的Checked狀態為true;
Case dataType是多選數據:
通過反射,取Obj的pname屬性值,并賦值到val
對WebControl的所有多選子控件執行:
如果該子控件的text屬性是val的一個“規范子串”,
選中該子控件,否則不選中該子控件
Case dataType是下拉列表數據:
通過反射,取Obj的pname屬性值,并賦值到val
把val賦值到下拉列表選擇的值
Case其它:
不予處理;
}
貴州省地質災害數據管理系統管理的災害包括:滑坡、泥石流、崩塌、地裂縫、地面沉降、地面塌陷等6種,每種地質災害的屬性數量多達200個以上,并且屬性類型復雜,單選屬性、多選屬性、下拉屬性多,造成顯示界面非常復雜。在項目原型階段,采用“拷貝—粘貼—修改”方式,僅實現滑坡災害數據對象到web頁面的顯示就寫了1850多行代碼,并且因為屬性太多,代碼相似度又極高,導致代碼中存在很多難于發現的低級錯誤,調試極其困難,最后只能徹底放棄這種方法。
通過討論,采用了基于反射的數據交換方法,只用了兩個公共函數,就實現了所有地質災害屬性的顯示與修改工作。函數WebPageToEntity實現web頁面顯示內容賦值到數據對象,代碼只有160行;函數EntityToWebPage實現數據對象到頁面的顯示,代碼只有158行。總共300多行代碼,實現了所有Web頁面與數據對象之間的數據交換功能。并且這300多行代碼結構嚴謹、邏輯性強,調試、排錯也很容易,系統的正確性得到了極大提高。
數據對象通過代碼生成工具,直接從數據庫生成。設計人員只把頁面設計好,并按規范命名各種控件,最后通過調用WebPageToEntity和EntityToWebPage函數,實現了數據對象與顯示元素之間的數據自動交換。數據對象的持久化通過iBatis實現。這樣,CRUD部分的代碼量和測試量就變得很小了,極大減少了系統開發的工作量。
文章提出了基于反射的顯示控件與數據對象之間的數據交換原理和方法,并對文本框、單選框、多選框、下拉列表等常用顯示控件的處理作了深入、詳細的討論,設計了實現數據交換的算法。
該方法具有普遍意義,適用于各種系統的CRUD操作,尤其對數據項多、界面復雜的系統能夠極大地減少編程代碼,減少程序錯誤,提高系統的正確性和穩定性。
該方法不局限于C#,可適用于支持反射機制的任何語言 (如Java),也不局限于Web系統,還可適用于winform桌面系統。
[1]GUO Guangjun,XU Zhangfa,YANG Siqing.Digitized archives management system for teaching evaluation based on struts-hibemate architecture[J].Computer Engineering and Design,2010,31(10):2358-2362(in Chinese).[郭廣軍,徐章法,羊四清.基于Struts-Hibernate構架的數字化教學評估檔案管理系統[J].計算機工程與設計,2010,31(10):2358-2362.]
[2]ZHOU Xiangbing,YANGXiaoping,YANGXingjiang.Application and implementation of general framework based on web layering structure[J].Computer Engineering and Design,2008,29(7):772-775(in Chinese).[任曉鵬,趙文兵,張春平.基于框架的Web系統開發研究[J].計算機工程與設計,2010,29(7):772-775.]
[3]ZUO Wenming,WANG Qingqiang,WU Yingliang.Use land management information system based on struts[J].Computer Engineering and Design,2008,29(19):4972-4974(in Chinese).[左文明,王慶強,吳應良,等.基于Struts的用地管理信息系統[J],計算機工程與設計,2008,29(19):4972-4974.]
[4]CHEN Nannan.Research and implementation of data transmission with C# [J].Computer and Information,2011(11):67-68(in Chinese).[陳南南.基于C#的對象間數據傳遞方法分析及實現 [J].電腦與信息,2011(11):67-68.]
[5]ZHANG Zhi,DU Jingkang,ZUO Fengjun,Research on.Net reflection based GISplugin technology[J].Science of Surveying and Mapping,2011,36(4):151-152(in Chinese).[章志,都金康,卓鳳軍.基于.NET反射機制的GIS插件技術研究[J].測試科學,2011,36(4):151-152.]
[6]ZHOU Xiangbing,YANG Xiaoping,YANGXingjiang.Application and implementation of general framework based on web layering structure[J].Computer Engineering and Design,2008,29(7):1859-1862(in Chinese).[周相兵,楊小平,楊興江.基于Web分層結構的通用框架實現及應用[J].計算機工程與設計,2008,29(7):1859-1862.]
[7]QIN Pengtao,WANG Suwen.Application of simple factory pattern in data access layer [J].Computer Engineering and Design,2009,30(7):1799-1801(in Chinese).[秦澎濤,蘇文.簡單工廠模式在數據訪問層中的應用[J].計算機工程與設計,2009,30(7):1799-1801.]
[8]LOU Buye.Design of auto-marking software framework for Java programming questions [J].Computer Engineering and Design,2010,31(24):5343-5346(in Chinese).[婁不夜.Java編程題自動判分軟件框架的設計 [J].計算機工程與設計,2010,31(24):5343-5346.]
[9]XIAO Lu,LONG Pengfei.The research of AOP based on Java dynamic proxy[J].Micro Computer Information,2011,27(2):211-213(in Chinese).[肖露,龍鵬飛.基于JAVA的動態代理實現的AOP的研究 [J].微計算機信息,2011,27(2):211-213.]
[10]DUAN Chao,QIAN Gang,SUN Yijie.Practice and application of the technology of reflection ln database operation[J].Process Automation Instrumentation,2010,31(6):17-20(in Chinese).[段超,錢剛,孫怡劫.反射技術在數據庫操作方面的實踐與應用[J].自動化儀表,2010,31(6):17-20.]
[11]Nagel C.Professional C#[D].6nd ed.Beijing:Tsinghua University Press,2008:10-205(in Chinese).[(美)內格爾(Nagel.C).C#高級編程[D].6版.北京:清華大學出版社,2008:10-205.]
[12]WANG Jianguo,WANG Jianyin,Struts+Spring+Hibernate frameworks and application development[D].Beijing:Tsinghua University Press,2011:1-638(in Chinese).[王建國,王建英.Struts+Spring+Hibernate框架及應用開發 [D].北京,清華大學出版社,2011:1-638.]