为了让使用Java语言编写的程序能在各种语言的平台下运行,Java在其内部使用Unicode字符集来表示字符,这样就存在Unicode字符集和本地字符集进行转换的过程。当在Java中读取字符数据的时候,需要将本地字符集编码的数据转换为Unicode编码,而在输出字符数据的时候,则需要将Unicode编码转换为本地字符集编码。
例如,在中文系统下,从控制台读取一个字符“中”,实际上读取的是“中”的GBK编码0xD6D0,在Java语言中要将GBK编码转换为Unicode编码0x4E2D,此时,在内存中,字符“中”对应的数值就是0x4E2D,当我们向控制台输出字符时,Java语言将Unicode编码再转换为GBK编码,输出到控制台,中文系统再根据GBK字符集画出相应的字符。
从上述过程来看,读取和写入的过程是可逆的,那么理应不会出现中文乱码问题。然而,实际应用的情形,比上述过程要复杂得多。在Web应用中,通常都包括了浏览器、Web服务器、Web应用程序和数据库等部分,每一部分都有可能使用不同的字符集,从而导致字符数据在各种不同的字符集之间转换时,出现乱码的问题。
在Java语言中,不同字符集编码的转换,都是通过Unicode编码作为中介来完成的。例如,GBK编码的字符“中”要转换为ISO-8859-1(同ISO8859-1)编码,其过程如下:
(1)因为在Java中的字符,都是用Unicode来表示的,所以GBK编码的字符“中”要转换为Unicode表示:0xD6D0->0x4E2D。
(2)将字符“中”的Unicode编码转换为ISO-8859-1编码,因为Unicode编码0x4E2D在ISO-8859-1中没有对应的编码,于是得到0x3f,也就是字符“?”。
下面的代码演示了这一过程:
//GBK编码的字符“中”转换为Unicode编码表示
String str="中";
//将字符“中”的Unicode编码转换为ISO-8859-1编码
byte[] b=str.getBytes("ISO-8859-1");
for(int i=0;i<b.length;i++)
{
//输出转换后的二进制代码。
System.out.print(b[i]);
}
当从Unicode编码向某个字符集转换时,如果在该字符集中没有对应的编码,则得到0x3f(即问号字符?)。这就是为什么有时候我们输入的是中文,在输出时却变成了问号。
从其他字符集向Unicode编码转换时,如果这个二进制数在该字符集中没有标识任何的字符,则得到的结果是0xfffd。例如一个GBK的编码值0x8140,从GB2312向Unicode转换,然而由于0x8140不在GB2312字符集的编码范围(0xa1a1-0xfefe),当然也就没有对应任何的字符,所以转换后会得到0xfffd。下面的代码演示了这一过程。
//构造一个二进制数据。
byte[] buf={(byte)0x81,(byte)0x40,(byte)0xb0,(byte)0xa1};
//将二进制数据按照GB2312向Unicode编码转换。
String str=new String(buf,"GB2312");
for(int i=0;i<str.length();i++)
{
//取出字符串中的每个Unicode编码的字符。
char ch=str.charAt(i);
//将该字符对应的Unicode编码以十六进制的形式输出。
System.out.print(Integer.toHexString((int)ch));
System.out.print("--");
//输出该字符。
System.out.println(ch);
}
在输出字符和字符串的时候,会从Unicode编码向中文系统默认的编码GBK转换,由于Unicode编码0xfffd在GBK字符集中没有对应的编码,于是得到0x3f,输出字符“?”。最后输出的结果如下:
fffd--?
40--@
554a--啊
从上述所知,由于存在着多种不同的字符集,在各种字符集之间进行转换,就有可能出现乱码,同样是中文字符集GB2312和GBK,由于编码范围的不同,某些字符在转换时也会出现乱码。
在一个使用了数据库的Web应用程序中,乱码可能会在多个环节产生。由于浏览器会根据本地系统默认的字符集来提交数据,而Web容器默认采用的是ISO-8859-1的编码方式解析POST数据,在浏览器提交中文数据后,Web容器会按照ISO-8859-1字符集来解码数据,在这一环节可能会导致乱码的产生。由于大多数数据库的JDBC驱动程序默认采用ISO-8859-1的编码方式在Java程序和数据库之间传递数据,我们的程序在向数据库中存储包含中文的数据时,JDBC驱动首先将程序内部的Unicode编码格式的数据转化为ISO-8859-1的格式,然后传递到数据库中,在这一环节可能会导致乱码的产生。目前流行的关系型数据库系统都支持数据库编码,也就是说在创建数据库时可以指定它自己的字符集设置,数据库的数据以指定的编码形式存储。当JDBC驱动向数据库中保存数据时,有可能还会发生字符集的转换。正是由于在Web应用程序运行过程中,输入的中文字符需要在不同的字符集之间来回转换,也就导致了中文乱码问题的频繁出现。
图17-1描述了在Web应用的请求响应过程中,发生的字符编码转换过程,其中浏览器是IE 6.0,Web容器的是Tomcat 6.0.16。
从图17-1描述的过程中可以看到,如果在Web应用程序中不指定任何的字符集,从浏览器端传来的中文字符,输出回浏览器时,可以正常显示(以简体中文的方式查看网页)。然而,事情并没有这么简单,在Servlet/JSP中,可能存在着直接写入的或从其他来源读取的中文字符,如果这些字符对应的Unicode码是从GB2312编码转换而来,那么以ISO-8859-1编码方式输出,这些字符将不能正常显示。所以对于中文的处理,应该在图17-1②和⑤的位置明确指定使用GB2312或GBK字符集。
图17-1 在Web请求响应过程中,中文字符编码的转换过程
- JavaWeb使用Filter进行字符编码过滤 预防web服务中文乱码
JavaWeb使用Filter进行字符编码过滤 预防web服务中文乱码 准备条件:一个创建好的 JavaWeb 项目 步骤: 1.创建一个类并实现 Filter 接口 import javax.ser ...
- TimesTen数据库表中显示中文乱码的真正原因
上一篇博客TimesTen中文乱码问题(其实是cmd.exe中文乱码)的内容可能不对,也许只是个巧合?不得而知了.因为我今天重装系统了,把win10换成了win7(64bit).又安装了timeste ...
- 1.JAVA WEB 笔记中文乱码
JAVA WEB 乱码问题解析 乱码原因 在Java Web开发过程中,经常遇到乱码的问题,造成乱码的原因,概括起来就是对字符编码和解码的方式不匹配. 既然乱码的原因是字符编码与解码的方式不匹配,那么 ...
- myql数据库在cmd下,中文乱码的问题原因
使用navicat把数据导入数据库,这些数据都是中文,导入成功,显式也正常,但是在mysql cmd下都是乱码.检查了我的mysql配置,字符编码都是utf8,包括navicat连接时候也设置过是ut ...
- 如何解决WEB应用中文乱码问题
最容易出现乱码的场景是浏览器向服务器发送请求的过程,解决的策略就是强制为请求和响应设置编码格式. 一.POST 方式请求乱码 1. 在每个 Controller 中单独处理 request.setCh ...
- 第三章 深入分析Java Web的中文乱码问题(待续)
几种常见的编码格式 在Java中需要编码的场景 在Java中如何编解码 在Java Web中涉及的编解码 在JS中的编码问题 常见问题分析 一种繁简转换的实现方式
- 解决Ubuntu下在firefox中打开Microsoft Outlook Web Access中文乱码
Edit---Preference--Content--Languages--Choose...---Select a langue to add... 添加中文
- Web | 解决中文乱码
设定文件的编码格式在head中添加 <head> <meta http-equiv="Content-Type" content="text/html; ...
- JMeter学习笔记(十八)——返回的响应数据出现中文乱码_解决方案
一.问题描述 使用jmeter过程中遇到了请求返回的响应数据出现中文乱码 二.原因分析 当没有对响应数据or响应页面设置支持解析中文的编码时,JMeter则会以默认的ISO-8859-1格式解析,而其 ...
随机推荐
- Java开源内容管理CMS系统J4CMS集成到JTM
JTM是Win32下绿色免费的JDK + Tomcat + MySQL环境集成工具. 通过JTM用户无需对JDK.Tomcat.MySQL进行不论什么安装和配置就可以迅速搭建支持JSP + MySQL ...
- HDUOJ ---悼念512汶川大地震遇难同胞——来生一起走
悼念512汶川大地震遇难同胞——来生一起走 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Ot ...
- 使用Apache FtpServer
Java大法一统天下.遇到任何问题,先查一下Java中的解决方案. 地球上的许多事情,在Java中都能找到完美的解决方案. FtpServer是apache MINA项目的一个子项目,它实现了一个ft ...
- Windows命令-route
Windows route命令 添加一条永久网关:route add 0.0.0.0 mask 0.0.0.0 192.168.2.1 -p例如: route -p add 192.168.0.0 m ...
- Find and Grep
find 1.格式 Usage: find [-H] [-L] [-P] [-Olevel] [-D help|tree|search|stat|rates|opt|exec] [path...] [ ...
- AME_IExpense费用报表通过AME审批简单例子(案例)
2014-05-30 Created By BaoXinjian
- js 倒计时 (时分秒版本)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- JDK1.5新特性,语言篇
Java 1.5版本,就是Java 2 Standard Edition 5,Version 1.5,简称Java 5.版本代号Tiger. 一. 泛型(Generics) C++通过模板技术可以指定 ...
- Android Gradle 引用本地 AAR 的几种方式
折衷方案: 1.方式2 - 不完美解决办法2 2.再使用"自定义Gradle代码"来减轻重复设置的问题. 自定义Gradle代码如下: repositories { flatDir ...
- Hypothesis Testing
Hypothesis Testing What's Hypothesis Testing(假设检验) Hypothesis testing is the statistical assessment ...