乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      Java平臺國際編碼問題分析_SUN-JAVA技術

       linyu2688 2006-11-16



        

                                  關于Java平臺國際化數(shù)據(jù)編碼常見問題分析   
        王旭科

      一、前言

       

      (CCW)經(jīng)常在看到有關討論Java相關技術的漢字的顯示,數(shù)據(jù)存儲漢字亂碼的解決方法。本人從事Java平臺相關開發(fā)也有近5年的時間,深感這種有關數(shù)據(jù)編碼(Encoding)的問題,不是一個 簡單的描述就可以指出問題的原因所在。目前零星的解決方案沒有提供一個全面的解釋。不同的瀏覽器,Web Server,Application Server,Database,支持的JDK版本不同,及設計的架構不周全,其組合是一個龐大的基數(shù),下面就從B/S 3層架構的角度,說明國際化的數(shù)據(jù)編碼常見問題的分析及解決方法。希望能分享自己的經(jīng)驗。

      二、常見Java應用架構

       

      以上是基本的Java常見架構,實際中可能Web server和應用服務器(Application Server)合二為一,不過為了清晰起見,還是分開顯示.

      2.1 請求/響應(Request/Response) 工作模式

      基于B/S架構的應用的模型,就是終端用戶通過瀏覽器向web Server發(fā)送請求,Web解釋并響應請求。其事件流模型可以參考標準HTTP協(xié)議獲得細節(jié)。常見的數(shù)據(jù)轉(zhuǎn)換及傳送發(fā)生以下三個環(huán)節(jié).所有的轉(zhuǎn)換都是雙向的.負責每個環(huán)節(jié)數(shù)據(jù)編碼(Encoding)的角色不同,需要對每個環(huán)節(jié)的角色進行正確的參數(shù)設定互相配合才能得到期望的結果。

      瀏覽器 ?----------?Web Server. Browser Render引擎/Web Server 引擎

      WebServer ?-------? 應用服務器 .JSP/Server 引擎及可能存在的其他連接WebServer

      和Application Server的Plugin.

      應用服務器 ?-------------? 數(shù)據(jù)庫 .每個數(shù)據(jù)庫廠家的JDBC驅(qū)動器.

      這里最重要和最易變的是Browser ?>WebServer ?-?JSP/Servet 之間的數(shù)據(jù)流和事件流發(fā)生的數(shù)據(jù)編碼,JDBC如果只是利用純粹的thin的模式來訪問數(shù)據(jù)庫,邏輯比較簡單,如果通過不同數(shù)據(jù)庫廠家為了提高性能提供的利用本地client的方式來訪問數(shù)據(jù)庫,其配置復雜性隨不同廠家而不同,這里略過。以下對該事件流做詳細描述,以闡述后面發(fā)生的”內(nèi)幕”.

      2.2 瀏覽器 HTML Render引擎如何顯示和提交數(shù)據(jù).核心的URL-Encoding.

      瀏覽器渲染html頁面里的內(nèi)容如何編碼,決策順序如下。

      首先瀏覽器根據(jù)Web Server發(fā)送的Content-Type Header,里的Charset信息來決定自己如何渲染html的顯示。如果沒有Content-Type,就根據(jù)Html頁面里的<meta>中的Content-Type來決定渲染的字符編碼.<meta>一般如下:

      <META HTTP-EQUIV="Content-Type"CONTENT="text/html; CHARSET= “UTF-8">

      一般出現(xiàn)亂碼的情況,有可能是content-type同實際數(shù)據(jù)不符,所以使用瀏覽器的”改變

      編碼”的功能換一個字符集合,就能看到正確的數(shù)據(jù).如果以上有關字符編碼的信息都無

      法得到,瀏覽器采用默認的ISO-8859-1來渲染HTML頁面

      其次,瀏覽器向WebServer通過 Form提交數(shù)據(jù)的時候,其編碼數(shù)據(jù)的行為決策順序如

      1.<Form>屬性的accept-charset,指定的字符編碼

      2.<meta>指定的Content-Type

      3.url-encoding 默認的字符編碼.

      這是標準按照HTML Internationalization (參考RFC 2070)規(guī)范的順序。

      根據(jù)實際的經(jīng)驗,F(xiàn)ireBird 瀏覽器(或Mozilla Familly) 完全順從這個順序。

      但IE 6 是2 <meta>指定的Content-Type優(yōu)先級別最高,所以,在HTML面在<body>

      標記之前,<head>標記后第一個寫入<meta>來聲明本頁的默認字符編碼,是良好的習慣。

      可以保證大多數(shù)瀏覽器可以正確渲染HTML數(shù)據(jù)。

      如果沒有指定任何Content-Type,瀏覽器將按照iso-8859-1這種字符編碼.

      URL-Encoding的詳細描述在(RFC 1738),重要的就是URL Encoding Converted.

      “Only alphanumerics [0-9a-zA-Z], the special characters "$-_.+!*‘()," [not including the quotes - ed], and reserved characters used for their reserved purposes may be used unencoded within a URL."”

      這種方式下,就是常見的%HH字符串的結果了。所有字符被編碼成 %HH字符串的方

      式被傳遞.

      如果<meta>中的charset指明的不符合實際數(shù)據(jù)或著指定的字符集合不包容實際輸入的

      字符集合,就會造成編碼錯誤,丟失數(shù)據(jù)信息。

      總之,瀏覽器向Web Server提交數(shù)據(jù)的時候,根據(jù)URL-Encodeds 編碼數(shù)據(jù)并且設置

      Content-Type 為application/x-www-form-urlencoded,但沒有傳送任何有關charset的信息。

      2.2.1 小結

      在HTML頁面或JSP/Servlet等動態(tài)生成的頁面里,必須指定正確的<meta>信

      息,才能保證數(shù)據(jù)顯示渲染和提交給Web Server數(shù)據(jù)是正確編碼的。如果沒有指定任

      何charset的信息,瀏覽器是按照ISO-8859-1編碼顯示和提交數(shù)據(jù),可能造成數(shù)據(jù)信

      息的丟失.

      2.3 Web Server 如何接受Post/get的數(shù)據(jù)

      通過2.2節(jié)的分析,我們可以知道,默認的情況下,WebServer是按照原始數(shù)據(jù)(raw data)來接受數(shù)據(jù)的。寫過CGI應用應該知道,這些數(shù)據(jù)是存放在服務器系統(tǒng)同應用相關的環(huán)境變量Cache中,我們常說的context(上下文)就包含了這些原始的提交數(shù)據(jù).

      2.4 JSP/Servlet 如何獲取數(shù)據(jù)

      當使用Servlet調(diào)用getParameter或getParameters時候,通過Servlet包容器(Container)上下文來從WebServer環(huán)境變量中獲取原始數(shù)據(jù)并編碼,但由于沒有關于Charset的信息,所以此時設置正確的字符編碼,才能把被URL-Encoding的數(shù)據(jù),正確還原。這是通過設置request的setCharacterEncoding來設置正確的字符集,才能得到正確數(shù)據(jù)。

      同時根據(jù)瀏覽器渲染HTML的規(guī)范,同樣送回瀏覽器的數(shù)據(jù)也必須指定正確的字符集才能保證瀏覽器正確編碼顯示,這是通過對response的setContentType方法調(diào)用來做到的。

      在實際應用中,了解了這些原理,不難寫出正確的處理數(shù)據(jù)的應用。Servlet 2.3規(guī)范提供了Filter技術,可以完美解決Post數(shù)據(jù)和回應信息的編碼問題,具體例子見附錄1.

      如果沒有Filter技術,則需要使用常用的“重構字符串”技術來解決這個問題,代碼見附錄2

      2.4.1 小結:

      判斷在Servlet中是否正確的重構了提交的(Post) 數(shù)據(jù),一個常見的小技巧是通過System.out.println打印出數(shù)據(jù)到后端控制臺,如果同系統(tǒng)當前字符集相同的數(shù)據(jù)能正確顯示,表明重構正確,比如你的服務器是Sun Solaris或Linux ,默認語言是中文,那么中文數(shù)據(jù)就可以正確的被打印出來,而不是一堆”?????”.

      2.5 JDBC 如何保存數(shù)據(jù)庫

      當把通過2.4 正確重構的數(shù)據(jù)要寫入數(shù)據(jù)庫時,同樣要考慮字符編碼的問題。

      首先必須在執(zhí)行JDBC或使用J2EE CMP通過setxxxx符值之前,調(diào)整數(shù)據(jù)的編碼同數(shù)據(jù)庫字符編碼一致,否則可能出錯。這種轉(zhuǎn)換同具體使用JDBC Driver 的方式不同而有所不同。假設純粹使用thin(Type 3或Type 4)的方式,相對比較簡單,只要知道正確的數(shù)據(jù)庫端的字符集,實現(xiàn)數(shù)據(jù)重構為符合數(shù)據(jù)庫字符編碼的數(shù)據(jù)就可以了,代碼見附錄 2

      三、通用國際化架構

      1、所有HTML或JSP/Servlet動態(tài)頁面<meta>指明字符集合為UTF-8

      2、Servlet 指明設置request獲取參數(shù)為UTF-8

      3、Servlet 指明reponse Content-Type 的charset為UTF-8

      4、數(shù)據(jù)庫編碼指明為UTF-8

      這是最簡明的國際化框架了.表現(xiàn)層HTML/JSP頁面可以用最終用戶本地語言編寫保存為Unicode模式,或通過字典方式根據(jù)用戶的選擇,來動態(tài)顯示HTML/JSP頁面上的本地語言提示性標簽。在JSTL 1.0推出后,沒有理由再使用本地語言編寫多套HTML/JSP頁面,帶來維護和代碼的復雜性。當然具體應用是復雜的,這里只是給出一個建議性的措施。

      本文給出比較細節(jié)的解釋了B/S架構下涉及到的Java編碼的方面,有助于出現(xiàn)問題時,快速定位問題環(huán)節(jié)并解決之。

      各種規(guī)范發(fā)展的很快,如果本文描述有錯誤或更好的實現(xiàn),歡迎指正.

      本文代碼在Jboss 3.2.2 with Tomcat 下調(diào)試通過。

      附錄1:

       

      Filter 源代碼:

      0 /*

      1 * JSPEncoding.java

      2 *

      3 * Created on 2003年12月17日, 下午9:45

      4 */

      5

      6 package action;

      7

      8 import java.io.*;

      9 import java.net.*;

      10 import java.util.*;

      11 import java.text.*;

      12 import javax.servlet.*;

      13 import javax.servlet.http.*;

      14

      15 import javax.servlet.Filter;

      16 import javax.servlet.FilterChain;

      17 import javax.servlet.FilterConfig;

      18 import javax.servlet.ServletContext;

      19 import javax.servlet.ServletException;

      20 import javax.servlet.ServletRequest;

      21 import javax.servlet.ServletResponse;

      22

      23 /**

      24 *

      25 * @author Administrator

      26 * @version

      27 */

      28

      29 public class JSPEncoding implements Filter {

      30

      31 // The filter configuration object we are associated with. If

      32 // this value is null, this filter instance is not currently

      33 // configured.

      34 private FilterConfig filterConfig = null;

      35 // default to UTF-8

      36 private String targetEncoding = "UTF-8";

      37 public JSPEncoding() {

      38 }

      39

      40 private void doBeforeProcessing(ServletRequest request, ServletResponse response)

      41 throws IOException, ServletException {

      42 if (debug) log("JSPEncoding:DoBeforeProcessing");

      43 }

      44

      45 private void doAfterProcessing(ServletRequest request, ServletResponse response)

      46 throws IOExce1ption, ServletException {

      47 if (debug) log("JSPEncoding:DoAfterProcessing");

      48 }

      49

      50 /**

      51 *

      52 * @param request The servlet request we are processing

      53 * @param result The servlet response we are creating

      54 * @param chain The filter chain we are processing

      55 *

      56 * @exception IOException if an input/output error occurs

      57 * @exception ServletException if a servlet error occurs

      58 */

      59 public void doFilter(ServletRequest request, ServletResponse response,

      60 FilterChain chain)

      61 throws IOException, ServletException {

      62

      63 if (debug) log("JSPEncoding:doFilter()");

      64

      65 doBeforeProcessing(request, response);

      66

      67 HttpServletRequest srequest = (HttpServletRequest)request;

      68 srequest.setCharacterEncoding(targetEncoding);

      69 HttpServletResponse sresponse=(HttpServletResponse)response;

      70 sresponse.addHeader("charset", targetEncoding);

      71 try {

      72 chain.doFilter(srequest, sresponse);

      73 }

      74 catch(Throwable t) {

      75 t.printStackTrace();

      76 }

      77

      78 doAfterProcessing(request, response);

      79

      80 }

      81

      82

      83 /**

      84 * Return the1 filter configuration object for this filter.

      85 */

      86 public FilterConfig getFilterConfig() {

      87 return (this.filterConfig);

      88 }

      89

      90

      91 /**

      92 * Set the filter configuration object for this filter.

      93 *

      94 * @param filterConfig The filter configuration object

      95 */

      96 public void setFilterConfig(FilterConfig filterConfig) {

      97

      98 this.filterConfig = filterConfig;

      99 }

      100

      101 /**

      102 * Destroy method for this filter

      103 *

      104 */

      105 public void destroy() {

      106 filterConfig = null;

      107 targetEncoding = null;

      108 }

      109

      110

      111 /**

      112 * Init method for this filter

      113 *

      114 */

      115 public void init(FilterConfig config) {

      116

      117 this.filterConfig = config;

      118 this.targetEncoding = config.getInitParameter("encoding");

      119 if (config != null) {

      120 if (debug) {

      121 log("JSPEncoding:Initializing filter");

      122 }

      123 }

      124 }

      125

      126 /**

      127 * Return a String representation of this object.

      128 */

      129 public String toString() {

      130

      131 if (filterConfig == null) return ("JSPEncoding()");

      132 StringBuffer sb = new StringBuffer("JSPEncoding(1");

      133 sb.append(filterConfig);

      134 sb.append(")");

      135 return (sb.toString());

      136

      137 }

      138

      139

      140

      141

      142

      143 public void log(String msg) {

      144 filterConfig.getServletContext().log(msg);

      145 }

      146

      147 private static final boolean debug = true;

      148 }

      附錄2 通用字符串重構

      /**

      *@param pValue is raw data

      *@pEncoding is target data Encode

      */

      public String convert(String pValue, String pEncoding)

      throws IOException

      {

      byte bytes[] = getBytes(pValue);

      return convert(bytes, pEncoding);

      byte[] getBytes(String pValue)

      {

      byte bytes[] = new byte[pValue.length()];

      for(int i = 0; i < bytes.length; i++)

      bytes[i] = (byte)pValue.charAt(i);

      return bytes;

      }

      public String convert(byte pValue[], String pEncoding)

      throws IOException

      {

      ByteArrayInputStream bais = new ByteArrayInputStream(pValue);

      InputStreamReader isr = new InputStreamReader(bais, pEncoding);

      StringBuffer sb = new StringBuffer();

      for(int c = isr.read(); c != -1; c = isr.read())

      sb.append((char)c);

      return sb.toString();

      }

      附錄3

      Servlet 2.3 Filter 的在web.xml中的表示

      WEB-INF/web.xml

      <filter>

      <filter-name>action.JSPEncoding</filter-name>

      <filter-class>action.JSPEncoding</filter-class>

      <init-param>

      <param-name>encoding</param-name>

      <param-value>UTF-8</param-value>

      </init-param>

      </filter>

      <filter-mapping>

      <filter-name>action.JSPEncoding</filter-name>

      <url-pattern>/*</url-pattern>

      </filter-mapping>



        本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內(nèi)容,請點擊一鍵舉報。
        轉(zhuǎn)藏 分享 獻花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多