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,这是强制性的,目前几乎所有的能处理中文的应用程序
都支持 GB2312。GB2312 包括了一二级汉字和 9区符号,高位从 0xa1 到0xfe,低位也是从 0xa1 到
0xfe,其中,汉字的编码范围为 0xb0a1 到0xf7fe。
另外有一种编码,叫做 GBK,但这是一份规范,不是强制的。GBK 提供了 20902 个汉字,它兼容
GB2312,编码范围为 0x8140 到0xfefe。GBK 中的所有字符都可以一一映射到 Unicode 2.0。
在不久的将来,中国会颁布另一种标准:GB18030-2000(GBK2K)。它收录了藏、蒙等少数民族
的字型,从根本上解决了字位不足的问题。注意:它不再是定长的。其二字节部份与 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 与cp1392、1392 相同,目前支持的 JDK 很少 在实际编程时,接触得比较多的是
GB2312(GBK)和 ISO8859-1。
为什么会有“?”号
上文说过,异种语言之间的转换是通过 Unicode 来完成的。假设有两种不同的语言 A和B,转换
的步骤为:先把 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 文件的解释和编译过程,并
跟踪其中的中文变化。
1、JSP/Servlet 引擎提供的 JSP 转换工具(jspc)搜索 JSP 文件中用<%@ page contentType
="text/html; charset=<Jsp-charset>"%>中指定的 charset。如果在 JSP 文件中未指定<Jsp-
charset>,则取 JVM 中的默认设置 file.encoding,一般情况下,这个值是 ISO8859-1;
2、jspc 用相当于“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 l'interface ou les textes ? Ou savez-vous comment améliorer l'interface utilisateur de StudyLib ? N'hésitez pas à envoyer vos suggestions. C'est très important pour nous!