<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Rookie

    Headache English

    數(shù)據(jù)加載中……
    J2EE開發(fā)中字符處理
            在java企業(yè)級開發(fā)中,會(huì)有多處涉及到字符集編碼,有些地方需要進(jìn)行正確的設(shè)置,有些地方需要進(jìn)行一定程度的處理。

    一,java中對字符的處理

            getBytes(charset):這是java字符串處理的一個(gè)標(biāo)準(zhǔn)函數(shù),其作用是將字符串所表示的字符按照charset編碼,并以字節(jié)方式表示。注意字符串在java內(nèi)存中總是按unicode編碼存儲的。比如"中文",正常情況下(即沒有錯(cuò)誤的時(shí)候)存儲為"4e2d 6587",如果charset為"gbk",則被編碼為"d6d0 cec4",然后返回字節(jié)"d6 d0 ce c4"。如果charset為"utf8"則最后是"e4 b8 ad e6 96 87"。如果是"iso8859-1",則由于無法編碼,最后返回 "3f 3f"(兩個(gè)問號)。
            new String(charset)這是java字符串處理的另一個(gè)標(biāo)準(zhǔn)函數(shù),和上一個(gè)函數(shù)的作用相反,將字節(jié)數(shù)組按照charset編碼進(jìn)行組合識別,最后轉(zhuǎn)換為unicode存儲。參考上述getBytes的例子,"gbk" 和"utf8"都可以得出正確的結(jié)果"4e2d 6587",但iso8859-1最后變成了"003f 003f"(兩個(gè)問號)。因?yàn)閡tf8可以用來表示/編碼所有字符,所以new String( str.getBytes( "utf8" ), "utf8" ) == str,即完全可逆。
           
    setCharacterEncoding()該函數(shù)用來設(shè)置http請求或者相應(yīng)的編碼。對于request,是指提交內(nèi)容的編碼,指定后可以通過getParameter()則直接獲得正確的字符串,如果不指定,則默認(rèn)使用iso8859-1編碼,需要進(jìn)一步處理。參見下述"表單輸入"。值得注意的是在執(zhí)行setCharacterEncoding()之前,不能執(zhí)行任何getParameter()。java doc上說明:This method must be called prior to reading request parameters or reading input using getReader()。而且,該指定只對POST方法有效,對GET方法無效。分析原因,應(yīng)該是在執(zhí)行第一個(gè)getParameter()的時(shí)候,java將會(huì)按照編碼分析所有的提交內(nèi)容,而后續(xù)的getParameter()不再進(jìn)行分析,所以setCharacterEncoding()無效。而對于GET方法提交表單是,提交的內(nèi)容在URL中,一開始就已經(jīng)按照編碼分析所有的提交內(nèi)容,setCharacterEncoding()自然就無效。對于response,則是指定輸出內(nèi)容的編碼,同時(shí),該設(shè)置會(huì)傳遞給瀏覽器,告訴瀏覽器輸出內(nèi)容所采用的編碼。

    二,web開發(fā)中字符編碼幾處設(shè)置
           對于web應(yīng)用程序,和編碼有關(guān)的設(shè)置或者函數(shù)如下。
            jsp編譯:指定文件的存儲編碼,很明顯,該設(shè)置應(yīng)該置于文件的開頭。例如:<@pagepageEncoding="GBK"%>。另外,對于一般class文件,可以在編譯的時(shí)候指定編碼。
            
    jsp輸出:指定文件輸出到browser是使用的編碼,該設(shè)置也應(yīng)該置于文件的開頭。例如:<%@ page contentType="text/html; charset= GBK" %>。該設(shè)置和response.setCharacterEncoding("GBK")等效。
            
    meta設(shè)置:指定網(wǎng)頁使用的編碼,該設(shè)置對靜態(tài)網(wǎng)頁尤其有作用。因?yàn)殪o態(tài)網(wǎng)頁無法采用jsp的設(shè)置,而且也無法執(zhí)行response.setCharacterEncoding()。例如:<META http-equiv="Content-Type" content="text/html; charset=GBK" />,如果同時(shí)采用了jsp輸出和meta設(shè)置兩種編碼指定方式,則jsp指定的優(yōu)先。因?yàn)閖sp指定的直接體現(xiàn)在response中。需要注意的是,apache有一個(gè)設(shè)置可以給無編碼指定的網(wǎng)頁指定編碼,該指定等同于jsp的編碼指定方式,所以會(huì)覆蓋靜態(tài)網(wǎng)頁中的meta指定。所以有人建議關(guān)閉該設(shè)置。
            
    form設(shè)置:當(dāng)瀏覽器提交表單的時(shí)候,可以指定相應(yīng)的編碼。例如:<form accept-charset= "gb2312">。一般不必不使用該設(shè)置,瀏覽器會(huì)直接使用網(wǎng)頁的編碼。

    三,URL地址

            URL地址中含有中文字符是很麻煩的,前面描述過使用GET方法提交表單的情況,使用GET方法時(shí),參數(shù)就是包含在URL中。
            URL編碼:對于URL中的一些特殊字符,瀏覽器會(huì)自動(dòng)進(jìn)行編碼。這些字符除了"/?&"等外,還包括unicode字符,比如漢子。這時(shí)的編碼比較特殊。
            
    IE有一個(gè)選項(xiàng)"總是使用UTF-8發(fā)送URL",當(dāng)該選項(xiàng)有效時(shí),IE將會(huì)對特殊字符進(jìn)行UTF-8編碼,同時(shí)進(jìn)行URL編碼。如果改選項(xiàng)無效,則使用默認(rèn)編碼"GBK",并且不進(jìn)行URL編碼。但是,對于URL后面的參數(shù),則總是不進(jìn)行編碼,相當(dāng)于UTF-8選項(xiàng)無效。比如"中文.html?a=中文",當(dāng)UTF-8選項(xiàng)有效時(shí),將發(fā)送鏈接"%e4%b8%ad%e6%96%87.html?a=\x4e\x2d\x65\x87";而UTF-8選項(xiàng)無效時(shí),將發(fā)送鏈接"\x4e\x2d\x65\x87.html?a=\x4e\x2d\x65\x87"。注意后者前面的"中文"兩個(gè)字只有4個(gè)字節(jié),而前者卻有18個(gè)字節(jié),這主要時(shí)URL編碼的原因。當(dāng)web server(tomcat)接收到該鏈接時(shí),將會(huì)進(jìn)行URL解碼,即去掉"%",同時(shí)按照ISO8859-1編碼(上面已經(jīng)描述,可以使用URLEncoding來設(shè)置成其它編碼)識別。上述例子的結(jié)果分別是"\ue4\ub8\uad\ue6\u96\u87.html?a=\u4e\u2d\u65\u87"和"\u4e\u2d\u65\u87.html?a=\u4e\u2d\u65\u87",注意前者前面的"中文"兩個(gè)字恢復(fù)成了6個(gè)字符。這里用"\u",表示是unicode。所以,由于客戶端設(shè)置的不同,相同的鏈接,在服務(wù)器上得到了不同結(jié)果。這個(gè)問題不少人都遇到,卻沒有很好的解決辦法。所以有的網(wǎng)站會(huì)建議用戶嘗試關(guān)閉UTF-8選項(xiàng)。不過,下面會(huì)描述一個(gè)更好的處理辦法。
            
    rewrite:熟悉的人都知道,apache有一個(gè)功能強(qiáng)大的rewrite模塊,這里不描述其功能。需要說明的是該模塊會(huì)自動(dòng)將URL解碼(去除%),即完成上述web server(tomcat)的部分功能。有相關(guān)文檔介紹說可以使用[NE]參數(shù)來關(guān)閉該功能,但我試驗(yàn)并未成功,可能是因?yàn)榘姹荆ㄎ沂褂玫氖莂pache 2.0.54)問題。另外,當(dāng)參數(shù)中含有"?& "等符號的時(shí)候,該功能將導(dǎo)致系統(tǒng)得不到正常結(jié)果。rewrite本身似乎完全是采用字節(jié)處理的方式,而不考慮字符串的編碼,所以不會(huì)帶來編碼問題。
            
    URLEncode.encode():這是Java本身提供對的URL編碼函數(shù),完成的工作和上述UTF-8選項(xiàng)有效時(shí)瀏覽器所做的工作相似。值得說明的是,java已經(jīng)不贊成不指定編碼來使用該方法(deprecated)。應(yīng)該在使用的時(shí)候增加編碼指定。當(dāng)不指定編碼的時(shí)候,該方法使用系統(tǒng)默認(rèn)編碼,這會(huì)導(dǎo)致軟件運(yùn)行結(jié)果得不確定。比如對于"中文",當(dāng)系統(tǒng)默認(rèn)編碼為"gb2312"時(shí),結(jié)果是"%4e%2d%65%87",而默認(rèn)編碼為"UTF-8",結(jié)果卻是"%e4%b8%ad%e6%96%87",后續(xù)程序?qū)㈦y以處理。另外,這兒說的系統(tǒng)默認(rèn)編碼是由運(yùn)行tomcat時(shí)的環(huán)境變量LC_ALL和LANG等決定的,曾經(jīng)出現(xiàn)過tomcat重啟后就出現(xiàn)亂碼的問題,最后才郁悶的發(fā)現(xiàn)是因?yàn)樾薷男薷牧诉@兩個(gè)環(huán)境變量。建議統(tǒng)一指定為"UTF-8"編碼,可能需要修改相應(yīng)的程序。
            
            
    一個(gè)解決方案
           上面說起過,因?yàn)闉g覽器設(shè)置的不同,對于同一個(gè)鏈接,web server收到的是不同內(nèi)容,而軟件系統(tǒng)有無法知道這中間的區(qū)別,所以這一協(xié)議目前還存在缺陷。
            
    針對具體問題,不應(yīng)該僥幸認(rèn)為所有客戶的IE設(shè)置都是UTF-8有效的,也不應(yīng)該粗暴的建議用戶修改IE設(shè)置,要知道,用戶不可能去記住每一個(gè)web server的設(shè)置。所以,接下來的解決辦法就只能是讓自己的程序多一點(diǎn)智能:根據(jù)內(nèi)容來分析編碼是否UTF-8。   
            
    比較幸運(yùn)的是UTF-8編碼相當(dāng)有規(guī)律,所以可以通過分析傳輸過來的鏈接內(nèi)容,來判斷是否是正確的UTF-8字符,如果是,則以UTF-8處理之,如果不是,則使用客戶默認(rèn)編碼(比如"GBK"),下面是一個(gè)判斷是否UTF-8的例子,如果你了解相應(yīng)規(guī)律,就容易理解

    public static boolean isValidUtf8(byte[] b,int aMaxCount){

           
    int lLen=b.length,lCharCount=0;

           
    for(int i=0;i<lLen && lCharCount<aMaxCount;++lCharCount){

                  
    byte lByte=b[i++];//to fast operation, ++ now, ready for the following for(;;)

                  
    if(lByte>=0continue;//>=0 is normal ascii

                  
    if(lByte<(byte)0xc0 || lByte>(byte)0xfreturn false;

                  
    int lCount=lByte>(byte)0xfc?5:lByte>(byte)0xf8?4

                         :lByte
    >(byte)0xf0?3:lByte>(byte)0xe0?2:1;

                  
    if(i+lCount>lLen) return false;

                  
    for(int j=0;j<lCount;++j,++i) if(b[i]>=(byte)0xc0return false;

           }

           
    return true;

    }

    相應(yīng)地,一個(gè)使用上述方法的例子如下:

    public static String getUrlParam(String aStr,String aDefaultCharset)

    throws UnsupportedEncodingException{

           
    if(aStr==nullreturn null;

           
    byte[] lBytes=aStr.getBytes("ISO-8859-1");

           
    return new String(lBytes,StringUtil.isValidUtf8(lBytes)?"utf8":aDefaultCharset);

    }

    不過,該方法也存在缺陷,如下兩方面:
            
    沒有包括對用戶默認(rèn)編碼的識別,這可以根據(jù)請求信息的語言來判斷,但不一定正確,因?yàn)槲覀冇袝r(shí)候也會(huì)輸入一些韓文,或者其他文字。
            
    可能會(huì)錯(cuò)誤判斷UTF-8字符,一個(gè)例子是"學(xué)習(xí)"兩個(gè)字,其GBK編碼是" \xd1\xa7\xcf\xb0",如果使用上述isValidUtf8方法判斷,將返回true。可以考慮使用更嚴(yán)格的判斷方法,不過估計(jì)效果不大。
            
    有一個(gè)例子可以證明google也遇到了上述問題,而且也采用了和上述相似的處理方法,比如,如果在地址欄中輸入"http://www.google.com/search?hl=zh-CN&newwindow=1&q=學(xué)習(xí)",google將無法正確識別,而其他漢字一般能夠正常識別。最后,應(yīng)該補(bǔ)充說明一下,如果不使用rewrite規(guī)則,或者通過表單提交數(shù)據(jù),其實(shí)并不一定會(huì)遇到上述問題,因?yàn)檫@時(shí)可以在提交數(shù)據(jù)時(shí)指定希望的編碼。另外,中文文件名確實(shí)會(huì)帶來問題,應(yīng)該謹(jǐn)慎使用。

    四,過濾器
            
    如果需要統(tǒng)一設(shè)置編碼,則通過filter進(jìn)行設(shè)置是個(gè)不錯(cuò)的選擇。在filter class中,可以統(tǒng)一為需要的請求或者回應(yīng)設(shè)置編碼。參加上述setCharacterEncoding()。這個(gè)類apache已經(jīng)給出了可以直接使用的例SetCharacterEncodingFilter。

    posted on 2008-01-05 17:36 zhhang920 閱讀(313) 評論(0)  編輯  收藏 所屬分類: J2EE

    主站蜘蛛池模板: 成人毛片18女人毛片免费| 无码精品一区二区三区免费视频 | 四虎亚洲精品高清在线观看| 免费国产叼嘿视频大全网站| 亚洲AV综合色区无码一区 | 青青操免费在线观看| 在线日韩日本国产亚洲| 好猛好深好爽好硬免费视频| 亚洲一区二区三区免费| 国产精品美女久久久免费| 亚洲午夜精品第一区二区8050| 国产精品美女久久久免费 | 永久免费AV无码网站国产| 亚洲精品无码成人片久久| 免费观看久久精彩视频| 亚洲综合久久久久久中文字幕| 国产精彩免费视频| 亚洲AV无码一区二区三区在线| 搡女人免费视频大全| 日韩精品亚洲专区在线影视| 亚洲一区二区三区免费| 一级毛片成人免费看免费不卡| 亚洲国产人成在线观看| 午夜视频免费观看| 农村寡妇一级毛片免费看视频| 久久久青草青青国产亚洲免观| 国产精品免费看久久久 | 精品无码国产污污污免费| 无遮挡国产高潮视频免费观看| 日本红怡院亚洲红怡院最新| 日本高清在线免费| 亚洲a∨国产av综合av下载| 亚洲一区视频在线播放| 99ee6热久久免费精品6| 亚洲欧好州第一的日产suv| 亚洲香蕉网久久综合影视| 3344永久在线观看视频免费首页| 亚洲av永久无码一区二区三区 | 国产成人免费一区二区三区| 男女拍拍拍免费视频网站| 亚洲国产精品张柏芝在线观看|