#

          文 字 變 化 效 果 JS事例講解

          源程序講解:
          ? ?

          var thissize=20

          聲明一個變量,定義字符串長度。
          var textfont="隸書" 聲明一個變量,定義字體。
          var textcolor= new Array()
          textcolor[0]="000000"
          textcolor[1]="000000"
          textcolor[2]="000000"
          textcolor[3]="111111"
          textcolor[4]="222222"
          textcolor[5]="333333"
          textcolor[6]="444444"
          textcolor[7]="555555"
          textcolor[8]="666666"
          textcolor[9]="777777"
          textcolor[10]="888888"
          textcolor[11]="999999"
          textcolor[12]="aaaaaa"
          textcolor[13]="bbbbbb"
          textcolor[14]="cccccc"
          textcolor[15]="dddddd"
          textcolor[16]="eeeeee"
          textcolor[17]="ffffff"
          textcolor[18]="ffffff"
          定義一個新數組,并列出其中的元素。
          var message = new Array()
          message[0]="洪恩在線 求知無限"
          message[1]="十二億人的網上大學"
          i_message=0
          定義新數組,并列出其中的元素。
          var i_strength=0
          var i_message=0
          聲明變量,并賦初值。
          var timer 聲明變量。
          function glowtext() { 定義函數。
          if(document.all)
          如果是IE瀏覽器,執行以下語句。
          { if (i_strength <=17)
          如果i_strength <=17,執行以下語句。
          { glowdiv.innerText=message[i_message]
          document.all.glowdiv.style.filter=
          "glow(color="+textcolor[i_strength]+", strength=4)"
          i_strength++
          輸出i_message的值,然后i_strength遞加,即亮度增加。
          timer=setTimeout("glowtext()",100) }
          每100毫秒,調用一次glowtext函數。
          else { clearTimeout(timer)
          setTimeout("deglowtext()",1500) }
          如果i_strength 大于17了,調用deglowtext函數,即亮度開始變暗。
          } } function deglowtext()
          { if(document.all)
          { if (i_strength >=0)
          定義deglowtext函數,并當瀏覽器是IE時,i_strength >=0時,執行以下語句。
          { glowdiv.innerText=message[i_message]
          document.all.glowdiv.style.filter=
          "glow(color="+textcolor[i_strength]+",
          strength=4)"
          i_strength--
          輸出i_message的值,然后i_strength遞減,即亮度減弱。
          timer=setTimeout("deglowtext()",100) }
          else { clearTimeout(timer)
          i_message++
          每100毫秒,調用一次glowtext函數,減到最暗,接著執行下一個字符串。
          if (i_message>=message.length)
          {i_message=0} i_strength=0 intermezzo() } } }
          如果數組message中的字符串都執行完了,一切恢復初始設置,并執行intermezzo函數。
          function intermezzo()
          定義一個函數intermezzo。
          { glowdiv.innerText=""
          setTimeout("glowtext()",1500) }
          1.5秒后,重新調用glowtext函數。

          posted @ 2007-07-08 22:23 金家寶 閱讀(394) | 評論 (0)編輯 收藏

          innerHTML、outerHTML、innerText、outerText的區別

          運行一下就知道區別了。

          posted @ 2007-07-08 22:15 金家寶 閱讀(301) | 評論 (0)編輯 收藏

          document 和 document.all

          如果與a,form對象,image對象,applet對象相對應的html標記中設定了name性質,它的值將被用作document對象的屬性名,用來引用相應的對象,其他的對象則不可以。
          另外,input等如果作為form的子元素,則直接用inputName或者document.inputName來引用此對象就是錯誤的,必須使用formName.inputName引用,否則就可以使用inputName來引用.
          另外應該注意到有很多平時用的元素都沒有name.
          如果想引用一個有id的元素,只能用Id或者document.getElementById,document.all.id來引用
          但是象這樣的元素,所以象<a href="......" name="linkname" id="linkid">......</a>這樣的
          可以用
          linkid.href;
          linkname.href;
          document.all.linkid.href;
          document.all.linkname.href;
          document.getElementById("linkid").href;
          document.getElementsByName("linkname")[0].href來引用

          all是一個集合,包含所有html對像的集合,寫一個程式,可以存取到所有的對像。像這樣:
          <script language="javascript">
          var obj="";
          for(i=0;i<document.all.length;i++)
          obj+=document.all[i].tagName+";";
          alert(obj);
          </script>
          注意要把程式放到</html>之后哦。

          posted @ 2007-07-08 22:05 金家寶 閱讀(260) | 評論 (0)編輯 收藏

          Java開源遲內幕

          對于全球軟件業人士來說,Java源碼要開放無疑是近期的焦點新聞。Sun公司的首席開源官菲利普澄清,表示Java開源化的工作不會在近期完成,還需要“十幾個月”的時間。許多業界人士認為,Java是人們最希望Sun開源的技術,而且這件事應該在幾年前就完成。Sun公司為何在Java開源上步履謹慎?其背后有何考慮? 日前美國《商業周刊》雜志撰文進行了解析:

            西蒙?菲利普打開了一個開源的“蠕蟲”之盒。6月的最后一個星期,他不得不澄清人們對于Sun公司一個眾人期待的宏大項目的質疑:Sun公司何時才會公開Java編程語言的源代碼?套用業內術語來說,Sun何時才會把Java“開源化”。

            這個問題已經長期困擾了Sun公司的高層,答案搖擺不定。此舉可以讓Java面向數以百萬計的開發人員,讓Java進一步融入IT業界,更不用說它將提高業界對Sun公司其他產品的興趣,并使一個正在提高業績的公司甩掉一個大包袱。

            作為Sun公司首席開源官的菲利普表示,Java的開源將在“幾個月”而不是“幾年內”完成。他后來表示,“幾個月”的意思是未來10到11個月,不過,與會者迫不及待地在其博客上宣布,Sun將在近期甚至九月份開放Java的源碼。菲利浦不得以再次面對媒體,強調不會那么早。此舉隨后又引發了Sun公司在Java開源上是否在自拖后腿的猜疑。

            來來回回的表態在Sun公司的開源道路上并不鮮見。正如菲利普等高層經常掛在嘴邊說的一樣,Sun公司的開源道路根植于1980年代,從Mozilla基金會的火狐瀏覽器到OpenOffice和Aparche WEB服務器,這些家喻戶曉的開源項目都有Sun的影子。

            這些顯然遠遠不夠,Sun公司現在幾乎是要把所有的產品都開放源碼。即使是作為Linux長期盟友的IBM也走不到那么遠。你參加任何一個有關開源的大會,總免不了會和Sun公司的頭面人物打照面,比如菲利普、首席信息官比爾?瓦斯,負責軟件的執行副總裁里奇?格林甚至是首席執行官喬納森?施瓦茨。

            盡管作出那么多努力,Sun公司卻很少獲得開源業界的褒獎。一些批評人士指出,Sun公司將Solaris操作系統開源的真實原因是因為它已經被Linux擊敗,此外,在其他已經開源的項目中,Sun公司也掌握了決定性的控制權,導致無法形成開發群體共同影響產品戰略的局面。

            事實上,Sun公司的高層也承認在開源業務上犯下錯誤。為了捍衛自己更加可靠但又價格昂貴的產品,施瓦茨和前任麥克尼利經常對Linux和低成本服務器產品“惡語相加”。這讓IBM和惠普等競爭對手有借口將Sun公司“刻畫”成為一個開源和Linux的敵人,這種形象甚至影響了大多數開源業界人士。

            在作為WEB和商業軟件開發語言的Java的開源問題上,業界的看法也不盡和Sun一致。前Sun公司高層、現任開源軟件公司ActiveGrid負責人的皮特?雅雷德表示:“其實Java是人們最希望Sun公司開放源碼的唯一產品。”另外一個Sun公司前任高層比爾?柯爾曼則表示:“我個人認為他們應該幾年前就做這件事。”

            現在看來,Sun公司終于決定作出妥協(開放Java源碼)。人們關心的另外一個問題是:Sun公司可以從中獲得什么利益?最簡單的答案:很多利益。可以考慮一下Java在Sun公司的地位。首先,這是一個公認的軟件開發語言標準,諸如甲骨文和BEA這樣的公司使用Java來開發應用軟件,也包括JBoss這樣的開源軟件項目。此外,Sun公司本身亦提供很多的Java應用軟件,并銷售相關的服務。雖然Java已經成為全球軟件行業發展的一個里程碑,不過,Sun公司并未從中獲得很多收入。
          對于柯爾曼這樣的業內人士來說,Sun開源Java還有背后的理由。據他介紹,在擔任BEA公司CEO的末期,Sun公司雇用了1200名工程師來維護Java,這個開支達到每年幾億美元,但他們帶來的銷售收入只占公司的百分之幾。隨著Sun公司逐步轉型,從一個銷售昂貴專有服務器的廠商逐漸適應一個更需要低價而靈活的產品的市場,諸如Java這樣的開支對于Sun來說已經成為一個包袱。

            不過,Sun開放Java源碼的道路走得很謹慎。菲利普強調,Java是一個標準和Sun公司的品牌,他們希望開源之后的Java能夠得到很好的維護。如果開源過早,則將會出現多個分裂市場的Java版本,削弱Java作為行業標準的地位。正如菲利普指出,Java成功的最大原因是任何一個公司都無法在它身上獲得不公平的優勢,在任何環境下,Java的這種特性必須得到保留。菲利普說:“問題是如何讓Java開源的同時保持著兩個價值,答案并不那么簡單。不負責任的人可能會有一個輕松的答案。”

            值得慶幸的是,這些爭論在Sun公司內部已經停止,他們表示在開源Java的問題上已經達成了一致。不管它是不是晚了五年,這仍然是一個正確的舉動。還有一個背景,其他逐漸流行的WEB開發語言,比如PHP和Ruby on Rails等正在蠶食Java的份額。雅雷德的公司ActiveGrid正在使這些開發語言足夠強勁,以便能夠在商用軟件開發中取代Java。如果菲利普認為Sun公司對全世界的Java開發人員有一種責任,那么,他們就必須保證其他語言不會削弱Java的地位。事實上,許多人認為在開源之后,在眾多開發人員的參與之下,Java會變得更加強大。

            對于Sun來說,Java開源還有其它好處,公司不會放棄有關Java的收入來源。隨著這個開發語言和IT業界的關系變得更加緊密,Sun公司也將更容易賣出自己兼容Java良好的WEB服務器和操作系統。這個舉動將會給軟件開發群體帶來新的活力,改善Sun公司的公眾形象,并同時證明Sun可以成為一個開源社會的“良民”。

            新官上任的CEO施瓦茨已經給人們留下深刻印象,他宣布了一系列“遲到”的大規模重組計劃。開放Java語言的源碼無疑將成為施瓦茨“后無來者”的“政績”。  



          更多資源:
          參與論壇討論: http://www.java-cn.com/forum/index.jsp
          更多技術文章: http://www.java-cn.com/technology/index.jsp
          更多JAVA博客: http://www.54bk.com
          JAVA中文站:? 我們要做中國最好的JAVA門戶網站,記住我們的域名: JAVA-CN.COM | JAVA-CN.NET | JAVA-CN.ORG
          本文網址: http://www.java-cn.com/technology/technology_detail.jsp?id=4216
          聲??? 明: 轉載此文章,須在顯著位置注明 JAVA中文站 的原文網址;
          ????????? 若是本站的轉載文章,請標明原文出處,并保留作者信息

          posted @ 2007-06-19 00:19 金家寶 閱讀(221) | 評論 (0)編輯 收藏

          .javascript.論壇

          http://bbs.javascript.com.cn

          posted @ 2007-05-27 01:02 金家寶 閱讀(1006) | 評論 (2)編輯 收藏

          php+mysql扎實個人基本功

          一. 10句話
          1.不要依賴register_global=ON的環境,從你剛懂得配置php運行環境甚至尚不明白register_global的ON/OFF會對自己有什么影響的那天起,就應該勇敢地把它設為OFF.
          2.寫程序前看看怎么用error_reporting.
          3.不懂就問本身沒錯,但你需要在那之前查查手冊。
          4.當然,你需要懂得使用手冊。手冊上找不到答案的時候,應該考慮下網絡上的搜索引擎。
          5.剛學會php+mysql之后,不要叫嚷著要寫論壇,要寫XXX。要明白,剛學會寫漢字并不表示你有能力寫詩。
          6.在學web編程的時候,你應該先去認識html這個朋友。
          7.有點能力后,試著回答新手的問題,不要看到自己懂的而別人不懂就沾沾自喜,扔下一名“簡單,那是基本的東西”就走更要不得。
          8.思考是一個好習慣,不動手去寫就等于空想,什么也沒有。
          9.寫好一段程序,如果覺得很滿意,一周后再看一遍,也許你會認為它應該有所改變
          10.有空多看看別人的程序,找出他人的不足或優點,自己掂量。

          二. 各取所需

          1.善于使用“引用”,它能直接影響到程序的效率。

          2.善于用三元運算子,可以讓程式較精簡有效率。
          比如:

          PHP代碼:

          if ($data[$i]['nickname'])
          {
          ????$nickname =??$data[$i]['nickname'];
          }
          else
          {
          ????$nickname =??$data[$i]['ip'];
          }


          可以寫成:

          PHP代碼:

          $nickname =??$data[$i]['nickname'] ? $data[$i]['nickname'] : $data[$i]['ip'];



          3.善于組織if...else...回圈
          比如:

          PHP代碼:

          $ext_name = strtolower(str_replace(".", "", strrchr($upfilename, ".")));
          if (!empty($type))
          {
          ????if (!strpos($type, $ext_name))
          ????{
          ????????echo "Please upload the file of $type form.";
          ????????exit();
          ????}
          }


          上面的代碼你應該寫成這樣:

          PHP代碼:

          $ext_name = strtolower(str_replace(".", "", strrchr($upfilename, ".")));
          if (!($type==='') && strpos($type, $ext_name)===false)
          {
          ????echo "Please upload the file of $type form.";
          ????exit();
          }



          4.盡量讓你的代碼清淅些
          如果寫成這樣,是比較讓人頭痛的:

          PHP代碼:

          $foo=$_post["foo"];
          ???$username=$_post["user"];
          $group=$_POST["group"];
          if ($group=="wheel"){
          $username=$username."wheel";
          }


          同樣的代碼,這樣就比較讓人看得舒服了:

          PHP代碼:

          $foo??????= $_post["foo"];
          $username = $_post["username"];
          $group????= $_POST["group"];
          if ($group=="wheel")
          {
          ????$username = $username."wheel";
          }


          當然,有一定基礎后,你應該要寫成這樣:

          PHP代碼:

          $foo??????= &$_POST['foo'];
          $username =??$_POST["group"]!='wheel' ? $_POST["username"] : $_POST["username"].'wheel';


          5.編寫規范的mysql 語句。
          字段和表名用"`"引起來,避免保留字的影響。
          如果看到下面這樣的一個sql query,會讓人比較頭痛:

          PHP代碼:

          $query="select `flash_comment`.`content` , `flash_comment`.`nickname` , `flash_comment`.`date` , `flash_comment`.`ip` , `product`.`p_name` , `sgflash`.`fid` from `flash_comment` left join `product` on ( `flash_comment`.`p_no` = `product`.`p_no` ) left join `sgflash` on ( `product`.`p_name` = `sgflash`.`f_name` ) where `flash_comment`.`p_no` != '' order by `flash_comment`.`date`";


          同樣的一個query,寫成這樣就令人看得明白得多了:

          PHP代碼:

          $query = "SELECT `flash_comment`.`content` , `flash_comment`.`nickname` , `flash_comment`.`date` , `flash_comment`.`ip` , `product`.`p_name` , `sgflash`.`fid`
          ??????????FROM `flash_comment`
          ??????????LEFT JOIN `product` ON ( `flash_comment`.`p_no` = `product`.`p_no` )
          ??????????LEFT JOIN `sgflash` ON ( `product`.`p_name` = `sgflash`.`f_name` )
          ??????????WHERE `flash_comment`.`p_no` != ''
          ??????????ORDER BY `flash_comment`.`date`";

          posted @ 2007-04-21 19:45 金家寶 閱讀(306) | 評論 (0)編輯 收藏

          深入剖析Java編程中的中文問題及建議最優解決方法

          1、中文問題的來源
          ????計算機最初的操作系統支持的編碼是單字節的字符編碼,于是,在計算機中一切處理程序最初都是以單字節編碼的英文為準進行處理。隨著計算機的發展,為了適應世界其它民族的語言(當然包括我們的漢字),人們提出了UNICODE編碼,它采用雙字節編碼,兼容英文字符和其它民族的雙字節字符編碼,所以,目前,大多數國際性的軟件內部均采用UNICODE編碼,在軟件運行時,它獲得本地支持系統(多數時間是操作系統)默認支持的編碼格式,然后再將軟件內部的UNICODE轉化為本地系統默認支持的格式顯示出來。Java的JDK和JVM即是如此,我這里說的JDK是指國際版的JDK,我們大多數程序員使用的是國際化的JDK版本,以下所有的JDK均指國際化的JDK版本。我們的漢字是雙字節編碼語言,為了能讓計算機處理中文,我們自己制定的gb2312、GBK、GBK2K等標準以適應計算機處理的需求。所以,大部分的操作系統為了適應我們處理中文的需求,均定制有中文操作系統,它們采用的是GBK,GB2312編碼格式以正確顯示我們的漢字。如:中文Win2K默認采用的是GBK編碼顯示,在中文WIN2k中保存文件時默認采用的保存文件的編碼格式也是GBK的,即,所有在中文WIN2K中保存的文件它的內部編碼默認均采用GBK編碼,注意:GBK是在GB2312基礎上擴充來的。
          ????由于Java語言內部采用UNICODE編碼,所以在JAVA程序運行時,就存在著一個從UNICODE編碼和對應的操作系統及瀏覽器支持的編碼格式轉換輸入、輸出的問題,這個轉換過程有著一系列的步驟,如果其中任何一步出錯,則顯示出來的漢字就會出是亂碼,這就是我們常見的JAVA中文問題。
          ????同時,Java是一個跨平臺的編程語言,也即我們編寫的程序不僅能在中文windows上運行,也能在中文Linux等系統上運行,同時也要求能在英文等系統上運行(我們經常看到有人把在中文win2k上編寫的JAVA程序,移植到英文Linux上運行)。這種移植操作也會帶來中文問題。
          ????還有,有人使用英文的操作系統和英文的IE等瀏覽器,來運行帶中文字符的程序和瀏覽中文網頁,它們本身就不支持中文,也會帶來中文問題。
          ????有,幾乎所有的瀏覽器默認在傳遞參數時都是以UTF-8編碼格式來傳遞,而不是按中文編碼傳遞,所以,傳遞中文參數時也會有問題,從而帶來亂碼現象。
          ????總之,以上幾個方面是JAVA中的中文問題的主要來源,我們把以上原因造成的程序不能正確運行而產生的問題稱作:JAVA中文問題。
          2、JAVA編碼轉換的詳細過程
          ????我們常見的JAVA程序包括以下類別:
          ???? *直接在console上運行的類(包括可視化界面的類)
          ???? *JSP代碼類(注:JSP是Servlets類的變型)
          ???? *Servelets類
          ???? *EJB類
          ???? *其它不可以直接運行的支持類
          ????這些類文件中,都有可能含有中文字符串,并且我們常用前三類JAVA程序和用戶直接交互,用于輸出和輸入字符,如:我們在JSP和Servlet中得到客戶端送來的字符,這些字符也包括中文字符。無論這些JAVA類的作用如何,這些JAVA程序的生命周期都是這樣的:
          ????*編程人員在一定的操作系統上選擇一個合適的編輯軟件來實現源程序代碼并以.java擴展名保存在操作系統中,例如我們在中文win2k中用記事本編輯一個java源程序;
          ???? *編程人員用JDK中的javac.exe來編譯這些源代碼,形成.class類(JSP文件是由容器調用JDK來編譯的);
          ???? *直接運行這些類或將這些類布署到WEB容器中去運行,并輸出結果。
          ????那么,在這些過程中,JDK和JVM是如何將這些文件如何編碼和解碼并運行的呢?
          ????這里,我們以中文win2k操作系統為例說明JAVA類是如何來編碼和被解碼的。
          ????第一步,我們在中文win2k中用編輯軟件如記事本編寫一個Java源程序文件(包括以上五類JAVA程序),程序文件在保存時默認采用了操作系統默認支持GBK編碼格式(操作系統默認支持的格式為file.encoding格式)形成了一個.java文件,也即,java程序在被編譯前,我們的JAVA源程序文件是采用操作系統默認支持的file.encoding編碼格式保存的,java源程序中含有中文信息字符和英文程序代碼;要查看系統的file.encoding參數,可以用以下代碼:
          public class ShowSystemDefaultEncoding {
          public static void main(String[] args) {
          String encoding = System.getProperty("file.encoding");
          System.out.println(encoding);
          }}
          ????第二步,我們用JDK的javac.exe文件編譯我們的Java源程序,由于JDK是國際版的,在編譯的時候,如果我們沒有用-encoding參數指定我們的JAVA源程序的編碼格式,則javac.exe首先獲得我們操作系統默認采用的編碼格式,也即在編譯java程序時,若我們不指定源程序文件的編碼格式,JDK首先獲得操作系統的file.encoding參數(它保存的就是操作系統默認的編碼格式,如WIN2k,它的值為GBK),然后JDK就把我們的java源程序從file.encoding編碼格式轉化為JAVA內部默認的UNICODE格式放入內存中。然后,javac把轉換后的unicode格式的文件進行編譯成.class類文件,此時.class文件是UNICODE編碼的,它暫放在內存中,緊接著,JDK將此以UNICODE編碼的編譯后的class文件保存到我們的操作系統中形成我們見到的.class文件。對我們來說,我們最終獲得的.class文件是內容以UNICODE編碼格式保存的類文件,它內部包含我們源程序中的中文字符串,只不過此時它己經由file.encoding格式轉化為UNICODE格式了。
          ????這一步中,對于JSP源程序文件是不同的,對于JSP,這個過程是這樣的:即WEB容器調用JSP編譯器,JSP編譯器先查看JSP文件中是否設置有文件編碼格式,如果JSP文件中沒有設置JSP文件的編碼格式,則JSP編譯器調用JDK先把JSP文件用JVM默認的字符編碼格式(也即WEB容器所在的操作系統的默認的file.encoding)轉化為臨時的Servlet類,然后再把它編譯成UNICODE格式的class類,并保存在臨時文件夾中。如:在中文win2k上,WEB容器就把JSP文件從GBK編碼格式轉化為UNICODE格式,然后編譯成臨時保存的Servlet類,以響應用戶的請求。
          ????第三步,運行第二步編譯出來的類,分為三種情況:
          ????A、 直接在console上運行的類
          ????B、 EJB類和不可以直接運行的支持類(如JavaBean類)
          ????C、 JSP代碼和Servlet類
          ????D、 JAVA程序和數據庫之間
          ????下面我們分這四種情況來看。
          ????A、直接在console上運行的類
          ????這種情況,運行該類首先需要JVM支持,即操作系統中必須安裝有JRE。運行過程是這樣的:首先java啟動JVM,此時JVM讀出操作系統中保存的class文件并把內容讀入內存中,此時內存中為UNICODE格式的class類,然后JVM運行它,如果此時此類需要接收用戶輸入,則類會默認用file.encoding編碼格式對用戶輸入的串進行編碼并轉化為unicode保存入內存(用戶可以設置輸入流的編碼格式)。程序運行后,產生的字符串(UNICODE編碼的)再回交給JVM,最后JRE把此字符串再轉化為file.encoding格式(用戶可以設置輸出流的編碼格式)傳遞給操作系統顯示接口并輸出到界面上。
          ????對于這種直接在console上運行的類,它的轉化過程可用圖1更加明確的表示出來:

          圖1
          ????以上每一步的轉化都需要正確的編碼格式轉化,才能最終不出現亂碼現象。
          ????B、EJB類和不可以直接運行的支持類(如JavaBean類)
          ????由于EJB類和不可以直接運行的支持類,它們一般不與用戶直接交互輸入和輸出,它們常常與其它的類進行交互輸入和輸出,所以它們在第二步被編譯后,就形成了內容是UNICODE編碼的類保存在操作系統中了,以后只要它與其它的類之間的交互在參數傳遞過程中沒有丟失,則它就會正確的運行。
          這種EJB類和不可以直接運行的支持類, 它的轉化過程可用圖2更加明確的表示出來:

          圖2
          ????C、JSP代碼和Servlet類
          ????經過第二步后,JSP文件也被轉化為Servlets類文件,只不過它不像標準的Servlets一校存在于classes目錄中,它存在于WEB容器的臨時目錄中,故這一步中我們也把它做為Servlets來看。
          ????對于Servlets,客戶端請求它時,WEB容器調用它的JVM來運行Servlet,首先,JVM把Servlet的class類從系統中讀出并裝入內存中,內存中是以UNICODE編碼的Servlet類的代碼,然后JVM在內存中運行該Servlet類,如果Servlet在運行的過程中,需要接受從客戶端傳來的字符如:表單輸入的值和URL中傳入的值,此時如果程序中沒有設定接受參數時采用的編碼格式,則WEB容器會默認采用ISO-8859-1編碼格式來接受傳入的值并在JVM中轉化為UNICODE格式的保存在WEB容器的內存中。Servlet運行后生成輸出,輸出的字符串是UNICODE格式的,緊接著,容器將Servlet運行產生的UNICODE格式的串(如html語法,用戶輸出的串等)直接發送到客戶端瀏覽器上并輸出給用戶,如果此時指定了發送時輸出的編碼格式,則按指定的編碼格式輸出到瀏覽器上,如果沒有指定,則默認按ISO-8859-1編碼發送到客戶的瀏覽器上。這種JSP代碼和Servlet類,它的轉化過程可用圖3更加明確地表示出來:

          圖3
          ????D、Java程序和數據庫之間
          ????對于幾乎所有數據庫的JDBC驅動程序,默認的在JAVA程序和數據庫之間傳遞數據都是以ISO-8859-1為默認編碼格式的,所以,我們的程序在向數據庫內存儲包含中文的數據時,JDBC首先是把程序內部的UNICODE編碼格式的數據轉化為ISO-8859-1的格式,然后傳遞到數據庫中,在數據庫保存數據時,它默認即以ISO-8859-1保存,所以,這是為什么我們常常在數據庫中讀出的中文數據是亂碼。
          ????對于JAVA程序和數據庫之間的數據傳遞,我們可以用圖4清晰地表示出來

          圖4
          ????3、分析常見的JAVA中文問題幾個必須清楚的原則
          ????首先,經過上面的詳細分析,我們可以清晰地看到,任何JAVA程序的生命期中,其編碼轉換的關鍵過程是在于:最初編譯成class文件的轉碼和最終向用戶輸出的轉碼過程。
          ????其次,我們必須了解JAVA在編譯時支持的、常用的編碼格式有以下幾種:
          ????*ISO-8859-1,8-bit, 同8859_1,ISO-8859-1,ISO_8859_1等編碼
          ????*Cp1252,美國英語編碼,同ANSI標準編碼
          ????*UTF-8,同unicode編碼
          ????*GB2312,同gb2312-80,gb2312-1980等編碼
          ????*GBK , 同MS936,它是gb2312的擴充
          ????及其它的編碼,如韓文、日文、繁體中文等。同時,我們要注意這些編碼間的兼容關體系如下:
          ????unicode和UTF-8編碼是一一對應的關系。GB2312可以認為是GBK的子集,即GBK編碼是在gb2312上擴展來的。同時,GBK編碼包含了20902個漢字,編碼范圍為:0x8140-0xfefe,所有的字符可以一一對應到UNICODE2.0中來。
          ????再次,對于放在操作系統中的.java源程序文件,在編譯時,我們可以指定它內容的編碼格式,具體來說用-encoding來指定。注意:如果源程序中含有中文字符,而你用-encoding指定為其它的編碼字符,顯然是要出錯的。用-encoding指定源文件的編碼方式為GBK或gb2312,無論我們在什么系統上編譯含有中文字符的JAVA源程序都不會有問題,它都會正確地將中文轉化為UNICODE存儲在class文件中。
          ????
          然后,我們必須清楚,幾乎所有的WEB容器在其內部默認的字符編碼格式都是以ISO-8859-1為默認值的,同時,幾乎所有的瀏覽器在傳遞參數時都是默認以UTF-8的方式來傳遞參數的。所以,雖然我們的Java源文件在出入口的地方指定了正確的編碼方式,但其在容器內部運行時還是以ISO-8859-1來處理的。

          ?




          ???4、中文問題的分類及其建議最優解決辦法
          ????了解以上JAVA處理文件的原理之后,我們就可以提出了一套建議最優的解決漢字問題的辦法。
          ????我們的目標是:我們在中文系統中編輯的含有中文字符串或進行中文處理的JAVA源程序經編譯后可以移值到任何其它的操作系統中正確運行,或拿到其它操作系統中編譯后能正確運行,能正確地傳遞中文和英文參數,能正確地和數據庫交流中英文字符串。
          ????我們的具體思路是:在JAVA程序轉碼的入口和出口及JAVA程序同用戶有輸入輸出轉換的地方限制編碼方法使之正確即可。
          ????具體解決辦法如下:
          ????1、 針對直接在console上運行的類
          ????對于這種情況,我們建議在程序編寫時,如果需要從用戶端接收用戶的可能含有中文的輸入或含有中文的輸出,程序中應該采用字符流來處理輸入和輸出,具體來說,應用以下面向字符型節點流類型:
          ????對文件:FileReader,FileWrieter
          ????????其字節型節點流類型為:FileInputStream,FileOutputStream
          ????對內存(數組):CharArrayReader,CharArrayWriter
          ????????其字節型節點流類型為:ByteArrayInputStream,ByteArrayOutputStream
          ????對內存(字符串):StringReader,StringWriter
          ????對管道:PipedReader,PipedWriter
          ????????其字節型節點流類型為:PipedInputStream,PipedOutputStream
          ????同時,應該用以下面向字符型處理流來處理輸入和輸出:
          ????BufferedWriter,BufferedReader
          ????????其字節型的處理流為:BufferedInputeStream,BufferedOutputStream
          ????InputStreamReader,OutputStreamWriter
          ????其字節型的處理流為:DataInputStream,DataOutputStream
          ????其中InputStreamReader和InputStreamWriter用于將字節流按照指定的字符編碼集轉換到字符流,如:
          ????InputStreamReader in = new InputStreamReader(System.in,"GB2312");
          ????OutputStreamWriter out = new OutputStreamWriter (System.out,"GB2312");
          ????例如:采用如下的示例JAVA編碼就達到了要求:
          //Read.java
          import java.io.*;
          public class Read {
          public static void main(String[] args) throws IOException {
          String str = "\n中文測試,這是內部硬編碼的串"+"\ntest english character";
          String strin= "";
          BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in,"gb2312")); //設置輸入接口按中文編碼
          BufferedWriter stdout = new BufferedWriter(new OutputStreamWriter(System.out,"gb2312")); //設置輸出接口按中文編碼
          stdout.write("請輸入:");
          stdout.flush();
          strin = stdin.readLine();
          stdout.write("這是從用戶輸入的串:"+strin);
          stdout.write(str);
          stdout.flush();
          }}
          ????同時,在編譯程序時,我們用以下方式來進行:
          ????javac -encoding gb2312 Read.java
          ????其運行結果如圖5所示:

          ????圖5
          ????2、 針對EJB類和不可以直接運行的支持類(如JavaBean類)
          ????由于這種類它們本身被其它的類調用,不直接與用戶交互,故對這種類來說,我們的建議的處理方式是內部程序中應該采用字符流來處理程序內部的中文字符串(具體如上面一節中一樣),同時,在編譯類時用-encoding gb2312參數指示源文件是中文格式編碼的即可。
          ????3、 針對Servlet類
          ????針對Servlet,我們建議用以下方法:
          ????在編譯Servlet類的源程序時,用-encoding指定編碼為GBK或GB2312,且在向用戶輸出時的編碼部分用response對象的setContentType("text/html;charset=GBK");或gb2312來設置輸出編碼格式,同樣在接收用戶輸入時,我們用request.setCharacterEncoding("GB2312");這樣無論我們的servlet類移植到什么操作系統中,只有客戶端的瀏覽器支持中文顯示,就可以正確顯示。如下是一個正確的示例:
          //HelloWorld.java
          package hello;
          import java.io.*;
          import javax.servlet.*;
          import javax.servlet.http.*;
          public class HelloWorld extends HttpServlet
          {
          public void init() throws ServletException { }
          public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
          {
          request.setCharacterEncoding("GB2312"); //設置輸入編碼格式
          response.setContentType("text/html;charset=GB2312"); //設置輸出編碼格式
          PrintWriter out = response.getWriter(); //建議使用PrintWriter輸出
          out.println("&lt hr &gt");
          out.println("Hello World! This is created by Servlet!測試中文!");
          out.println("&lt hr &gt");
          }
          public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
          {
          request.setCharacterEncoding("GB2312"); //設置輸入編碼格式
          response.setContentType("text/html;charset=GB2312"); //設置輸出編碼格式
          String name = request.getParameter("name");
          String id = request.getParameter("id");
          if(name==null) name="";
          if(id==null) id="";
          PrintWriter out = response.getWriter(); //建議使用PrintWriter輸出
          out.println("&lt hr &gt");
          out.println("你傳入的中文字串是:" + name);
          out.println("&lt hr &gt你輸入的id是:" + id);
          out.println("&lt hr &gt");
          }
          public void destroy() { }
          }
          ??? 請用javac -encoding gb2312 HelloWorld.java來編譯此程序。
          ??? 測試此Servlet的程序如下所示:
          &lt %@page contentType="text/html; charset=gb2312"% &gt
          &lt %request.setCharacterEncoding("GB2312");% &gt
          &lt html &gt&lt head &gt&lt title &gt&lt /title &gt
          &lt Script language="JavaScript" &gt
          function Submit() {
          //通過URL傳遞中文字符串值給Servlet
          document.base.action = "./HelloWorld?name=中文";
          document.base.method = "POST";
          document.base.submit();
          }
          &lt /Script &gt
          &lt /head &gt
          &lt body bgcolor="#FFFFFF" text="#000000" topmargin="5" &gt
          &lt form name="base" method = "POST" target="_self" &gt
          &lt input name="id" type="text" value="" size="30" &gt
          &lt a href = "JavaScript:Submit()" &gt傳給Servlet&lt /a &gt
          &lt /form &gt&lt /body &gt&lt /html &gt
          ??? 其運行結果如圖6所示:

          ????圖6
          ????4、 JAVA程序和數據庫之間
          ????為避免JAVA程序和數據庫之間數據傳遞出現亂碼現象,我們建議采用以下最優方法來處理:
          ????1、 對于JAVA程序的處理方法按我們指定的方法處理。
          ????2、 把數據庫默認支持的編碼格式改為GBK或GB2312的。
          ????如:在mysql中,我們可以在配置文件my.ini中加入以下語句實現:
          ????在[mysqld]區增加:
          ????default-character-set=gbk
          ????并增加:
          ????[client]
          ????default-character-set=gbk
          ????在SQL Server2K中,我們可以將數據庫默認的語言設置為Simplified Chinese來達到目的。
          ????5、 針對JSP代碼
          ????由于JSP是在運行時,由WEB容器進行動態編譯的,如果我們沒有指定JSP源文件的編碼格式,則JSP編譯器會獲得服務器操作系統的file.encoding值來對JSP文件編譯的,它在移植時最容易出問題,如在中文win2k中可以很好運行的jsp文件拿到英文linux中就不行,盡管客戶端都是一樣的,那是因為容器在編譯JSP文件時獲取的操作系統的編碼不同造成的(在中文wink中的file.encoding和在英文Linux中file.encoding是不同的,且英文Linux的file.encoding對中文不支持,所以編譯出來的JSP類就會有問題)。網絡上討論的大多數是此類問題,多是因為JSP文件移植平臺時不能正確顯示的問題,對于這類問題,我們了解了JAVA中程序編碼轉換的原理,解決起來就容易多了。我們建議的解決辦法如下:
          ????1、我們要保證JSP向客戶端輸出時是采用中文編碼方式輸出的,即無論如何我們首先在我們的JSP源代編中加入以下一行:

          ? &lt %@page contentType="text/html; charset=gb2312"% &gt
          ??? 2、為了讓JSP能正確獲得傳入的參數,我們在JSP源文件頭加入下面一句:
          ??? &lt %request.setCharacterEncoding("GB2312");% &gt
          ??? 3、為了讓JSP編譯器能正確地解碼我們的含有中文字符的JSP文件,我們需要在JSP源文件中指定我們的JSP源文件的編碼格式,具體來說,我們在JSP源文件頭上加入下面的一句即可:
          ??? &lt %@page pageEncoding="GB2312"% &gt或&lt %@page pageEncoding="GBK"% &gt
          ??? 這是JSP規范2.0新增加的指令。
          ??? 我們建議使用此方法來解JSP文件中的中文問題,下面的代碼是一個正確做法的JSP文件的測試程序:
          //testchinese.jsp
          &lt %@page pageEncoding="GB2312"% &gt
          &lt %@page contentType="text/html; charset=gb2312"% &gt
          &lt %request.setCharacterEncoding("GB2312");% &gt
          &lt %
          String action = request.getParameter("ACTION");
          String name = "";
          String str = "";
          if(action!=null && action.equals("SENT"))
          {
          name = request.getParameter("name");
          str = request.getParameter("str");
          }
          % &gt
          &lt html &gt
          &lt head &gt
          &lt title &gt&lt /title &gt
          &lt Script language="JavaScript" &gt
          function Submit()
          {
          document.base.action = "?ACTION=SENT&str=傳入的中文";
          document.base.method = "POST";
          document.base.submit();
          }
          &lt /Script &gt
          &lt /head &gt
          &lt body bgcolor="#FFFFFF" text="#000000" topmargin="5" &gt
          &lt form name="base" method = "POST" target="_self" &gt
          &lt input type="text" name="name" value="" size="30" &gt
          &lt a href = "JavaScript:Submit()" &gt提交&lt /a &gt
          &lt /form &gt
          &lt %
          if(action!=null && action.equals("SENT"))
          {
          out.println("&lt br &gt你輸入的字符為:"+name);
          out.println("&lt br &gt你通過URL傳入的字符為:"+str);
          }
          % &gt
          &lt /body &gt
          &lt /html &gt
          ??? 如圖7是此程序運行的結果示意圖:

          ????圖7
          ????5、總結
          ????在上面的詳細分析中,我們清晰地給出了JAVA在處理源程序過程中的詳細轉換過程,為我們正確解決JAVA編程中的中文問題提供了基礎。同時,我們給出了認為是最優的解決JAVA中文問題的辦法。
          ????6、參考資料
          ????1、段明輝.Java 編程技術中漢字問題的分析及解決.
          ????????http://www-900.ibm.com/developerWorks/cn/java/java_chinese/index.shtml
          ????2、 周競濤.關于Java中文問題的幾條分析原則
          ????????http://www-900.ibm.com/developerWorks/cn/java/l-javachinese/index.shtml
          ????7、作者介紹
          ????????作者:abnerchai,高級程序員,作者聯系方法:josserchai@yahoo.com

          ???

          posted @ 2007-04-10 15:55 金家寶 閱讀(594) | 評論 (0)編輯 收藏

          Java/J2EE中文問題終極解決之道

          ?

          Java中文問題一直困擾著很多初學者,如果了解了Java系統的中文問題原理,我們就可以對中文問題能夠采取根本的解決之道。

            最古老的解決方案是使用String的字節碼轉換,這種方案問題是不方便,我們需要破壞對象封裝性,進行字節碼轉換。

            還有一種方式是對J2EE容器進行編碼設置,如果J2EE應用系統脫離該容器,則會發生亂碼,而且指定容器配置不符合J2EE應用和容器分離的原則。

            在Java內部運算中,涉及到的所有字符串都會被轉化為UTF-8編碼來進行運算。那么,在被Java轉化之前,字符串是什么樣的字符集? Java總是根據操作系統的默認編碼字符集來決定字符串的初始編碼,而且Java系統的輸入和輸出的都是采取操作系統的默認編碼。

            因此,如果能統一Java系統的輸入、輸出和操作系統3者的編碼字符集合,將能夠使Java系統正確處理和顯示漢字。這是處理Java系統漢字的一個原則,但是在實際項目中,能夠正確抓住和控制住Java系統的輸入和輸出部分是比較難的。J2EE中,由于涉及到外部瀏覽器和數據庫等,所以中文問題亂碼顯得非常突出。

            J2EE應用程序是運行在J2EE容器中。在這個系統中,輸入途徑有很多種:一種是通過頁面表單打包成請求(request)發往服務器的;第二種是通過數據庫讀入;還有第3種輸入比較復雜,JSP在第一次運行時總是被編譯成Servlet,JSP中常常包含中文字符,那么編譯使用javac時,Java將根據默認的操作系統編碼作為初始編碼。除非特別指定,如在Jbuilder/eclipse中可以指定默認的字符集。

            輸出途徑也有幾種:第一種是JSP頁面的輸出。由于JSP頁面已經被編譯成Servlet,那么在輸出時,也將根據操作系統的默認編碼來選擇輸出編碼,除非指定輸出編碼方式;還有輸出途徑是數據庫,將字符串輸出到數據庫。

            由此看來,一個J2EE系統的輸入輸出是非常復雜,而且是動態變化的,而Java是跨平臺運行的,在實際編譯和運行中,都可能涉及到不同的操作系統,如果任由Java自由根據操作系統來決定輸入輸出的編碼字符集,這將不可控制地出現亂碼。

            正是由于Java的跨平臺特性,使得字符集問題必須由具體系統來統一解決,所以在一個Java應用系統中,解決中文亂碼的根本辦法是明確指定整個應用系統統一字符集。

            指定統一字符集時,到底是指定ISO8859_1 、GBK還是UTF-8呢?

            (1)如統一指定為ISO8859_1,因為目前大多數軟件都是西方人編制的,他們默認的字符集就是ISO8859_1,包括操作系統Linux和數據庫MySQL等。這樣,如果指定Jive統一編碼為ISO8859_1,那么就有下面3個環節必須把握:

            開發和編譯代碼時指定字符集為ISO8859_1。

            運行操作系統的默認編碼必須是ISO8859_1,如Linux。

            在JSP頭部聲明:<%@ page contentType="text/html;charset=ISO8859_1" %>。

            (2)如果統一指定為GBK中文字符集,上述3個環節同樣需要做到,不同的是只能運行在默認編碼為GBK的操作系統,如中文Windows。

            統一編碼為ISO8859_1和GBK雖然帶來編制代碼的方便,但是各自只能在相應的操作系統上運行。但是也破壞了Java跨平臺運行的優越性,只在一定范圍內行得通。例如,為了使得GBK編碼在linux上運行,設置Linux編碼為GBK。

            那么有沒有一種除了應用系統以外不需要進行任何附加設置的中文編碼根本解決方案呢?

            將Java/J2EE系統的統一編碼定義為UTF-8。UTF-8編碼是一種兼容所有語言的編碼方式,惟一比較麻煩的就是要找到應用系統的所有出入口,然后使用UTF-8去“結扎”它。

            一個J2EE應用系統需要做下列幾步工作:

          1. 開發和編譯代碼時指定字符集為UTF-8。JBuilder和Eclipse都可以在項目屬性中設置。
          2. 使用過濾器,如果所有請求都經過一個Servlet控制分配器,那么使用Servlet的filter執行語句,將所有來自瀏覽器的請求(request)轉換為UTF-8,因為瀏覽器發過來的請求包根據瀏覽器所在的操作系統編碼,可能是各種形式編碼。關鍵一句:
            request.setCharacterEncoding("UTF-8")。
            網上有此filter的源碼,Jdon框架源碼中com.jdon.util.SetCharacterEncodingFilter
            需要配置web.xml 激活該Filter。
          3. 在JSP頭部聲明:<%@ page contentType="text/html;charset= UTF-8" %>。
          4. 在Jsp的html代碼中,聲明UTF-8:
            <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
          5. 設定數據庫連接方式是UTF-8。例如連接MYSQL時配置URL如下:
            jdbc:mysql://localhost:3306/test?useUnicode=true&amp;characterEncoding=UTF-8
            一般數據庫都可以通過管理設置設定UTF-8
          6. 其他和外界交互時能夠設定編碼時就設定UTF-8,例如讀取文件,操作XML等。
                 

            以上討論了Java/J2EE的中文問題。如果整個應用系統是從開始進行開發,那么統一指定編碼為UTF-8就非常容易做到。如果是在英文源代碼基礎上二次開發,那么首先要將原來的源代碼轉換為統一編碼UTF-8,那么這種轉換工作會帶來一定的麻煩。  

            有了這個解決方案,無論使用什么框架Struts 或JSF或未來出現的Java技術,統一成UTF-8的方案都不會出現亂碼,筆者以前在Jsp/Servlet時就基于這個原則,后來使用Struts等框架,從未被亂碼困擾過,希望本方案公布出來供更多初學者分享,減少Java/J2EE的第一個攔路虎,也避免采取一些臨時解決方案。

          posted @ 2007-04-10 15:38 金家寶 閱讀(227) | 評論 (0)編輯 收藏

          表現層、持久層、業務層

          為了實現web層(struts)和持久層(Hibernate)之間的松散耦合,我們采用業務代表(Business Delegate)和DAO(Data Access Object)兩種模式。DAO模式為了減少業務邏輯和數據訪問邏輯之間的耦合,當一個持久曾框架被應用時,該模式將會減少業務對象和該框架之間的耦合,這樣我們可以不修改業務對象而選擇不同的持久層框架的實現。實際上在DAO模式中包含兩種結構模式:橋(Bridge)模式和適配器(Adaptor)模式。?

          對表現層,我們使用 Struts ;業務層使用 Spring ;對于持久層我們使用的是 Hibernate 。你盡可以取代這里的某個框架而使用你喜歡的框架已達到同樣的效果。下圖顯示了框架被整合起來時,從最高層次看到的視圖。

          clip_image001_0007.gif

          應用層

          ??? 許多設計良好的web應用,可以被按職責分為四層。這些層次是表現層、持久層、業務層、和領域模型層。每一個層次都有其獨特的職責,不能把各自的功能與其它層次相混合。每一個應用層都應該和其它層隔離開來,但允許使用接口在層間進行通信。我們開始來看看每個層,并討論一下它們各自都應該提供什么和不應該提供什么。

          表現層

          ??? 一個典型的web 應用的末端是表現層。許多Java 開發者都知道Struts提供了什么東西。然而,太多時候,耦合代碼比如業務邏輯被放進org.apache.struts.Action中。所以,我們先總結一下Struts之類的框架應該提供什么。下面就是Struts 的職責所在:

          1. 管理用戶的請求和響應
          2. 提供一個控制起來將調用委托到業務邏輯和其他上游處理
          3. 將來自于拋出例外的其他層的例外處理到Struts Action 中
          4. 組裝可以在視圖中表現的模型對象
          5. 執行UI 校驗

          下面是一些經常可以使用Struts進行編碼但是不應該和表現層關聯的事情:

          1. 直接和數據庫交互,比如JDBC 調用
          2. 與應用相關的業務邏輯和校驗
          3. 事務管理

          在表現層中引入這些類型的代碼將導致類型耦合和維護負擔。

          持久層

          ??? 一個典型Web應用的另一端是持久層。這也是應用中最容易很快失控的地方。開發者通常低估了自己構建自己的持久層框架的挑戰。一個定制的,內部開發的持久層不僅需要大量的開發時間,并且通常缺乏功能和難以管理。目前有許多解決這些問題的開源對象關系映射 (ORM) 框架。特別地,Hibernate 框架就允許Java中的對象-關系的持久性和查詢服務。Hibernate 對已經熟悉了SQL 和JDBC API的Java開發者來或具有中度的學習曲線。Hibernate 的持久對象基于POJO和Java群集(collections)。此外,使用Hibernate 不和你的IDE接口。下面列出了你需要在持久性框架中編寫的代碼類型:

          1. 查詢關系信息到對象中。Hibernate是通過稱為HQL的OO查詢語言,或者使用更有表現能力的規則API,來完成這個工作的。除了使用對象而不是表,使用字段而不是列的方式,HQL非常類似于 SQL。也有一些新的特定的HQL 語言特征需要學習;但是,它們是很容易理解和良好編寫的。HQL是一種用于查詢對象的自然語言,而對象,只需要很少的學習曲線吧。.
          2. 存儲、更新和刪除存儲在數據庫中的信息
          3. 高級的對象關系映射框架比如Hibernate支持大部分主流SQL數據庫,它們支持父/子關系,事務,繼承和多態。

          下面是應該在持久層避免的一些事情:

          1. 業務邏輯應該置于應用的更高層中。這里只允許數據訪問方法。
          2. 不應該使持久邏輯和表現邏輯耦合。避免表現組件如JSP或者基于servlet的類中的邏輯直接和數據訪問進行通信。通過將持久性邏輯隔離在其自己的層中,應用將具有更加靈活的修改性而不影響到其他層的代碼。例如, Hibernate可以使用其他持久框架和API代替,而不需要修改其它層中的代碼。

          業務層應該負責下面的問題:

          1. 處理應用的業務邏輯和業務校驗
          2. 管理事務
          3. 允許與其他層進行交互的接口
          4. 管理業務級對象之間的依賴性
          5. 加入了表現和持久層之間的靈活性,以便它們不需要彼此進行直接通信
          6. 從表現層暴露上下文給業務層以獲得業務服務
          7. 管理從業務層到表現層的實現

          posted @ 2007-04-08 03:17 金家寶 閱讀(24148) | 評論 (6)編輯 收藏

          關于POJO及DAO- -

          POJO = pure old Java object POJO有一些private的參數作為對象的屬性。然后針對每個參數定義了get和set方法作為訪問的接口。例如: public class User {

          private long id;

          private String name;

          public void setId(long id) {

          this.id = id;

          }

          public void setName(String name) {

          this.name=name;

          }

          public long getId() {

          return id;

          }

          public String getName() {

          return name;

          }

          }

          POJO對象有時也被稱為Data對象,大量應用于表現現實中的對象。

          取自"

          ?

          ??????????????????????????????????????

          POJO = pure old java object or plain ordinary java object or what ever.

          PO = persisent object 持久對象

          就是說在一些Object/Relation Mapping工具中,能夠做到維護數據庫表記錄的persisent object完全是一個符合Java Bean規范的純Java對象,沒有增加別的屬性和方法。全都是這樣子的:

          public class User { 
            private long id; 
            private String name;
            public void setId(long id) {
           this.id = id;
          }  
          public void setName(String name) {
          this.name=name;
          } 
           public long getId() {
           return id;
          }  
          public String getName() { 
          return name;
          }
          }  
          

          首先要區別持久對象和POJO。

          持久對象實際上必須對應數據庫中的entity,所以和POJO有所區別。比如說POJO是由new創建,由GC回收。但是持久對象是insert數據庫創建,由數據庫delete刪除的。基本上持久對象生命周期和數據庫密切相關。另外持久對象往往只能存在一個數據庫Connection之中,Connnection關閉以后,持久對象就不存在了,而POJO只要不被GC回收,總是存在的。

          由于存在諸多差別,因此持久對象PO(Persistent Object)在代碼上肯定和POJO不同,起碼PO相對于POJO會增加一些用來管理數據庫entity狀態的屬性和方法。而ORM追求的目標就是要PO在使用上盡量和POJO一致,對于程序員來說,他們可以把PO當做POJO來用,而感覺不到PO的存在。

          JDO的實現方法是這樣的:

          1、編寫POJO

          2、編譯POJO

          3、使用JDO的一個專門工具,叫做Enhancer,一般是一個命令行程序,手工運行,或者在ant腳本里面運行,對POJO的class文件處理一下,把POJO替換成同名的PO。

          4、在運行期運行的實際上是PO,而不是POJO。

          該方法有點類似于JSP,JSP也是在編譯期被轉換成Servlet來運行的,在運行期實際上運行的是Servlet,而不是JSP。

          Hibernate的實現方法比較先進:

          1、編寫POJO

          2、編譯POJO

          3、直接運行,在運行期,由Hibernate的CGLIB動態把POJO轉換為PO。

          由此可以看出Hibernate是在運行期把POJO的字節碼轉換為PO的,而JDO是在編譯期轉換的。一般認為JDO的方式效率會稍高,畢竟是編譯期轉換嘛。但是Hibernate的作者Gavin King說CGLIB的效率非常之高,運行期的PO的字節碼生成速度非常之快,效率損失幾乎可以忽略不計。

          實際上運行期生成PO的好處非常大,這樣對于程序員來說,是無法接觸到PO的,PO對他們來說完全透明。可以更加自由的以POJO的概念操縱PO。另外由于是運行期生成PO,所以可以支持增量編譯,增量調試。而JDO則無法做到這一點。實際上已經有很多人在抱怨JDO的編譯期Enhancer問題了,而據說JBossDO將采用運行期生成PO字節碼,而不采用編譯期生成PO字節碼。

          另外一個相關的問題是,不同的JDO產品的Enhancer生成的PO字節碼可能會有所不同,可能會影響在JDO產品之間的可移植性,這一點有點類似EJB的可移植性難題。


          由這個問題另外引出一個JDO的缺陷。

          由于JDO的PO狀態管理方式,所以當你在程序里面get/set的時候,實際上不是從PO的實例中取values,而是從JDO State Manager?中取出來,所以一旦PM關閉,PO就不能進行存取了。

          在JDO中,也可以通過一些辦法使得PO可以在PM外面使用,比如說定義PO是transient的,但是該PO在PM關閉后就沒有PO identity了。無法進行跨PM的狀態管理。

          而Hibernate是從PO實例中取values的,所以即使Session關閉,也一樣可以get/set,可以進行跨Session的狀態管理。

          在分多層的應用中,由于持久層和業務層和web層都是分開的,此時Hibernate的PO完全可以當做一個POJO來用,也就是當做一個VO,在各層間自由傳遞,而不用去管Session是開還是關。如果你把這個POJO序列化的話,甚至可以用在分布式環境中。(不適合lazy loading的情況)

          但是JDO的PO在PM關閉后就不能再用了,所以必須在PM關閉前把PO拷貝一份VO,把VO傳遞給業務層和web層使用。在非分布式環境中,也可以使用ThreadLocal模式確保PM始終是打開狀態,來避免每次必須進行PO到VO的拷貝操作。但是不管怎么說,這總是權宜之計,不如Hibernate的功能強。

          辨別一些名詞:
          1。VO:實際上很模糊,通常指ValueObject和ViewObject
          2. ViewObject,界面展現需要的對象,如Struts的FormBean
          3。Value Object,早期被作為ValueObject和Transfer Object的總稱。實際上Value Object的真正意義在于它的內容,而不是身份
          4。Transfer Object:數據傳輸對象,在應用程序不同層次之間傳書對象,在一個分布式應用程序中,通常可以提高整體的性能
          5。PO:也許就是Persistent Object,基本上就是Entity了
          在不同的體系結構和實現方式里面,這些對象有可能重復,也有可能不重疊。如果你要做一個對所有的體系都能夠方便移植的框架,那么每一種對象都需要嚴格區分。例如JDO的PO不能作為TO,應為它不能脫離PM,譬如你可以選擇用ViewObject(如Struts的FOrmBean)直接作為TO,但在tapestry和Webwork里面就不合適了。但在很多時候,能夠方便實用是最重要的,不要過度設計就是了。

          POJO是這樣一個對象,它是一個普通的Java對象,它不同于EJB這樣的帶有繁重的容器控制功能的對象,它也不是那種被Enhanced過的對象,例如JDO的靜態Enhance,也不是類似Hibernate那樣被動態的byte code generation過。

          也就是說POJO的概念是相對于其他那種被人動過手腳的class而言的,它是沒有被動過手腳的。

          其實,為什么要做DAO?無非是:
          1, 管理connection/transaction (hibernate的話就是session/transaction)
          2, 便于進行統計/log操作;
          3, 便于進行權限控制;

          DAO模式中,有兩類對象,一種是DAO,一種是valueObject。 在我們討論的這個情況中,value object是hibernate對應的POJO.

          那么,按照我的理解,DAO就是一個Transaction包裝器,其邏輯結構就是商業的具體事務。此處,數據庫的transaction和商業的事務是統一的。

          posted @ 2007-04-06 22:11 金家寶 閱讀(1947) | 評論 (0)編輯 收藏

          僅列出標題
          共7頁: 上一頁 1 2 3 4 5 6 7 下一頁 
          主站蜘蛛池模板: 高阳县| 乃东县| 安龙县| 铁力市| 前郭尔| 宁乡县| 阿图什市| 进贤县| 江华| 阿拉善左旗| 仙桃市| 凉山| 宽城| 宽甸| 青河县| 新沂市| 黄石市| 安化县| 龙岩市| 江都市| 阳泉市| 亚东县| 临颍县| 七台河市| 巴里| 甘德县| 梧州市| 绍兴县| 左贡县| 金门县| 镇远县| 准格尔旗| 黄冈市| 贺兰县| 屯留县| 徐汇区| 罗田县| 新安县| 桂东县| 马公市| 治多县|