zoukankan      html  css  js  c++  java
  • Java 关于中文乱码处理的经验总结【转载】

    为什么说乱码是中国程序员无法避免的话题呢?这个首先要从编码机制上说起,大家都是中文和英文的编码格式不是一样,解码也是不一样的!如果中国的程序员不会遇到乱码,那么只有使用汉语编程。汉语编程是怎么回事我也不大清楚,应该是前年吧,我一朋友给我介绍汉语编程,怎么不错不错?当时因为学习忙没去关注这个,等我闲了,那个朋友不弄这个,问他他也不说不大清楚,最后自己对这个学习也不了了之了。
        今天我写这个不是讲解中英文之间的差距,解码等,我是将我在这几年工作遇到各种各样的乱码的解决方法,总结一样,也希望大家能把自己晕倒解决乱码的方法都说出来,咱们弄一个解决乱码的“葵花宝典”。

    对于Java由于默认的编码方式是 UNICODE,所以用中文也易出问题,常见的解决是
    String s2 = new String(s1.getBytes(“ISO-8859-1”),”GBK”);

    1、utf8解决JSP中文乱码问题
    一般说来在每个页面的开始处,加入:

    <%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"%>

    <%
    request.setCharacterEncoding("UTF-8");
    %>

    charset=UTF-8  的作用是指定JSP向客户端输出的编码方式为“UTF-8”

    pageEncoding="UTF-8"  为了让JSP引擎能正确地解码含有中文字符的JSP页面,这在LINUX中很有效

    request.setCharacterEncoding("UTF-8"); 是对请求进行了中文编码

    有时,这样仍不能解决问题,还需要这样处理一下:

    String msg = request.getParameter("message");
    String str=new String(msg.getBytes("ISO-8859-1"),"UTF-8");
    out.println(st);

    2、Tomcat 5.5 中文乱码

    ) 只要把%TOMCAT安装目录%/   webappsservlets-examplesWEB-INFclassesfilters SetCharacterEncodingFilter.class文件拷到你的webapp目录/filters下,如果没有filters目录,就创建一个。  
      2)在你的web.xml里加入如下几行:   <filter>  
      <filter-name>Set   Character   Encoding</filter-name>  
      <filter-class>filters.SetCharacterEncodingFilter</filter-class>  
      <init-param>  
      <param-name>encoding</param-name>  
      <param-value>GBK</param-value>  
      </init-param>  
      </filter>  
          <filter-mapping>  
      <filter-name>Set   Character   Encoding</filter-name>  
      <url-pattern>/*</url-pattern>  
      </filter-mapping>  
      3)完成.  
      2   get方式的解决办法  
      1)   打开tomcat的server.xml文件,找到区块,加入如下一行:  
      URIEncoding=”GBK”  
      完整的应如下:  
      <Connector    
      port="80"   maxThreads="150"   minSpareThreads="25"   maxSpareThreads="75"  
      enableLookups="false"   redirectPort="8443"   acceptCount="100"  
      debug="0"   connectionTimeout="20000"    
      disableUploadTimeout="true"    
      URIEncoding="GBK"  
      />     
      2)重启tomcat,一切OK。

    3、xmlHttpRequest中文问题

    页面jsp用的GBK编码

    代码
    <%@ page contentType="text/html; charset=GBK"%>

    javascript部分

    代码
    function addFracasReport() {  
        var url="controler?actionId=0_06_03_01&actionFlag=0010";  
        var urlmsg="&reportId="+fracasReport1.textReportId.value;  //故障报告表编号  
        var xmlHttp=Common.createXMLHttpRequest();  
        xmlHttp.onreadystatechange = Common.getReadyStateHandler(xmlHttp, eval("turnAnalyPage"));  
        xmlHttp.open("POST",url,true);  
        xmlHttp.setRequestHeader( " Content-Type " , " application/x-www-form-urlencoded);  
        xmlHttp.send(urlmsg);  
    }

    后台java中获得的reportId是乱码,不知道该怎么转,主要是不知道xmlHttp.send(urlmsg);以后是什么编码?在后面用java来转,试了几种,都没有成功,其中有:

    代码
    public static String UTF_8ToGBK(String str) {  
            try {  
                return new String(str.getBytes("UTF-8"), "GBK");  
            } catch (Exception ex) {  
                return null;  
            }  
        }  
        public static String UTF8ToGBK(String str) {  
            try {  
                return new String(str.getBytes("UTF-16BE"), "GBK");  
            } catch (Exception ex) {  
                return null;  
            }  
        }  
        public static String GBK(String str) {  
            try {  
                return new String(str.getBytes("GBK"),"GBK");  
            } catch (Exception ex) {  
                return null;  
            }  
        }  
             public static String getStr(String str) {  
            try {  
                String temp_p = str;  
                String temp = new String(temp_p.getBytes("ISO8859_1"), "GBK");  
                temp = sqlStrchop(temp);  
                return temp;  
            } catch (Exception e) {  
                return null;  
            }  
        }

    4、JDBC ODBC Bridge的Bug及其解决方法

    在编写一数据库管理程序时,发现JDBC-ODBC Bridge存在不易发现的Bug。在向数据表插入数据时,如果为英文字符,存储内容完全正确,如果存入中文字符,部分数据库只能存储前七八个中文字符,其他内容被截去,导致存储内容的不完整(有些数据库不存在这个问题,如Sybase SQL Anywhere 5.0。JDBC-ODBC Bridge还存在无法建表的Bug)。

    对于广大需要存储中文信息的Java程序员来说,这可是一个不好的消息。要么改用其他语言编程,要么选择其他价格昂贵的数据库产品。“一次编写,到处运行”的目标,也大打折扣。能不能采用变通的方法,将中文信息进行处理后再存储来解决这个问题呢?答案是肯定的。

    解决问题的具体思路、方法
    Java采用Unicode码编码方式,中英文字符均采用16bit存储。既然存储英文信息是正确的,根据一定规则,将中文信息转换成英文信息后存储,自然不会出现截尾现象。读取信息时再进行逆向操作,将英文信息还原成中文信息即可。由GB2312编码规则可知,汉字一般为二个高位为1的ASCII码,在转换时将一个汉字的二个高位1去掉,还原时再将二个高位1加上。为了处理含有英文字符的中文字串,对英文字符则需要加上一个Byte 0标记。以下提供的两个公用静态方法,可加入任何一个类中使用。

    将中英文字串转换成纯英文字串
    public static String toTureAsciiStr(String str){

    StringBuffer sb = new StringBuffer();

    byte[] bt = str.getBytes();

    for(int i =0 ;i〈bt.length;i++){

    if(bt[i]〈0){

    //是汉字去高位1

    sb.append((char)(bt[i]&&0x7f));

    }else{//是英文字符 补0作记录

    sb.append((char)0);

    sb.append((char)bt[i]);

    }

    }

    return sb.toString();

    }

    将经转换的字串还原
    public static String unToTrueAsciiStr(String str){

    byte[] bt = str.getBytes();

    int i,l=0,length = bt.length,j=0;

    for(i = 0;i〈length;i++){

    if(bt[i] == 0){

    l++;

    }

    }

    byte []bt2 = new byte[length-l];

    for(i =0 ;i〈length;i++){

    if(bt[i] == 0){

    i++;

    bt2[j] = bt[i];

    }else{

    bt2[j] = (byte)(bt[i]|0×80);

    }

    j++;

    }

    String tt = new String(bt2);

    return tt;

    }

    上例在实际编程中效果很好,只是存储的中文信息需要经过同样处理,才能被其他系统使用。而且如果中文字串出现英文字符,实际上增加了额外的存储空间。

    5、Solaris下Servlet编程的中文问题及解决办法
    在使用Java开发Internet上的一个应用系统时,发现在Windows下调试完全正常的Servlet,上传到Solaris 服务器上,运行却出现故障——返回的网页不能显示中文,应为中文的信息全为乱码;用中文信息做关键字,不能正确检索数据库。后来采用加入检查代码等方法探知故障原因如下:

    显示乱码主要是因为通过类 HttpServletResponse提供的方法setContentType 无法改变返回给客户的数据的编码方式,正确的编码方式应为GB2312或者GBK,而事实上为缺省的ISO8859-1。无法检索中文信息则是因为,客户提交的中文信息经浏览器编码到达服务器后,Servlet无法将其正确解码。

    举例说明显示乱码解决方法
    Servlet 一般通常做法如下:

    public class ZldTestServlet extends HttpServlet {

    public void doGet (HttpServletRequest request,HttpServletResponse response)throws ServletException, IOException{

    //在使用 Writer向浏览器返回数据前,设置 content-type header ,在这里设置相应的字符集gb2312

    response.setContentType("text/html;charset=gb2312");

    PrintWriter out = response.getWriter(); //*

    // 正式返回数据

    out.println("〈html〉〈head〉〈title〉Servlet test〈/title〉〈/head〉" );

    out.println("这是一个测试页!");

    out.println("〈/body〉〈/html〉");

    out.close();

    }

    }

    解决页面显示乱码问题,需将*处代码换成如下内容:

    PrintWriter out = new PrintWriter(new OutputStreamWriter(response.getOutputStream(),"gb2312"));

    Solaris中文信息检索问题的解决
    浏览器利用表单向服务器提交信息时,一般采用x-www-form-urlencoded 的MIME格式对数据进行编码。如果使用get方法,参数名称和参数值经编码后附加在URL后,在Java中称作查询串(query string)。

    在Servlet程序中,如果采用ServletRequest的方法getParameter取得参数值,在Solaris环境下,对汉字却不能正确解码。因而无法正确检索数据库。

    在Java 1.2的包——java.net中提供了URLEncode和URLDecode类。类URLEncode提供了按x-www-form-urlencoded格式对给定串进行转换的方法。类URLEncode则提供了逆方法。

    6、Common Mail乱码问题
    common mail是一个小而方便的mail包,他实现了对Java Mail的封装,使用起来十分的方便,但是我在使用他的时候发现,使用纯文本的内容发送,结果是乱码,代码如下:
    public class TestCommonMail {
    public static void main(String[] args) throws EmailException, MessagingException {
    SimpleEmail email = new SimpleEmail();
    email.setCharset("GB2312");
    email.setHostName("smtp.163.com");
    email.setSubject("test");
    email.addTo("test@163.com");
    email.setFrom("test@163.com");
    email.setMsg("我的测试");
    email.setAuthentication("test", "test");
    email.send();
    }
    }

    分析了一下commons mail的源码找到了原因。源码如下:
    public class SimpleEmail extends Email
    {
    public Email setMsg(String msg) throws EmailException, MessagingException
    {
    if (EmailUtils.isEmpty(msg))
    {
    throw new EmailException("Invalid message supplied");
    }

    setContent(msg, TEXT_PLAIN);
    return this;
    }
    }

    Email代码片段
    public void setContent(Object aObject, String aContentType)
    {
    this.content = aObject;
    if (EmailUtils.isEmpty(aContentType))
    {
    this.contentType = null;
    }
    else
    {
    // set the content type
    this.contentType = aContentType;

    // set the charset if the input was properly formed
    String strMarker = "; charset=";
    int charsetPos = aContentType.toLowerCase().indexOf(strMarker);
    if (charsetPos != -1)
    {
    // find the next space (after the marker)
    charsetPos += strMarker.length();
    int intCharsetEnd =
    aContentType.toLowerCase().indexOf(" ", charsetPos);

    if (intCharsetEnd != -1)
    {
    this.charset =
    aContentType.substring(charsetPos, intCharsetEnd);
    }
    else
    {
    this.charset = aContentType.substring(charsetPos);
    }
    }
    }
    }

    email.send();的send方法将调用
    public void buildMimeMessage() throws EmailException
    {
    try
    {
    this.getMailSession();
    this.message = new MimeMessage(this.session);

    if (EmailUtils.isNotEmpty(this.subject))
    {
    if (EmailUtils.isNotEmpty(this.charset))
    {
    this.message.setSubject(this.subject, this.charset);
    }
    else
    {
    this.message.setSubject(this.subject);
    }
    }

    // ========================================================
    // Start of replacement code
    if (this.content != null)
    {
    this.message.setContent(this.content, this.contentType);
    }
    // end of replacement code
    // ========================================================
    else if (this.emailBody != null)
    {
    this.message.setContent(this.emailBody);
    }
    else
    {
    this.message.setContent("", Email.TEXT_PLAIN);
    }

    if (this.fromAddress != null)
    {
    this.message.setFrom(this.fromAddress);
    }
    else
    {
    throw new EmailException("Sender address required");
    }

    if (this.toList.size() + this.ccList.size() + this.bccList.size() == 0)
    {
    throw new EmailException(
    "At least one receiver address required");
    }

    if (this.toList.size() > 0)
    {
    this.message.setRecipients(
    Message.RecipientType.TO,
    this.toInternetAddressArray(this.toList));
    }

    if (this.ccList.size() > 0)
    {
    this.message.setRecipients(
    Message.RecipientType.CC,
    this.toInternetAddressArray(this.ccList));
    }

    if (this.bccList.size() > 0)
    {
    this.message.setRecipients(
    Message.RecipientType.BCC,
    this.toInternetAddressArray(this.bccList));
    }

    if (this.replyList.size() > 0)
    {
    this.message.setReplyTo(
    this.toInternetAddressArray(this.replyList));
    }

    if (this.headers.size() > 0)
    {
    Iterator iterHeaderKeys = this.headers.keySet().iterator();
    while (iterHeaderKeys.hasNext())
    {
    String name = (String) iterHeaderKeys.next();
    String value = (String) headers.get(name);
    this.message.addHeader(name, value);
    }
    }

    if (this.message.getSentDate() == null)
    {
    this.message.setSentDate(getSentDate());
    }

    if (this.popBeforeSmtp)
    {
    Store store = session.getStore("pop3");
    store.connect(this.popHost, this.popUsername, this.popPassword);
    }
    }
    catch (MessagingException me)
    {
    throw new EmailException(me);
    }
    }
    由代码可以知道纯文本方式最终调用了Java Mail的
    message.setContent(this.content, this.contentType);
    content是内容
    contentType是类型,如text/plain,
    (我们可以试试直接用Java mail发邮件,设置文本内容不使用setText方法,也使用setContent("测试", "text/plain")方式,你可以看到内容也是乱码)
    关键就在于text/plain,我们改成text/plain;charset=gb2312,ok乱码解决了。在commons mail我们看SimpleEmail 类中setMsg方法调用的就是 setContent(msg, TEXT_PLAIN);我们只需要将Email类中的常量TEXT_PLAIN修改一下加入 charset=你的字符集 ,重新打包jar,这样就可以了

    7、toad的字符集的设置与oracle的安装
    oracle数据库服务器的安装一般是中文字符集,有时安装在不同的平台下,设置为ISO编码,toad是oracle开发的最好工具,不是我说的,可是中文环境下安装的toad,打开英文字符的oracle时,中文全是乱码。必须进行设置

    环境变量—〉系统变量

      NLS_lANG=SIMPLIFIED CHINESE_CHINA.ZHS16GBK
      或
      NLS_lANG=AMERICAN_AMERICA.WE8ISO8859P1

    AMERICAN_AMERICA.WE8MSWIN1252
    或者

    打开注册表,点击HKEY_LOCAL_MATHINE
    再点击Software,再点击ORACLE
    在点击HOME(ORACLE所在目录)
    在注册表的右半面有NLS_LANG,
    双击它,将你想要的覆盖掉原来的就可以了
    最好记下旧的,以便可以改回来。

    connect sys/chang_on_install
    update props$
    set value$=’ZHS16CGB231280′
    where name=’NLS_CHARACTERSET’;
    commit;
    这样就OK了

    8、如何解決GWT(google web toolkit)中文的問題
    GWT 中文乱码解决方法

    1.把你要显示的中文“测试字符串”输入到一个文件,如:1.txt
    2.进入命令行,进入1.txt所在的目录,敲入以下命令:native2ascii.exe 1.txt 2.txt 回车。这样就生成了另外一个文件2.txt。
    3.2.txt的内容如下:u6d4bu8bd5u5b57u7b26u4e32
    4.然后用上面的编码,在gwt中使用,就可以了.

    9、xmlHttp得到的网页怎么是乱码?
    (1)在服务器端使用WebRequest而不是xmlHttp
    (2) 将

    StreamReader sr = new StreamReader(stream);

    对于简体中文改成:

    StreamReader sr = new StreamReader(stream , Encoding.Default );
    对于utf-8改成:

    StreamReader sr = new StreamReader(stream , Encoding.UTF8 );
    当然,Encoding枚举还有很多其他的成员,对于不同的编码content-type可以有选择的应用

    (3)后来我发现无论是content-type是gb2312还是utf-8,用

    StreamReader sr = new StreamReader(stream , Encoding.Default );

    都可以返回正常的汉字,所以统一的改成Encoding.Default

    ——————————————————————————–

    最后,在服务器端从一个url获得网页的源代码的代码如下:

    /// <summary>
    /// post一个指定的url,获得网页的源代码(用WebRequest实现)
    /// </summary>
    /// <param name="url"></param>
    /// <returns>
    /// 如果请求失败,返回null
    /// 如果请求成功,返回网页的源代码
    /// </returns>
    public static string GetContentFromUrl2( string url )
    {
        //变量定义
        string respstr;

        WebRequest myWebRequest=WebRequest.Create(url);
        //            myWebRequest.PreAuthenticate=true;
        //            NetworkCredential networkCredential=new NetworkCredential( username , password , domain );
        //            myWebRequest.Credentials=networkCredential;

        // Assign the response object of ‘WebRequest’ to a ‘WebResponse’ variable.
        WebResponse myWebResponse=myWebRequest.GetResponse();
        System.IO.Stream stream = myWebResponse.GetResponseStream();
        StreamReader sr = new StreamReader(stream , Encoding.Default );
        //以字符串形式读取数据流
        respstr = sr.ReadToEnd();
        sr.Close();
        return respstr;
    }

  • 相关阅读:
    Java 蓝桥杯 算法训练 貌似化学
    Java 蓝桥杯 算法训练 貌似化学
    Java 蓝桥杯 算法训练 字符串的展开 (JAVA语言实现)
    Java 蓝桥杯 算法训练 字符串的展开 (JAVA语言实现)
    Java 蓝桥杯 算法训练 字符串的展开 (JAVA语言实现)
    Java 蓝桥杯 算法训练 字符串的展开 (JAVA语言实现)
    Java 蓝桥杯 算法训练 字符串的展开 (JAVA语言实现)
    JAVA-蓝桥杯-算法训练-字符串变换
    Ceph:一个开源的 Linux PB 级分布式文件系统
    shell 脚本监控程序是否正在执行, 如果没有执行, 则自动启动该进程
  • 原文地址:https://www.cnblogs.com/sunhan/p/3542154.html
Copyright © 2011-2022 走看看