2008年7月30日

          struts-config.xml中 action 的attribute屬性與name屬性

          1、在一般情況下,actionForm是被存儲(chǔ)在一定的scope中(request或session,通過action的scope屬性來(lái)配置),當(dāng)我們?cè)谂渲脮r(shí),指定name而不指定attribute,那么指定的name值就作為actionForm存儲(chǔ)在scope中的key值,我們可以在action中通過httpServletRequest.getAttribute("指定的name屬性值")來(lái)獲得這個(gè)actionForm;     當(dāng)我們既配置了name又配置了attribute,那么actionForm存儲(chǔ)在scope中的key值就采用attribute屬性指定的值了,這時(shí)要通過httpServletRequest.getAttribute("指定的attribute屬性值")來(lái)獲得actionForm,此時(shí)通過httpServletRequest.getAttribute("指定的name屬性值")是不能獲得actionForm的。  
             
              所以,是否配置attribute屬性就決定了actionForm存儲(chǔ)在scope中的key值是采用name,還是采用attribute

           2、 在《Programming Jakarta Struts》這本書中的第四章“Configuring the Struts Application”中這樣一段說(shuō)明來(lái)分別闡述這兩
          個(gè)屬性:(102頁(yè))
          ++++++++
          atribute:
          ++++++++
          The name of the request or session scope attribute under which the form bean for this action can be accessed.
          A value is only allowed here if there is a form bean specified in the name attribute. This attribute is
          optional and has no default value.

          ++++++++
          name:
          ++++++++
          The name of the form bean, if any, that is associated with this action. This value must be the name attribute
          from one of the form-bean elements defined earlier. This attribute is optional and has no default value.

          最初看這些真的還是不好區(qū)分這兩者。不過在仔細(xì)看過struts的源代碼以后,豁然開朗。。。

          下面主要對(duì)attribute進(jìn)行解釋,應(yīng)為沒有人會(huì)對(duì)name屬性不了解的(呵呵。。。)


          解釋:在struts實(shí)例化actionform的時(shí)候,有兩種情況:如果已經(jīng)存在,那么從內(nèi)存中取回;如果第一次實(shí)例化,那么創(chuàng)建,并放入內(nèi)存。
          這樣就有一個(gè)問題了,struts是根據(jù)什么來(lái)取回并創(chuàng)建actionform的呢,答案就是attribute的值。讓我們進(jìn)入struts的源代碼:

          /**
          *創(chuàng)建或者取回formbean方法
          *該方法在:org.apache.struts.util.RequestUtils中
          */
          public static Actionform createActionform(
          HttpServletRequest request,
          ActionMapping mapping,
          ModuleConfig moduleConfig,
          ActionServlet servlet) {
          。。。。
          。。。
          // Is there a form bean associated with this mapping?
          //得到action mapping中attribute的值
          String attribute = mapping.getAttribute();
          。。。。
          。。。。
          Actionform instance = null;
          HttpSession session = null;
          //yes!!就在這里了,把創(chuàng)建以后的actionform放在request或者session里,看到放入的名字了么,就是mapping.getAttribute();
          if ("request".equals(mapping.getScope())) {
          instance = (Actionform) request.getAttribute(attribute);
          } else {
          session = request.getSession();
          instance = (Actionform) session.getAttribute(attribute);
          }
          。。。
          。。。


          }


          下面又有一個(gè)問題浮出水面:如果我沒有在action mapping中指定attribute呢,那struts 是如何解決的?
          答案很簡(jiǎn)單,如果單從結(jié)果上看,此時(shí)struts使用的name的值,為什么呢,看struts源代碼:

          /**
          * The request-scope or session-scope attribute name under which our
          * form bean is accessed, if it is different from the form bean's
          * specified <code>name</code>.
          *該代碼在:org.apache.struts.config.ActionConfig中
          */
          protected String attribute = null;

          public String getAttribute() {
          //yes!!!!就在這里,看到了吧,如果你沒有設(shè)定attribute,那么struts 會(huì)把name的值拿過來(lái)用。呵呵。。。
          if (this.attribute == null) {
          return (this.name);
          } else {
          return (this.attribute);
          }
          }

          public void setAttribute(String attribute) {
          if (configured) {
          throw new IllegalStateException("Configuration is frozen");
          }
          this.attribute = attribute;
          }

          posted @ 2008-09-20 13:37 chenkai 閱讀(701) | 評(píng)論 (1)編輯 收藏

          Request的getParameter和getAttribute方法的區(qū)別

          當(dāng)兩個(gè)Web組件之間為轉(zhuǎn)發(fā)關(guān)系時(shí),轉(zhuǎn)發(fā)源會(huì)將要共享 request范圍內(nèi)的數(shù)據(jù)先用setAttribute將數(shù)據(jù)放入到HttpServletRequest對(duì)象中,然后轉(zhuǎn)發(fā)目標(biāo)通過 getAttribute方法來(lái)取得要共享的數(shù)據(jù)。而MVC中用的就是Web組件之間的轉(zhuǎn)發(fā)啊!真是笨,怎么當(dāng)時(shí)沒有想到呢?

                下面整理一下getParameter和getAttribute的區(qū)別和各自的使用范圍。

                (1)HttpServletRequest類有setAttribute()方法,而沒有setParameter()方法

                (2)當(dāng)兩個(gè)Web組件之間為鏈接關(guān)系時(shí),被鏈接的組件通過getParameter()方法來(lái)獲得請(qǐng)求參數(shù),例如假定welcome.jsp和authenticate.jsp之間為鏈接關(guān)系,welcome.jsp中有以下代碼:

                <a  href="authenticate.jsp?username=wolf">authenticate.jsp  </a>

                或者:

                <form  name="form1"  method="post"  action="authenticate.jsp">
                    請(qǐng)輸入用戶姓名:<input  type="text"  name="username">
                    <input  type="submit"  name="Submit"  value="提交">
                </form>

                 在authenticate.jsp中通過request.getParameter("username")方法來(lái)獲得請(qǐng)求參數(shù)username:

                 <%  String  username=request.getParameter("username");  %>

                 (3)當(dāng)兩個(gè)Web組件之間為轉(zhuǎn)發(fā)關(guān)系時(shí),轉(zhuǎn)發(fā)目標(biāo)組件通過getAttribute()方法來(lái)和轉(zhuǎn)發(fā)源組件共享request范圍內(nèi)的數(shù)據(jù)。

                  假定  authenticate.jsp和hello.jsp之間為轉(zhuǎn)發(fā)關(guān)系。authenticate.jsp希望向hello.jsp傳遞當(dāng)前的用戶名字,  如何傳遞這一數(shù)據(jù)呢?先在authenticate.jsp中調(diào)用setAttribute()方法:

                  <%
                  String  username=request.getParameter("username");
                  request.setAttribute("username",username);
                  %>

                  <jsp:forward  page="hello.jsp"  />

                  在hello.jsp中通過getAttribute()方法獲得用戶名字:

                  <%  String  username=(String)request.getAttribute("username");  %>
                  Hello:  <%=username  %>

                  從更深的層次考慮,request.getParameter()方法傳遞的數(shù)據(jù),會(huì)從Web客戶端傳到Web服務(wù)器端,代表HTTP請(qǐng)求數(shù)據(jù)。request.getParameter()方法返回String類型的數(shù)據(jù)。

                  request.setAttribute()和getAttribute()方法傳遞的數(shù)據(jù)只會(huì)存在于Web容器內(nèi)部,在具有轉(zhuǎn)發(fā)關(guān)系的Web組件之間共享。這兩個(gè)方法能夠設(shè)置Object類型的共享數(shù)據(jù)。

                  request.getParameter()取得是通過容器的實(shí)現(xiàn)來(lái)取得通過類似post,get等方式傳入的數(shù)據(jù)。

                  request.setAttribute()和getAttribute()只是在web容器內(nèi)部流轉(zhuǎn),僅僅是請(qǐng)求處理階段。

                  getAttribute是返回對(duì)象,getParameter返回字符串

                  總的來(lái)說(shuō):request.getAttribute()方法返回request范圍內(nèi)存在的對(duì)象,而request.getParameter()方法是獲取http提交過來(lái)的數(shù)據(jù)。

          posted @ 2008-09-20 09:57 chenkai 閱讀(2792) | 評(píng)論 (0)編輯 收藏

          用javascript實(shí)現(xiàn)table的排序

          <%@page
          language="java"
          contentType="text/html;charset=GBK"
          %>

          <html>
          <head>
              <title>MyHtml.html</title>
              <meta http-equiv="content-type" content="text/html; charset=gbk">
             
              <!--<link rel="stylesheet" type="text/css" href="./styles.css">-->

             <script  language="javascript">

           

          function   JM_PowerList(colNum)  
            {  
            headEventObject=event.srcElement;//取得引發(fā)事件的對(duì)象  
            while(headEventObject.tagName!="TR")   //不是tr行,則從底下的td冒泡上來(lái)尋找到相應(yīng)行  
            {  
            headEventObject=headEventObject.parentElement;  
            }  
             
            for   (i=0;i<headEventObject.children.length;i++)  
            {   alert(headEventObject.children[i].tagName);
            if   (headEventObject.children[i]!=event.srcElement)//找到事件發(fā)生的td單元格  
            {  
            headEventObject.children[i].className='listTableHead';//把點(diǎn)擊的列的className屬性設(shè)為listTableHead  
            }  
            }  
             
            var   tableRows=0;  
            trObject=clearStart.children[0].children;   //取得表格中行對(duì)象,   原來(lái)這里叫DataTable,   可能是你寫錯(cuò)了吧??  
            for   (i=0;i<trObject.length;i++)  
            {  
            Object=clearStart.children[0].children[i];//取得每行的對(duì)象  
            tableRows=(trObject[i].id=='ignore')?tableRows:tableRows+1;//如果不是忽略行,則行數(shù)加一  
            }  
             
            var   trinnerHTML=new   Array(tableRows);    
            var   tdinnerHTML=new   Array(tableRows);  
            var   tdNumber=new   Array(tableRows)  
            var   i0=0  
            var   i1=0  
            for   (i=0;i<trObject.length;i++)  
            {  
            if   (trObject[i].id!='ignore')  
            {  
            trinnerHTML[i0]=trObject[i].innerHTML;//把行放在數(shù)組里  
            tdinnerHTML[i0]=trObject[i].children[colNum].innerHTML;//把要排序的行中td的內(nèi)容放數(shù)組里  
            tdNumber[i0]=i;//行號(hào)  
            i0++;//加一,下個(gè)循環(huán)用  
            }  
            }  
            sourceHTML=clearStart.children[0].outerHTML;//取得表格中所有tr的html代碼  
             
            //對(duì)所有td中的字符串進(jìn)行排序,   算不算冒泡排序???  
            for   (bi=0;bi<tableRows;bi++)  
            {  
            for   (i=0;i<tableRows;i++)  
            {  
            if(tdinnerHTML[i]>tdinnerHTML[i+1])  
            {  
            t_s=tdNumber[i+1];  
            t_b=tdNumber[i];  
            tdNumber[i+1]=t_b;  
            tdNumber[i]=t_s;  
            temp_small=tdinnerHTML[i+1];  
            temp_big=tdinnerHTML[i];  
            tdinnerHTML[i+1]=temp_big;  
            tdinnerHTML[i]=temp_small;  
            }  
            }  
            }  
             
             
             
            var   showshow='';  
            var   numshow='';  
            for   (i=0;i<tableRows;i++)  
            {  
            showshow=showshow+tdinnerHTML[i]+' ';//把排序好的td的內(nèi)容存在showshow字串里  
            numshow=numshow+tdNumber[i]+'|';             //把排序好的相應(yīng)的行號(hào)也存在numshow中  
            }  
             
            sourceHTML_head=sourceHTML.split("<TBODY>");//從<TBODY>截?cái)?我試了,前頭串為空  
             
            numshow=numshow.split("|");  
            var   trRebuildHTML='';  
            if   (event.srcElement.className=='listHeadClicked')  
            {//已點(diǎn)擊的列,   則逆排  
            for   (i=0;i<tableRows;i++)  
            {  
            trRebuildHTML=trRebuildHTML+trObject[numshow[tableRows-1-i]].outerHTML;//取出排序好的tr的內(nèi)容連接起來(lái)  
             
            }  
            event.srcElement.className='listHeadClicked0';  
            }  
            else  
            {//默認(rèn)順排,新點(diǎn)擊順排  
            for   (i=0;i<tableRows;i++)  
            {  
            trRebuildHTML=trRebuildHTML+trObject[numshow[i]].outerHTML;  
            }  
            event.srcElement.className='listHeadClicked';  
            }  
            //取得排序后的tr集合結(jié)果字符串  
            var   DataRebuildTable='';  
            //把舊的表格頭和新的tr排序好的元素連接起來(lái),   (修改了一下)  
            DataRebuildTable   =   "<table   border=1 width=100%  cellpadding=1 cellspacing=1 id='clearStart'><TBODY>"
                +   trObject[0].outerHTML   +   trRebuildHTML   +   "</TBODY>"   +      "</table>";  
            clearStart.outerHTML=DataRebuildTable;//表格用新串重新寫一次  
             
            }  

          </script>

            </head>
          <table border=1 id="clearStart">
           <tr bgcolor=cccccc id='ignore'>
            <td onclick="JM_PowerList(0)">列一
            </td>
            <td onclick="JM_PowerList(1)">
             列二
            </td>
            <td onclick="JM_PowerList(2)">
             列二
            </td>
           </tr>
            <tr>
            <td>
             周
            </td>
            <td>
             公務(wù)員
            </td>
            <td>
             22
            </td>
           </tr>
           <tr>
            <td>
             張三
            </td>
            <td>
             研究員
            </td>
            <td>
             65
            </td>
           </tr>
           <tr>
            <td>
             李思
            </td>
            <td>
             科學(xué)家
            </td>
            <td>
             24
            </td>
           </tr>
           <tr>
            <td>
            王武
            </td>
            <td>
             社會(huì)學(xué)家
            </td>
            <td>
             38
            </td>
           </tr>
          </table>
          </body></html>

           

          posted @ 2008-08-09 11:40 chenkai 閱讀(396) | 評(píng)論 (0)編輯 收藏

          Java 編程技術(shù)中漢字問題的分析及解決

          在基于 Java 語(yǔ)言的編程中,我們經(jīng)常碰到漢字的處理及顯示的問題。一大堆看不懂的亂碼肯定不是我們?cè)敢饪吹降娘@示效果,怎樣才能夠讓那些漢字正確顯示呢?Java語(yǔ)言默認(rèn)的編碼方式是UNICODE,而我們中國(guó)人通常使用的文件和數(shù)據(jù)庫(kù)都是基于GB2312或者BIG5等方式編碼的,怎樣才能夠恰當(dāng)?shù)剡x擇漢字編碼方式并正確地處理漢字的編碼呢?本文將從漢字編碼的常識(shí)入手,結(jié)合Java編程實(shí)例,分析以上兩個(gè)問題并提出解決它們的方案。

          現(xiàn)在 Java 編程語(yǔ)言已經(jīng)廣泛應(yīng)用于互聯(lián)網(wǎng)世界,早在 Sun 公司開發(fā) Java 語(yǔ)言的時(shí)候,就已經(jīng)考慮到對(duì)非英文字符的支持了。Sun 公司公布的 Java 運(yùn)行環(huán)境(JRE)本身就分英文版和國(guó)際版,但只有國(guó)際版才支持非英文字符。不過在 Java 編程語(yǔ)言的應(yīng)用中,對(duì)中文字符的支持并非如同 Java Soft 的標(biāo)準(zhǔn)規(guī)范中所宣稱的那樣完美,因?yàn)橹形淖址恢灰粋€(gè),而且不同的操作系統(tǒng)對(duì)中文字符的支持也不盡相同,所以會(huì)有許多和漢字編碼處理有關(guān)的問題在我們進(jìn)行應(yīng)用開發(fā)中困擾著我們。有很多關(guān)于這些問題的解答,但都比較瑣碎,并不能夠滿足大家迫切解決問題的愿望,關(guān)于 Java 中文問題的系統(tǒng)研究并不多,本文從漢字編碼常識(shí)出發(fā),分析 Java 中文問題,希望對(duì)大家解決這個(gè)問題有所幫助。

          漢字編碼的常識(shí)

          我們知道,英文字符一般是以一個(gè)字節(jié)來(lái)表示的,最常用的編碼方法是 ASCII 。但一個(gè)字節(jié)最多只能區(qū)分256個(gè)字符,而漢字成千上萬(wàn),所以現(xiàn)在都以雙字節(jié)來(lái)表示漢字,為了能夠與英文字符分開,每個(gè)字節(jié)的最高位一定為1,這樣雙字節(jié)最多可以表示64K格字符。我們經(jīng)常碰到的編碼方式有 GB2312、BIG5、UNICODE 等。關(guān)于具體編碼方式的詳細(xì)資料,有興趣的讀者可以查閱相關(guān)資料。我膚淺談一下和我們關(guān)系密切的 GB2312 和 UNICODE。GB2312 碼,中華人民共和國(guó)國(guó)家標(biāo)準(zhǔn)漢字信息交換用編碼,是一個(gè)由中華人民共和國(guó)國(guó)家標(biāo)準(zhǔn)總局發(fā)布的關(guān)于簡(jiǎn)化漢字的編碼,通行于中國(guó)大陸地區(qū)及新加坡,簡(jiǎn)稱國(guó)標(biāo)碼。兩個(gè)字節(jié)中,第一個(gè)字節(jié)(高字節(jié))的值為區(qū)號(hào)值加32(20H),第二個(gè)字節(jié)(低字節(jié))的值為位號(hào)值加32(20H),用這兩個(gè)值來(lái)表示一個(gè)漢字的編碼。UNICODE 碼是微軟提出的解決多國(guó)字符問題的多字節(jié)等長(zhǎng)編碼,它對(duì)英文字符采取前面加“0”字節(jié)的策略實(shí)現(xiàn)等長(zhǎng)兼容。如 “A” 的 ASCII 碼為0x41,UNICODE 就為0x00,0x41。利用特殊的工具各種編碼之間可以互相轉(zhuǎn)換。

          Java 中文問題的初步認(rèn)識(shí)

          我們基于 Java 編程語(yǔ)言進(jìn)行應(yīng)用開發(fā)時(shí),不可避免地要處理中文。Java 編程語(yǔ)言默認(rèn)的編碼方式是 UNICODE,而我們通常使用的數(shù)據(jù)庫(kù)及文件都是基于 GB2312 編碼的,我們經(jīng)常碰到這樣的情況:瀏覽基于 JSP 技術(shù)的網(wǎng)站看到的是亂碼,文件打開后看到的也是亂碼,被 Java 修改過的數(shù)據(jù)庫(kù)的內(nèi)容在別的場(chǎng)合應(yīng)用時(shí)無(wú)法繼續(xù)正確地提供信息。

          String sEnglish = “apple”;
          String sChinese = “蘋果”;
          String s = “蘋果 apple ”;

          sEnglish 的長(zhǎng)度是5,sChinese的長(zhǎng)度是4,而 s 默認(rèn)的長(zhǎng)度是14。對(duì)于 sEnglish來(lái)說(shuō), Java 中的各個(gè)類都支持得非常好,肯定能夠正確顯示。但對(duì)于 sChinese 和 s 來(lái)說(shuō),雖然 Java Soft 聲明 Java 的基本類已經(jīng)考慮到對(duì)多國(guó)字符的支持(默認(rèn) UNICODE 編碼),但是如果操作系統(tǒng)的默認(rèn)編碼不是 UNICODE ,而是國(guó)標(biāo)碼等。從 Java 源代碼到得到正確的結(jié)果,要經(jīng)過 “Java 源代碼-> Java 字節(jié)碼-> ;虛擬機(jī)->操作系統(tǒng)->顯示設(shè)備”的過程。在上述過程中的每一步驟,我們都必須正確地處理漢字的編碼,才能夠使最終的顯示結(jié)果正確。

          “ Java 源代碼-> Java 字節(jié)碼”,標(biāo)準(zhǔn)的 Java 編譯器 javac 使用的字符集是系統(tǒng)默認(rèn)的字符集,比如在中文 Windows 操作系統(tǒng)上就是 GBK ,而在 Linux 操作系統(tǒng)上就是ISO-8859-1,所以大家會(huì)發(fā)現(xiàn)在 Linux 操作系統(tǒng)上編譯的類中源文件中的中文字符都出了問題,解決的辦法就是在編譯的時(shí)候添加 encoding 參數(shù),這樣才能夠與平臺(tái)無(wú)關(guān)。用法是

          javac -encoding GBK。

          “ Java 字節(jié)碼->虛擬機(jī)->操作系統(tǒng)”, Java 運(yùn)行環(huán)境 (JRE)分英文版和國(guó)際版,但只有國(guó)際版才支持非英文字符。 Java 開發(fā)工具包 (JDK) 肯定支持多國(guó)字符,但并非所有的計(jì)算機(jī)用戶都安裝了 JDK 。很多操作系統(tǒng)及應(yīng)用軟件為了能夠更好的支持 Java ,都內(nèi)嵌了 JRE 的國(guó)際版本,為自己支持多國(guó)字符提供了方便。

          “操作系統(tǒng)->顯示設(shè)備”,對(duì)于漢字來(lái)說(shuō),操作系統(tǒng)必須支持并能夠顯示它。英文操作系統(tǒng)如果不搭配特殊的應(yīng)用軟件的話,是肯定不能夠顯示中文的。

          還有一個(gè)問題,就是在 Java 編程過程中,對(duì)中文字符進(jìn)行正確的編碼轉(zhuǎn)換。例如,向網(wǎng)頁(yè)輸出中文字符串的時(shí)候,不論你是用

          out.println(string);還是用

          <%=string%>,都必須作 UNICODE 到 GBK 的轉(zhuǎn)換,或者手動(dòng),或者自動(dòng)。在 JSP 1.0中,可以定義輸出字符集,從而實(shí)現(xiàn)內(nèi)碼的自動(dòng)轉(zhuǎn)換。用法是

          <%@page contentType=”text/html;charset=gb2312” %>

          但是在一些 JSP 版本中并沒有提供對(duì)輸出字符集的支持,(例如 JSP 0.92),這就需要手動(dòng)編碼輸出了,方法非常多。最常用的方法是

          String s1 = request.getParameter(“keyword”);

          String s2 = new String(s1.getBytes(“ISO-8859-1”),”GBK”);

          getBytes 方法用于將中文字符以“ISO-8859-1”編碼方式轉(zhuǎn)化成字節(jié)數(shù)組,而“GBK” 是目標(biāo)編碼方式。我們從以ISO-8859-1方式編碼的數(shù)據(jù)庫(kù)中讀出中文字符串 s1 ,經(jīng)過上述轉(zhuǎn)換過程,在支持 GBK 字符集的操作系統(tǒng)和應(yīng)用軟件中就能夠正確顯示中文字符串 s2 。


          Java 中文問題的表層分析及處理
          背景
          開發(fā)環(huán)境 JDK1.15 Vcafe2.0 JPadPro
          服務(wù)器端 NT IIS Sybase System Jconnect(JDBC)
          客戶端 IE5.0 Pwin98 ?span >

          .CLASS 文件存放在服務(wù)器端,由客戶端的瀏覽器運(yùn)行 APPLET , APPLET 只起調(diào)入 FRAME 類等主程序的作用。界面包括 Textfield ,TextArea,List,Choice 等。

          I.用 JDBC 執(zhí)行 SELECT 語(yǔ)句從服務(wù)器端讀取數(shù)據(jù)(中文)后,將數(shù)據(jù)用 APPEND 方法加到 TextArea(TA) ,不能正確顯示。但加到 List 中時(shí),大部分漢字卻可正確顯示。

          將數(shù)據(jù)按“ISO-8859-1” 編碼方式轉(zhuǎn)化為字節(jié)數(shù)組,再按系統(tǒng)缺省編碼方式 (Default Character Encoding) 轉(zhuǎn)化為 STRING ,即可在 TA 和 List 中正確顯示。

          程序段如下:

          dbstr2 = results.getString(1);
          //After reading the result from DB server,converting it to string.
          dbbyte1 = dbstr2.getBytes(“iso-8859-1”);
          dbstr1 = new String(dbbyte1);

          在轉(zhuǎn)換字符串時(shí)不采用系統(tǒng)默認(rèn)編碼方式,而直接采用“ GBK” 或者 “GB2312” ,在 A 和 B 兩種情況下,從數(shù)據(jù)庫(kù)取數(shù)據(jù)都沒有問題。

          II.處理方式與“取中文”相逆,先將 SQL 語(yǔ)句按系統(tǒng)缺省編碼方式轉(zhuǎn)化為字節(jié)數(shù)組,再按“ISO-8859-1”編碼方式轉(zhuǎn)化為 STRING ,最后送去執(zhí)行,則中文信息可正確寫入數(shù)據(jù)庫(kù)。

          程序段如下:

          sqlstmt = tf_input.getText();
          //Before sending statement to DB server,converting it to sql statement.
          dbbyte1 = sqlstmt.getBytes();
          sqlstmt = newString(dbbyte1,”iso-8859-1”);
          _stmt = _con.createStatement();
          _stmt.executeUpdate(sqlstmt);
          ……

          問題:如果客戶機(jī)上存在 CLASSPATH 指向 JDK 的 CLASSES.ZIP 時(shí)(稱為 A 情況),上述程序代碼可正確執(zhí)行。但是如果客戶機(jī)只有瀏覽器,而沒有 JDK 和 CLASSPATH 時(shí)(稱為 B 情況),則漢字無(wú)法正確轉(zhuǎn)換。

          我們的分析:

          1.經(jīng)過測(cè)試,在 A 情況下,程序運(yùn)行時(shí)系統(tǒng)的缺省編碼方式為 GBK 或者 GB2312 。在 B 情況下,程序啟動(dòng)時(shí)瀏覽器的 JAVA 控制臺(tái)中出現(xiàn)如下錯(cuò)誤信息:

          Can't find resource for sun.awt.windows.awtLocalization_zh_CN

          然后系統(tǒng)的缺省編碼方式為“8859-1”。

          2.如果在轉(zhuǎn)換字符串時(shí)不采用系統(tǒng)缺省編碼方式,而是直接采用 “GBK” 或“GB2312”,則在 A 情況下程序仍然可正常運(yùn)行,在 B 情況下,系統(tǒng)出現(xiàn)錯(cuò)誤:

          UnsupportedEncodingException。

          3. 在客戶機(jī)上,把 JDK 的 CLASSES.ZIP 解壓后,放在另一個(gè)目錄中, CLASSPATH 只包含該目錄。然后一邊逐步刪除該目錄中的 .CLASS 文件,另一邊運(yùn)行測(cè)試程序,最后發(fā)現(xiàn)在一千多個(gè) CLASS 文件中,只有一個(gè)是必不可少的,該文件是:

          sun.io.CharToByteDoubleByte.class。

          將該文件拷到服務(wù)器端和其它的類放在一起,并在程序的開頭 IMPORT 它,在 B 情況下程序仍然無(wú)法正常運(yùn)行。

          4.在 A 情況下,如果在 CLASSPTH 中去掉 sun.io.CharToByteDoubleByte.class ,則程序運(yùn)行時(shí)測(cè)得默認(rèn)編碼方式為“8859-1”,否則為 “GBK” 或 “GB2312” 。

          如果 JDK 的版本為1.2以上的話,在 B 情況下遇到的問題得到了很好的解決,測(cè)試的步驟同上,有興趣的讀者可以嘗試一下。

          Java 中文問題的根源分析及解決

          在簡(jiǎn)體中文 MS Windows 98 + JDK 1.3 下,可以用 System.getProperties() 得到 Java 運(yùn)行環(huán)境的一些基本屬性,類 PoorChinese 可以幫助我們得到這些屬性。

          類 PoorChinese 的源代碼:

          public class PoorChinese {
          }

          執(zhí)行 java PoorChinese 后,我們會(huì)得到:

          系統(tǒng)變量 file.encoding 的值為 GBK ,user.language 的值為 zh , user.region 的值為 CN ,這些系統(tǒng)變量的值決定了系統(tǒng)默認(rèn)的編碼方式是 GBK 。

          在上述系統(tǒng)中,下面的代碼將 GB2312 文件轉(zhuǎn)換成 Big5 文件,它們能夠幫助我們理解 Java 中漢字編碼的轉(zhuǎn)化:


          import java.io.*;
          import java.util.*;

          public class gb2big5 {

          static int iCharNum=0;

          public static void main(String[] args) {
          System.out.println("Input GB2312 file, output Big5 file.");
          if (args.length!=2) {
          System.err.println("Usage: jview gb2big5 gbfile big5file");
          System.exit(1);
          String inputString = readInput(args[0]);
          writeOutput(inputString,args[1]);
          System.out.println("Number of Characters in file: "+iCharNum+".");
          }

          static void writeOutput(String str, String strOutFile) {
          try {
          FileOutputStream fos = new FileOutputStream(strOutFile);
          Writer out = new OutputStreamWriter(fos, "Big5");
          out.write(str);
          out.close();
          }
          catch (IOException e) {
          e.printStackTrace();
          e.printStackTrace();
          }
          }

          static String readInput(String strInFile) {
          StringBuffer buffer = new StringBuffer();
          try {
          FileInputStream fis = new FileInputStream(strInFile);
          InputStreamReader isr = new InputStreamReader(fis, "GB2312");
          Reader in = new BufferedReader(isr);
          int ch;
          while ((ch = in.read()) > -1) {
          iCharNum += 1;
          buffer.append((char)ch);
          }
          in.close();
          return buffer.toString();
          }
          catch (IOException e) {
          e.printStackTrace();
          return null;
          }
          }
          }

          編碼轉(zhuǎn)化的過程如下:

          GB2312------------------>Unicode------------->Big5

          執(zhí)行 java gb2big5 gb.txt big5.txt ,如果 gb.txt 的內(nèi)容是“今天星期三”,則得到的文件 big5.txt 中的字符能夠正確顯示;而如果 gb.txt 的內(nèi)容是“情人節(jié)快樂”,則得到的文件 big5.txt 中對(duì)應(yīng)于“節(jié)”和“樂”的字符都是符號(hào)“?”(0x3F),可見 sun.io.ByteToCharGB2312 和 sun.io.CharToByteBig5 這兩個(gè)基本類并沒有編好。

          正如上例一樣, Java 的基本類也可能存在問題。由于國(guó)際化的工作并不是在國(guó)內(nèi)完成的,所以在這些基本類發(fā)布之前,沒有經(jīng)過嚴(yán)格的測(cè)試,所以對(duì)中文字符的支持并不像 Java Soft 所聲稱的那樣完美。前不久,我的一位技術(shù)上的朋友發(fā)信給我說(shuō),他終于找到了 Java Servlet 中文問題的根源。兩周以來(lái),他一直為 Java Servlet 的中文問題所困擾,因?yàn)槊棵鎸?duì)一個(gè)含有中文字符的字符串都必須進(jìn)行強(qiáng)制轉(zhuǎn)換才能夠得到正確的結(jié)果(這好象是大家公認(rèn)的唯一的解決辦法)。后來(lái),他確實(shí)不想如此繼續(xù)安分下去了,因?yàn)檫@樣的事情確實(shí)不應(yīng)該是高級(jí)程序員所要做的工作,他就找出 Servlet 解碼的源代碼進(jìn)行分析,因?yàn)樗麘岩蓡栴}就出在解碼這部分。經(jīng)過四個(gè)小時(shí)的奮斗,他終于找到了問題的根源所在。原來(lái)他的懷疑是正確的, Servlet 的解碼部分完全沒有考慮雙字節(jié),直接把 %XX 當(dāng)作一個(gè)字符。(原來(lái) Java Soft 也會(huì)犯這幺低級(jí)的錯(cuò)誤!)

          如果你對(duì)這個(gè)問題有興趣或者遇到了同樣的煩惱的話,你可以按照他的步驟 對(duì)Servlet.jar 進(jìn)行修改:

          找到源代碼 HttpUtils 中的 static private String parseName ,在返回前將 sb(StringBuffer) 復(fù)制成 byte bs[] ,然后 return new String(bs,”GB2312”)。作上述修改后就需要自己解碼了:

          HashTable form=HttpUtils .parseQueryString(request.getQueryString())或者

          form=HttpUtils.parsePostData(……)

          千萬(wàn)別忘了編譯后放到 Servlet.jar 里面。

          關(guān)于 Java 中文問題的總結(jié)

          Java 編程語(yǔ)言成長(zhǎng)于網(wǎng)絡(luò)世界,這就要求 Java 對(duì)多國(guó)字符有很好的支持。 Java 編程語(yǔ)言適應(yīng)了計(jì)算的網(wǎng)絡(luò)化的需求,為它能夠在網(wǎng)絡(luò)世界迅速成長(zhǎng)奠定了堅(jiān)實(shí)的基礎(chǔ)。 Java 的締造者 (Java Soft) 已經(jīng)考慮到 Java 編程語(yǔ)言對(duì)多國(guó)字符的支持,只是現(xiàn)在的解決方案有很多缺陷在里面,需要我們付諸一些補(bǔ)償性的措施。而世界標(biāo)準(zhǔn)化組織也在努力把人類所有的文字統(tǒng)一在一種編碼之中,其中一種方案是 ISO10646 ,它用四個(gè)字節(jié)來(lái)表示一個(gè)字符。當(dāng)然,在這種方案未被采用之前,還是希望 Java Soft 能夠嚴(yán)格地測(cè)試它的產(chǎn)品,為用戶帶來(lái)更多的方便。

          posted @ 2008-07-30 17:16 chenkai 閱讀(174) | 評(píng)論 (0)編輯 收藏

          <2008年7月>
          293012345
          6789101112
          13141516171819
          20212223242526
          272829303112
          3456789

          導(dǎo)航

          統(tǒng)計(jì)

          常用鏈接

          留言簿(2)

          隨筆檔案

          搜索

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          主站蜘蛛池模板: 侯马市| 子长县| 潍坊市| 霍山县| 新干县| 怀来县| 都昌县| 邢台县| 武城县| 永仁县| 浦东新区| 乐山市| 肃南| 南投县| 蓬溪县| 江北区| 吉首市| 柳州市| 老河口市| 双桥区| 信丰县| 仪征市| 九江县| 秦安县| 山东省| 建瓯市| 山丹县| 丹东市| 施秉县| 瑞安市| 运城市| 武宣县| 吉林省| 萨迦县| 根河市| 诏安县| 林州市| 天柱县| 五指山市| 澄江县| 白银市|