request.Dispatecher disp=request.getRequestDispatcher("servlet

request.Dispatecher disp=request.getRequestDispatcher("servlet")
dis.forward(request,response)
request.setAttribute()
/// 中文乱码解决方案
首先在 server.xml 中添加 URIEncoding="GBK",如 CSDN 上所说。
MyEclipse 生成的 JSP 页面的"pageEncoding"改成 GBK
如果表单的 method get 的话,可以直接使用 request.getParameter("")得没有乱码的中文。
如果表单的 method post 的话,可以通过添"request.setCharacterEncoding("GBK");"语句,
随后使用 request.getParameter("");得没有乱码的中文。
世界上的各地区都有本地的语言。地区差异直接导致了语言环境的差异。在开发一个国际化程序的
过程中,处理语言问题就显得很重要了。
这是一个世界范围内都存在的问题,所以Java 提供了世界性的解决方法。本文描述的方法是
用于处理中文的,但是,推而广之,对于处理世界上其它国家和地区的语言同样适用。
汉字是双字节的。所谓双字节是指一个双字要占用两个 BYTE 的位置(即 16 位),分别称为高
位和低位。中国规定的汉字编码GB2312这是强制性的,目前几乎所有的能处理中文的应用程序
都支持 GB2312GB2312 包括了一二级汉字和 9区符号,高位从 0xa1 0xfe,低位也是0xa1
0xfe,其中,汉字的编码范围0xb0a1 0xf7fe
另外有一种编码,叫做 GBK,但这是一份规范,不是强制的。GBK 提供了 20902 个汉字,它兼容
GB2312,编码范围为 0x8140 0xfefeGBK 中的所有字符都可以一一映射到 Unicode 2.0
在不久的将来,中国会颁布另一种标准:GB18030-2000GBK2K)。它收录了藏、蒙等少数民族
的字型,从根本上解决了字位不足的问题。注意:它不再是定长的。其二字节部份与 GBK 容,四
字节部分是扩充的字符、字形。它的首字节和第三字节从 0x81 0xfe,二字节和第四字节从 0x30
0x39
本文不打算介绍 Unicode,有兴趣的可以浏览“http://www.unicode.org/”查看更多的信息。
Unicode 有一个特性:它包括了世界上所有的字符字形。所以,各个地区的语言都可以建立
Unicode 的映射关系,而 Java 是利用了这一点以达到异种语言之间的转换
JDK 中,与中文相关的编码有
1 JDK 中与中文相关的编码列表
编码名称说明 ASCII7 位,与 ascii7 相同 ISO8859-18-位,与 8859_1,ISO-8859-1,ISO_8859-
1,latin1...相同 GB2312-8016 ,与 gb2312,gb2312-1980,EUC_CN,euccn,1381,Cp1381, 1383,
Cp1383, ISO2022CN,ISO2022CN_GB...等相GBK MS936 相同,注意:区分大小UTF8 UTF-8
相同 GB18030 cp13921392 相同,目前支持的 JDK 很少 在实际编程时,接触得比较多的是
GB2312GBK)和 ISO8859-1
为什么会有?”号
上文说过,异种语言之间的转换是通过 Unicode 来完成的。假设有两种不同的语AB,转换
的步骤为:先A化为 Unicode再把 Unicode 转化为 B
举例说明。GB2312 中有一个汉字“李”,其编码为“C0EE”,欲转化ISO8859-1 码。步
骤为:先把“李”字转化为 Unicode,得到“674E”,再把“674E”转化ISO8859-1 字符。当然,
这个映射不会成功,因为 ISO8859-1 中根本就没有与“674E”对应的字符。
当映射不成功时,问题就发生了!当从某语言向 Unicode 转化时,如果在某语言中没有该字
符,得到的将Unicode 的代码“\uffffd”(“\u”表示是 Unicode 编码,)。而从 Unicode 向某
语言转化时,如果某语言没有对应的字符,则得到的是“0x3f”(“?”)。这就是“?”的由来。
例如:把字符流 buf =0x80 0x40 0xb0 0xa1”进new String(buf, "gb2312")操作,得
的结果是“\ufffd\u554a”,再 println 出来,得到的结果将是“?啊”,因为“0x80 0x40”是 GBK
中的字符,在 GB2312 中没有。
再如,把字符串 String="\u00d6\u00ec\u00e9\u0046\u00bb\u00f9"进行 new String
(buf.getBytes("GBK"))操作,得到的结果是“3fa8aca8a6463fa8b4”,其中,\u00d6”在
GBK”中没有对应的字符,得到“3f”,\u00ec”对应着“a8ac”,\u00e9”对应着
a8a6”,“0046”对应着“46”(因为这ASCII 字符),“\u00bb”没找到,得到3f”,最
后,“\u00f9对应着“a8b4”。把这个字符串 println 一下,得到的结果是“?ìéF?ù”。看
没?这里并不全是问号,因为 GBK Unicode 映射的内容中除了汉字外还有字符,本例就是最好的
明证。
所以,在汉字转码时,如果发生错乱,得到的不一定都是问号噢!不过,错了终究是错了,50
步和 100 步并没有质的差别。
或者会问:如果源字符集中有,而 Unicode 中没有,结果会如何?回答是不知道。因为我手头
没有能做这个测试的源字符集。但有一点是肯定的,那就是源字符集不够规范。在 Java ,如果发
生这种情况,是会抛出异常的。
什么是 UTF
UTF,是 Unicode Text Format 的缩写,意为 Unicode 文本格式。对于 UTF,是这样定义的:
1)如果 Unicode 16 位字符的头 9位是 0,则用一个字节表示,这个字节的首位是“0”,
剩下的 7位与原字符中的后 7相同,如“\u0034”(0000 0000 0011 0100),用34 (0011
0100)表示;(与源 Unicode 符是相同的)
2)如果 Unicode 16 位字符的头 5位是 0,则用 2个字节表示,首字节是110”开头,后
面的 5位与源字符中除去头 5个零后的最高 5位相同;第二个字节以“10”开头,后面6位与源
字符中的低 6相同。如“\u025d”(0000 0010 0101 1101),转化后为“c99d”(1100 1001
1001 1101);
3)如果不符合上述两个规则,则用三个字节表示。第一个字节以1110”开头,后四位为源
字符的高四位;第二个字节以“10”开头,后六位为源字符中间的六位;第三个字节以“10”开
头,后六位为源字符的低六位;如“\u9da7”(1001 1101 1010 0111),转化为“e9b6a7”(1110
1001 1011 0110 1010 0111);
可以这么描JAVA 程序中 Unicode UTF 的关系,虽然不绝对:字符串在内存中运行时,表现
Unicode 代码,而当要保存到文件或其它介质中去时,用的是 UTF。这个转化过程是由 writeUTF
readUTF 来完成的
好了,基础性的论述差不多了,下面进入正题。
先把这个问题想成是一个黑匣子。先看黑匣子的一级表示
input(charsetA)->process(Unicode)->output(charsetB)
简单,这就是一个 IPO 模型,即输入、处理和输出。同样的内容要经过“从 charsetA
unicode 再到 charsetB”的转化。
再看二级表示:
SourceFile(jsp,java)->class->output
在这个图中,可以看出,输入的是 jsp java 源文件,在处理过程中,以 Class 文件为载体
然后输出。再细化到三级表示:
jsp->temp file->class->browser,os console,db
app,servlet->class->browser,os console,db
这个图就更明白了。Jsp 文件先生成中间的 Java 文件,再生成 Class。而 Servlet 和普通 App
则直接编译生Class。然后,Class 再输出到浏览器、控制台或数据库等。
JSP:从源文件到 Class 的过程
Jsp 的源文件是以“.jsp”结尾的文本文件。在本节中,将阐JSP 文件的解释和编译过程,并
跟踪其中的中文变化。
1JSP/Servlet 引擎提供的 JSP 转换工具jspc)搜索 JSP 件中用<%@ page contentType
="text/html; charset=<Jsp-charset>"%>中指定的 charset。如果在 JSP 文件中未指<Jsp-
charset>,则取 JVM 中的默认设file.encoding,一般情况下,这个值是 ISO8859-1
2jspc 相当于“javac encoding <Jsp-charset>”的命令解释 JSP 文件中出现的所有字
符,包括中文字符和 ASCII 字符,然后把这些字符转换Unicode 字符,再转化成 UTF 格式,存
JAVA 文件。ASCII 字符转化为 Unicode 字符时只是简单地在前面加“00”,如“A”,转化为
\u0041”(不需要理由,Unicode 的码表就是这么编的)。然后,经过到 UTF 转换,又变回
41”了!这也就是可以使用普通文本编辑器查看由 JSP 生成的 JAVA 文件的原因;
3、引擎用相当于“javac encoding UNICODE”的命令,把 JAVA 文件编译成 CLASS 文件
先看一下这些过程中中文字符的转换情况。有如下源代码
<%@ page contentType="text/html; charset=gb2312"%>
<html><body>
<%
String a="中文";
out.println(a);
%>
</body></html>
这段代码是UltraEdit for Windows 上编写的。保存后,“中文”两个字的 16 进制编码为
D6 D0 CE C4”(GB2312 编码)。经查表,“中文”两字Unicode 编码为“\u4E2D\u6587,用
UTF 表示就是“E4 B8 AD E6 96 87”。打开引擎生成的JSP 文件转变而成JAVA 文件,发现其中
的“中文”两个字确实被“E4 B8 AD E6 96 87”替代了,再查看由 JAVA 文件编译生成的 CLASS
件,发现结果JAVA 文件中的完全一样。
再看 JSP 中指定CharSet ISO-8859-1 情况。
<%@ page contentType="text/html; charset=ISO-8859-1"%>
<html><body>
<%
String a="中文";
out.println(a);
%>
</body></html>
同样,该文件是用 UltraEdit 编写的,“中文”这两个字也是存GB2312 码“D6 D0 CE
C4”。先模拟一下生成的 JAVA 文件CLASS 文件的过程:jspc ISO-8859-1 来解释“中文”,
把它映射到 Unicode。由于 ISO-8859-1 8位的,且是拉丁语系,其映射规则就是在每个字节前
00”,所以,映射后的 Unicode 编码应为“\u00D6\u00D0\u00CE\u00C4”,转化UTF 后应该是
C3 96 C3 90 C3 8E C3 84”。好,打开文件看一下,JAVA 文件和 CLASS 件中,“中文”果然都
表示为“C3 96 C3 90 C3 8E C3 84”。
如果上述代码中不指定<Jsp-charset>即把第一行写成“<%@ page
contentType="text/html" %>”,JSPC 会使用 file.encoding 的设置来解释 JSP 文件。在 RedHat
6.2 上,其处理结果与指定为 ISO-8859-1 完全相同的。
到现在为止,已经解释了JSP 文件到 CLASS 文件的转变过程中中文字符的映射过程。一句
话:从“JspCharSet Unicode 再到 UTF”。下表总结了这个过程:
2 “中文”从 JSP CLASS 的转化过程
Jsp-CharSetJSP 文件JAVA 文件中 CLASS 文件中 GB2312D6 D0 CE C4(GB2312)
\u4E2D\u6587(Unicode)E4 B8 AD E6 96 87 (UTF)E4 B8 AD E6 96 87 (UTF)ISO-8859-1D6 D0 CE
C4
(GB2312)\u00D6\u00D0\u00CE\u00C4 (Unicode)C3 96 C3 90 C3 8E C3 84 (UTF)C3 96 C3 90
C3 8E C3 84 (UTF)无(默认=file.encoding)同 ISO-8859-1 ISO-8859-1 ISO-8859-1
下节先讨Servlet JAVA 件到 CLASS 文件的转化过程,然后再解释从 CLASS 文件如何输
到客户端。之所以这样安排,是因为 JSP Servlet 在输出时处理方法是一样的。
Servlet从源文件到 Class 的过程
Servlet 文件是以“.java”结尾的文本文件。本节将讨论 Servlet 的编译过程并跟踪其中的
中文变化。
用“javac”编译 Servlet 源文件。javac 可以带“-encoding <Compile-charset>”参数,意思
是“用< Compile-charset >中指定的编码来解释 Serlvet 源文件”。
源文件在编译时,用<Compile-charset>来解释所有字符,包括中文字符和 ASCII 符。然后把
字符常量转变Unicode 字符,最后,把 Unicode 转变UTF
Servlet 中,还有一个地方设置输出流的 CharSet。通常在输出结果前,调用
HttpServletResponse setContentType 方法来达到与在 JSP 中设置<Jsp-charset>一样的效果,
之为<Servlet-charset>
注意,文中一共提到了三个变量:<Jsp-charset><Compile-charset><Servlet-charset>
其中,JSP 文件只与<Jsp-charset>有关,而<Compile-charset><Servlet-charset>只与 Servlet
有关。
看下例:
import javax.servlet.*;
import javax.servlet.http.*;
class testServlet extends HttpServlet
{
public void doGet(HttpServletRequest req,HttpServletResponse resp)
throws ServletException,java.io.IOException
{
resp.setContentType("text/html; charset=GB2312");
java.io.PrintWriter out=resp.getWriter();
out.println("<html>");
out.println("#中文#");
out.println("</html>");
}
}
该文件也是UltraEdit for Windows 编写的,其中的“中文”两个字保存为“D6 D0 CE C4
GB2312 编码)。
开始编译。下表是<Compile-charset>不同时,CLASS 文件中“中文”两字的十六进制码。在编
译过程中,<Servlet-charset>不起任何作用。<Servlet-charset>只对 CLASS 文件的输出产生
响,实际上是<Servlet-charset><Compile-charset>一起,达到JSP 文件中的<Jsp-charset>
同的效果,因为<Jsp-charset>对编译和 CLASS 文件的输出都会产生影响。
3 “中文”从 Servlet 源文件到 Class 的转变过程
Compile-charsetServlet 源文件Class 文件中等效的 Unicode GB2312D6 D0 CE C4
(GB2312)E4 B8 AD E6 96 87 (UTF)\u4E2D\u6587 (Unicode 中=“中文”)ISO-8859-1D6 D0 CE
C4
(GB2312)C3 96 C3 90 C3 8E C3 84 (UTF)\u00D6 \u00D0 \u00CE \u00C4 (D6 D0 CE C4 前面各
加了一个 00)(默认)D6 D0 CE C4 (GB2312)ISO-8859-1 ISO-8859-1
普通 Java 程序的编译过程与 Servlet 完全一样。
CLASS 文件中的中文表示法是不是昭然若揭了OK,接下来看CLASS 又是怎样输出中文的呢?
Class:输出字符串
上文说过,字符串在内存中表现为 Unicode 编码。至于这Unicode 码表示了什么,那要看
它是从哪种字符集映射过来的,也就是说要看它的祖先。这好比在托运行李时,外观都是纸箱子,
里面装了什么就要看寄邮件的人实际邮了什么东西。
看看上面的例子,如果给一Unicode 码“00D6 00D0 00CE 00C4”,如果不作转换,直接用
Unicode 码表来对照它时,是四个字符(而且是特殊字符);假如把它与“ISO8859-1进行映射,
则直接去掉前面的“00即可得到“D6 D0 CE C4”,这ASCII 码表中的四个字符;而假如把它当
GB2312 来进行映射,得到的结果很可能是一大堆乱码,因为GB2312 有可能没有(也有可能
有)字符与 00D6 等字符对应(如果对应不上,将得到 0x3f,也就是问号,如果对应上了,由于
00D6 等字符太靠前,估计也是一些特殊符号,真正的汉字在 Unicode 中的编码从 4E00 开始)。
各位看到了,同样的 Unicode 字符,可以解释成不同的样子。当然,这其中有一种是我们期望
的结果。以上例而论,“D6 D0 CE C4”应该是我们所想要的,当把“D6 D0 CE C4”输出到 IE
时,用“简体中文”方式查看,就能看到清楚的“中文”两个字了。(当然了,如果你一定要用
“西欧字符”来看,那也没办法,你将得不到任何有何时何地的东西)为什么呢?因为“00D6 00D0
00CE 00C4”本来就是由 ISO8859-1 转化过去的。
给出如下结论:
Class 出字符串前,会Unicode 字符串按照某一种内码重新生成字节流,然后把字节
流输入,相当于进行了一步“String.getBytes(???)”操作。???代表某一种字符集。
如果是 Servlet,那么,这种内码就是在 HttpServletResponse.setContentType()方法中指定
的内码,也就是上文定义的<Servlet-charset>。
如果是 JSP,那么,这种内码就是在%@ page contentType=""%>中指定的内码,也就是上
定义的<Jsp-charset>。
如果是 Java 程序,那么,这种内码就是 file.encoding 指定的内码,默认为 ISO8859-1
当输出对象是浏览器时
以流行的浏览器 IE 为例。IE 持多种内码。假如 IE 接收到了一个字节流D6 D0 CE C4”,你
可以尝试用各种内码去查看。你会发现用“简体中文”时能得到正确的结果。因为“D6 D0 CE C4
本来就是简体中文中“中文”两个字的编码。
OK,完整地看一遍。
JSP:源文件为 GB2312 格式的文本文件,JSP 源文件中有“中文”这两个汉字
如果指定了Jsp-charset>为 GB2312转化过程如下表。
4 Jsp-charset = GB2312 时的变化过程
序号步骤说明结果 1编写 JSP 文件,且存为 GB2312 格式 D6 D0 CE C4
1 / 9 100%
La catégorie de ce document est-elle correcte?
Merci pour votre participation!

Faire une suggestion

Avez-vous trouvé des erreurs dans linterface ou les textes ? Ou savez-vous comment améliorer linterface utilisateur de StudyLib ? Nhésitez pas à envoyer vos suggestions. Cest très important pour nous !