`
chenshuyi
  • 浏览: 26161 次
文章分类
社区版块
存档分类
最新评论

JSP编码问题浅析

阅读更多

1.各种字符集的意义

Unicode字符集:它是世界上所有字符的统一编码,Unicode字符集包含了世界上所有文字的二进制编码。但是它没有规定字符的存储方式。

UTF-8:它是Unicode字符集的一种实现方式,即Unicode的一种存储方式。

GBK/GB2312:都是中文的的一种字符编码,只不过GBK的表示范围更广。

ISO-8859-1:是ASCII的扩展字符集,包括了基本的英文字符和一些欧洲字符。

所以,如果我们的网页包含汉字的话,只能用UTF-8/GBK/GB2312这三种中的一种。一般来说,UTF-8编码能够更好地实现国际化,因为它是Unicode(Unique Code)的实现方式,可以表示所有字符。

2.如何在各种字符编码间转换

说起字符乱码,还是得怪我们的语言种类太多,每种语言都有自己的字符。一种字符用一种编码方式,中文用GBK/GB2312,英文用ASCII和ISO-8859-1。为了交流的方便,便有了Unicode字符,而Unicode字符又没规定如何存储,于是UTF-8编码方式就出现了。在Java中,如果要在几种字符方式之间转换,可以用getBytes(String charset)方法和new String(byte[] byte, String charset)方法。其中

①String.getBytes(String charset)是将String字符串根据charset编码方式编码。

getBytes方法其实是将某一个字符串中的字符转换成对应字符集中的字节数组。

String str2 = "abcde";
		byte[] strByte2 = str2.getBytes("iso-8859-1");
		
		for(byte b : strByte2)
		{
			System.out.print(b + " ");  //输出:97 98 99 100 101
		}

上图这个例子,将字符串『abcde』转成字节数组就分别是:97 98 99 100 101。

这是一个将字符串专场字节的过程,是一个编码的过程。

②new String(byte[] byte, String charset)是将byte字节数组转换成charset编码方式下的字符串。

比如:

String str = "这是陈树义的博客";
	
		byte[] strByte = str.getBytes("utf-8"); //将字符串用utf-8方式编码
		
		System.out.println(strByte.length); //一共有8个汉字,一个汉字用3个字节表示,一共有24个字节。
		
		String newString = new String(strByte, "utf-8"); //将字节数组用utf-8编码方式还原成数组
		System.out.println(newString);  //输出:"这是陈树义的博客"

③有时候传输数据的时候要求数据必须以ISO-8859-1编码方式传输,这时你可以先将数据以ISO-8859-1方式保存。到达指定页面之后再将数据再转换一次,从而得到指定的字符。在下面这个例子,原本的页面是UTF-8编码的,但是传输的时候要求用ISO-8859-1编码,于是我们先转换成ISO-8859-1表示的字符串,即:

String str = "传输必须用ISO-8859-1编码";
str = new String(str.getBytes("gb2312"), "iso-8859-1");
此时,str字符串就是用iso-8859-1编码方式表示的数据,但是直接输出它将是乱码(因为iso-8859-1没有中文字符)

到了指定页面之后就再转过来,即:

String newStr = new String(str.getBytes("iso-8859-1"), "utf-8");
完整的例子:

String str = "传输必须用ISO-8859-1编码";
		str = new String(str.getBytes("gb2312"), "iso-8859-1");
		
		System.out.println(str);  //输出乱码
		
		String newStr = new String(str.getBytes("iso-8859-1"), "gb2312");
		
		System.out.println(newStr); //输出『传输必须用ISO-8859-1编码』

3.JSP页面中涉及到的编码

JSP页面中设计到的有三个编码,分别是pageEncoding、contentType和meta。

<%@ page language="java" pageEncoding="gb2312"%>   //①

<%@ page contentType="text/html;charset=gb2312"%>	//②

<html>

<head>

<title>JSP的中文处理</title>

<meta http-equiv="Content-Type" content="text/html charset=gb2312">	//③

</head>

<body>

<%out.print("JSP的中文处理");%>

</body>

</html>
在上面的代码中的①、②、③分别就是JSP中的三个编码。

①<%@page pageEncoding="gb2312"%>

pageEncoding表示JSP文件转换成Java类文件时使用的编码。因为JSP文件是通过Tomcat进行解析转换成java文件,在转换成Java文件时就会根据用户设置的编码方式进行编码。即如果你在JSP页面上有中文字符,但是你在pageEncoding声明为ISO-8859-1。那么JSP文件在转成Java文件时就会用ISO-8859-1去编码,而ISO-8859-1中不包含中文字符,所以当我们打开Tomcat目录下对应的缓存文件(在Tomcat的work目录下)时会看到对应的Java文件中的中文字符是乱码。也就是说,这时候在Java文件中就是乱码了,那么这时你即使JSP页面设置正确了,但你在前台得到的数据还是乱码。因此,pageEncoding属性也要设置正确,一般设置成“UTF-8"可以更好地支持国际化。

②<%@ page contentType="text/html;charset=gb2312" %>

contentType指定了服务器发送给客户端时的内容编码。当用户请求数据时,Tomcat会请求并解析响应的class文件,在解析之时就会根据用户设置的contentType来解码,并将解码后的数据发送到客户端显示。这里和pageEncoding是对应的,如果你在pageEncoding中设置是GB2312,而在contentType中设置UTF-8,那么有可能出现出现乱码。因为Class文件是用GB2312编码的,而你解码用UTF-8,可能会导致解码不正确。所以,pageEncoding和contentType最好使用统一编码方式。

③<meta http-equiv="Content-Type" content="text/html;charset=gb2312">

meta标签可以控制浏览器用某种特定的字符集解释页面。

疑问:

①其实现在还不是很清楚JSP文件转换成Java文件,编译成class文件,以及用户请求这些过程涉及的编码问题,对pageEncoding、contentType、meta的理解也停留在一个很浅的水平。有机会请再弄清楚!

4.页面中文乱码

前面已经说过,如果pageEncoding设置错误,那么在Java类文件中就已经是乱码,这时候无论如何都是错误的。但是如果pageEncoding设置正确,那么还出现乱码,那么出现错误的应该就是contentType这个属性了。这个属性指的是JSP页面中使用的字符集(其实与meta好像差不多)。我做过一些测试,如果你将contentType设置成iso-8859-1,那么网页中的中文不能显示。如果设成UTF-8/GBK/GB2312,那么中文可以显示。

5.表单提交数据乱码

表单提交方式有两种方式,一种是GET方式,一种是POST方式。这里只讨论GET方式(请在另文补充POST方式)。

我们在一个页面提交中文数据,到另外一个页面用request.getParameter得到数据。这时候如果直接用request.getParameter得到数据,然后直接输出将会乱码。因为Tomcat在传输数据的时候进行了编码的转换(这涉及到Tomcat的源码内容,请继续补充)。如果要得到正确的数据,请进行编码转换,即做以下操作:

String name = new String(request.getParameter("name").getBytes("iso-8859-1"), "gb2312");
这里的表单提交出现乱码似乎与contentType没有必然的关联,因为contentType是控制页面的显示的字符集,而提交表单出现乱码主要是在提交数据后与得到数据前的数据传输过程。

6.数据库乱码(不清楚)

数据库乱码有两种可能,一种是你request得到的数据就是乱码的,另一种就是你request得到的数据正确,而存入数据库时乱码。第一种情况,参考第5点的解决方式。第二种情况,则是数据库的问题,暂时不清楚。


总结:到现在而知,对于JSP编码的方式还不是很清楚,虽然能解决问题了,但是弄不清许多问题。这些问题有:

①JSP->JAVA->class文件,这个过程涉及到的编码是怎样的。还有当用户请求,服务器发给客户端时,与contentType的关系是这样的?

②Request请求数据后,浏览器是怎么发送数据的,这中间的编码是怎样的?


参考资料:

*解决中文JSP乱码问题

*JSP中的pageEncoding和contentType属性

*String.getBytes()方法


分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics