很怪的乱码问题,怎么解决啊? 页面开头用下面的两句就不会有乱码了<%@page contentType="text/html;charset=gb2312"%><% request.setCharacterEncoding("gb2312");%>//设置传递参数为gb2312 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 给你一个JavaBean,/** * Title: 含有中文的字符串转换成能正常显示中文的字符串 * * Description: --beans scope 推荐: "page"或"application" * **/public class tranChinese { public String toChinese(String s) { if (s != null) { try { return new String(s.getBytes("iso-8859-1"), "GB2312"); } catch (java.io.UnsupportedEncodingException e) { System.out.println(e.toString()); } } return s; }public String toUnicode(String s) { if (s != null) { try { return new String(s.getBytes("GB2312"), "iso-8859-1"); } catch (java.io.UnsupportedEncodingException e) { System.out.println(e.toString()); } } return s; }} 转换函数 public static String U2C(String s) { String str = s; try { if ( str == null ) return str; byte[] u = str.getBytes("iso-8859-1"); return new String(u,"GB2312"); } catch(java.io.UnsupportedEncodingException e) { e.printStackTrace(); return str; } } tcmy_168(超人) ,试过你的方法,没有用,而且我不是一个人做项目,你的页面传递的参数字符集都变了,不好跟别人的模块结合啊java.net.URLEncoder.encode()用的是什么字符集啊? 谢谢大家,但我说过我已经试过了String content = new String(request.getParameter("content").getBytes("ISO-8859-1"), "gb2312");没人遇见过类似的问题? 请问你get参数时是否用decode(URLDecoder())方法解码?你可以试试用request.getCharacterEncoding()来看看你的编码类型。 request.getCharacterEncoding()=null ?我用java.net.URLDecoder.decode()也不行啊 开头加上这个<%@page contentType="text/html;charset=GBK"%> 查到原因:java.net.URLEncoder.encode(content)输出全为%3F%3F%3F%3F%3F...?怎么回事啊? 你的问题我遇到过,是在linux下没有你要的中文字体,你修改jdk的font.property属性,再把win下的中文字符拷过来就可以了,是不是你显示的乱码是小方格。 1:在URL中传递中文时,要注意先 tempStr = java.net.URLEncoder.encode(tempStr); 在目标页取值时再 tempStr = java.net.URLDecoder.decode(tempStr); 否则等到的值为"". 但是注意,用了decode后就不要2中的转换了。2:用表单进行传值则目标页 byte[] tempByte = tempStr.getBytes("ISO8859-1"); tempStr = new String(tempStr); request.getCharacterEncoding()=null ?~~~~可以在你的jsp页的开头设置编码:<%request.setCharacterEncoding("GBK")%> 可是我如果不用java.net.URLEncoder.encode()时,用别的方法传递参数就可以显示中文啊 不需要这么麻烦在读取参数之前先设置一下编码request.setCharacterEncoding("GBK"); 用filter吧,写一个class很简洁就搞定中文问题了。。 1.我需要用QueryString附带到URL中传值,所以用了java.net.URLEncoder.encode()有别的方法吗?2.现在的不是读取参数的问题,而是发送request之前就出错了:不管我的content是什么java.net.URLEncoder.encode(content)输出全为%3F%3F%3F%3F%3F... 给些资料你看,你自己去理解一下吧,相信对你的问题有所帮助:首先一个概念:即使是基于Java的WEB应用,在服务器和客户端之间传递的仍然是字节流,比如我从一个中文客户端的浏览器表单中提交“世界你好”这4个中文字到服务器时:首先浏览器按照GBK方式编码成字节流CA C0 BD E7 C4 E3 BA C3,然后8个字节按照URLEncoding的规范转成:%CA%C0%BD%E7%C4%E3%BA%C3,服务器端的Servlet接收到请求后应该按什么解码处理,输出时又应该按什么方式编码行字节流呢? 在目前的Servlet的规范中,如果不指定的话通过WEB提交时的输入ServletRequest和输出时的ServletResponse缺省都是ISO-8859-1方式编/码解码的(注意,这里的编码/解码方式是和操作系统环境中的语言环境是无关的)。因此,即使服务器操作系统的语言环境是中文,上面输入的请求仍然按英文解码成8个UNICODE字符,输出时仍按照英文再编码成8个字节,虽然这样在浏览器端如果设置是中文能够正确显示,但实际上读写的是“字节”,正确的方式是应该根据客户端浏览器设置ServletRequest和ServletResponse用相应语言的编码方式进行输入解码/输入编码,HelloUnicodeServlet.java就是这样一个监测客户端浏览器语言设置的例子:当根据浏览器的头信息中的"Accept-Language"为zh-cn(中文)时,设置请求的解码方式和输出的字符集编码方式使用GBK: //auto detect broswer's languages String clientLanguage = req.getHeader("Accept-Language"); //for Simplied Chinese if ( clientLanguage.equals("zh-cn") ) { req.setCharacterEncoding("GBK"); res.setContentType("text/html; charset=GBK"); }输出为: '世界你好' length=4ServletRequest's Charset Encoding = GBK ServletResponse's Charset Encoding = GBK char[0]='世' byte=22 \u16 short=19990 \u4E16 CJK_UNIFIED_IDEOGRAPHSchar[1]='界' byte=76 \u4C short=30028 \u754C CJK_UNIFIED_IDEOGRAPHSchar[2]='你' byte=96 \u60 short=20320 \u4F60 CJK_UNIFIED_IDEOGRAPHSchar[3]='好' byte=125 \u7D short=22909 \u597D CJK_UNIFIED_IDEOGRAPHS再做一个试验:把程序开头部分的浏览器自动检测功能注释掉,再次的输出结果就是和目前很多应用一样其实是按ISO-8859-1方式解码/编码的“字节应用”了:'世界你好' length=8ServletRequest's Charset Encoding = null ServletResponse's Charset Encoding = ISO-8859-1 char[0]='? byte=-54 \uFFFFFFCA short=202 \uCA LATIN_1_SUPPLEMENTchar[1]='? byte=-64 \uFFFFFFC0 short=192 \uC0 LATIN_1_SUPPLEMENTchar[2]='? byte=-67 \uFFFFFFBD short=189 \uBD LATIN_1_SUPPLEMENTchar[3]='? byte=-25 \uFFFFFFE7 short=231 \uE7 LATIN_1_SUPPLEMENTchar[4]='? byte=-60 \uFFFFFFC4 short=196 \uC4 LATIN_1_SUPPLEMENTchar[5]='? byte=-29 \uFFFFFFE3 short=227 \uE3 LATIN_1_SUPPLEMENTchar[6]='? byte=-70 \uFFFFFFBA short=186 \uBA LATIN_1_SUPPLEMENTchar[7]='? byte=-61 \uFFFFFFC3 short=195 \uC3 LATIN_1_SUPPLEMENT虽然这样的输出结果如果在浏览器中设置用中文字符集也能正确显示,但实际上处理的已经是“字节”而不是处理中文“字符”了。ServletRequest 和 ServletResponse 缺省使用ISO-8859-1字符集解码/编码的具体定义请参考:http://java.sun.com/products/servlet/2.3/javadoc/javax/servlet/ServletRequest.html#setCharacterEncoding(java.lang.String)http://java.sun.com/products/servlet/2.3/javadoc/javax/servlet/ServletResponse.html#setContentType() 以前能够配置让一个WEB应用能够在GBK方式编码的中文Windows2000服务器上和按ISO-8859-1方式编码的GNU/Linux上都能够正确的显示中文一直让我迷惑了很久。我仔细想了一下,后来终于想明白了,在一个国际化的应用中:ServletRequest和ServletResponse的编码/解码方式的确不应该根据服务器设置成固定的字符集,而应该是面向客户端语言环境进行输入/输出编码方式的自适应。一个按照国际化规范设计的WEB应用中:在Servlet的源代码中尽量不要有中文:因为在MVC模式中,Servlet主要是控制器(C)的角色,因此,应该通过ResourceBundle机制由Servlet控制转向到相应的显示器(JSP或者XSLT)中,所以应该将与本地界面语言相关的界面显示的部分从Servlet和后台的模块中完全剥离出来,放到相应的ResourceBundle文件中或者XSLT文件中。这样源程序里完全是英文,编译时完全不需要考虑字符集的问题。如果Servlet实在需要包含中文,则需要设置应用服务器的Javac编译选项,加上-encoding选项成系统缺省的字符集,如果把用中文编写的字符按照英文方式解码编译,然后再按照英文方式输出,虽然结果表面正确,实际上都成了面向“字节”编程。在Servlet层,应该像GOOGLE搜索引擎那样,设计成能够根据客户端浏览器的语言环境自适应输出,为了判断浏览器的语言Servlet中应该有类似以下的代码: public void doGet (HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { //从HTTP请求的头信息中获取客户端的语言设置 String clientLanguage = req.getHeader("Accept-Language"); //简体中文浏览器 if ( clientLanguage.equals("zh-cn") ) { req.setCharacterEncoding("GBK"); res.setContentType("text/html; charset=GBK"); } //繁体中文浏览器 else if ( clientLanguage.equals("zh-tw") ) { req.setCharacterEncoding("BIG5"); res.setContentType("text/html; charset=BIG5"); } //日文浏览器 else if ( clientLanguage.equals("jp") ) { req.setCharacterEncoding("SJIS"); res.setContentType("text/html; charset=SJIS"); } //缺省认为是英文浏览器 else { req.setCharacterEncoding("ISO-8859-1"); res.setContentType("text/html; charset=ISO-8859-1"); } ... //设置好request的解码方式和response的编码方式后,进行后续的操作。 //比如再转向到HelloWorld.gbk.jsp HelloWorld.big5.jsp HelloWorld.jis.jsp等 }而SERVLET缺省将字符集设置为ISO-8859-1也许是标准制定者认为英文的浏览器占大多数吧(而且按照ISO-8859-1方式输出界面往往也是正确的)。 给段资料你,相信对你的问题有所帮助:首先一个概念:即使是基于Java的WEB应用,在服务器和客户端之间传递的仍然是字节流,比如我从一个中文客户端的浏览器表单中提交“世界你好”这4个中文字到服务器时:首先浏览器按照GBK方式编码成字节流CA C0 BD E7 C4 E3 BA C3,然后8个字节按照URLEncoding的规范转成:%CA%C0%BD%E7%C4%E3%BA%C3,服务器端的Servlet接收到请求后应该按什么解码处理,输出时又应该按什么方式编码行字节流呢? 在目前的Servlet的规范中,如果不指定的话通过WEB提交时的输入ServletRequest和输出时的ServletResponse缺省都是ISO-8859-1方式编/码解码的(注意,这里的编码/解码方式是和操作系统环境中的语言环境是无关的)。因此,即使服务器操作系统的语言环境是中文,上面输入的请求仍然按英文解码成8个UNICODE字符,输出时仍按照英文再编码成8个字节,虽然这样在浏览器端如果设置是中文能够正确显示,但实际上读写的是“字节”,正确的方式是应该根据客户端浏览器设置ServletRequest和ServletResponse用相应语言的编码方式进行输入解码/输入编码,HelloUnicodeServlet.java就是这样一个监测客户端浏览器语言设置的例子:当根据浏览器的头信息中的"Accept-Language"为zh-cn(中文)时,设置请求的解码方式和输出的字符集编码方式使用GBK: //auto detect broswer's languages String clientLanguage = req.getHeader("Accept-Language"); //for Simplied Chinese if ( clientLanguage.equals("zh-cn") ) { req.setCharacterEncoding("GBK"); res.setContentType("text/html; charset=GBK"); }输出为: '世界你好' length=4ServletRequest's Charset Encoding = GBK ServletResponse's Charset Encoding = GBK char[0]='世' byte=22 \u16 short=19990 \u4E16 CJK_UNIFIED_IDEOGRAPHSchar[1]='界' byte=76 \u4C short=30028 \u754C CJK_UNIFIED_IDEOGRAPHSchar[2]='你' byte=96 \u60 short=20320 \u4F60 CJK_UNIFIED_IDEOGRAPHSchar[3]='好' byte=125 \u7D short=22909 \u597D CJK_UNIFIED_IDEOGRAPHS再做一个试验:把程序开头部分的浏览器自动检测功能注释掉,再次的输出结果就是和目前很多应用一样其实是按ISO-8859-1方式解码/编码的“字节应用”了:'世界你好' length=8ServletRequest's Charset Encoding = null ServletResponse's Charset Encoding = ISO-8859-1 char[0]='? byte=-54 \uFFFFFFCA short=202 \uCA LATIN_1_SUPPLEMENTchar[1]='? byte=-64 \uFFFFFFC0 short=192 \uC0 LATIN_1_SUPPLEMENTchar[2]='? byte=-67 \uFFFFFFBD short=189 \uBD LATIN_1_SUPPLEMENTchar[3]='? byte=-25 \uFFFFFFE7 short=231 \uE7 LATIN_1_SUPPLEMENTchar[4]='? byte=-60 \uFFFFFFC4 short=196 \uC4 LATIN_1_SUPPLEMENTchar[5]='? byte=-29 \uFFFFFFE3 short=227 \uE3 LATIN_1_SUPPLEMENTchar[6]='? byte=-70 \uFFFFFFBA short=186 \uBA LATIN_1_SUPPLEMENTchar[7]='? byte=-61 \uFFFFFFC3 short=195 \uC3 LATIN_1_SUPPLEMENT虽然这样的输出结果如果在浏览器中设置用中文字符集也能正确显示,但实际上处理的已经是“字节”而不是处理中文“字符”了。ServletRequest 和 ServletResponse 缺省使用ISO-8859-1字符集解码/编码的具体定义请参考:http://java.sun.com/products/servlet/2.3/javadoc/javax/servlet/ServletRequest.html#setCharacterEncoding(java.lang.String)http://java.sun.com/products/servlet/2.3/javadoc/javax/servlet/ServletResponse.html#setContentType() 以前能够配置让一个WEB应用能够在GBK方式编码的中文Windows2000服务器上和按ISO-8859-1方式编码的GNU/Linux上都能够正确的显示中文一直让我迷惑了很久。我仔细想了一下,后来终于想明白了,在一个国际化的应用中:ServletRequest和ServletResponse的编码/解码方式的确不应该根据服务器设置成固定的字符集,而应该是面向客户端语言环境进行输入/输出编码方式的自适应。一个按照国际化规范设计的WEB应用中:在Servlet的源代码中尽量不要有中文:因为在MVC模式中,Servlet主要是控制器(C)的角色,因此,应该通过ResourceBundle机制由Servlet控制转向到相应的显示器(JSP或者XSLT)中,所以应该将与本地界面语言相关的界面显示的部分从Servlet和后台的模块中完全剥离出来,放到相应的ResourceBundle文件中或者XSLT文件中。这样源程序里完全是英文,编译时完全不需要考虑字符集的问题。如果Servlet实在需要包含中文,则需要设置应用服务器的Javac编译选项,加上-encoding选项成系统缺省的字符集,如果把用中文编写的字符按照英文方式解码编译,然后再按照英文方式输出,虽然结果表面正确,实际上都成了面向“字节”编程。在Servlet层,应该像GOOGLE搜索引擎那样,设计成能够根据客户端浏览器的语言环境自适应输出,为了判断浏览器的语言Servlet中应该有类似以下的代码: public void doGet (HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { //从HTTP请求的头信息中获取客户端的语言设置 String clientLanguage = req.getHeader("Accept-Language"); //简体中文浏览器 if ( clientLanguage.equals("zh-cn") ) { req.setCharacterEncoding("GBK"); res.setContentType("text/html; charset=GBK"); } //繁体中文浏览器 else if ( clientLanguage.equals("zh-tw") ) { req.setCharacterEncoding("BIG5"); res.setContentType("text/html; charset=BIG5"); } //日文浏览器 else if ( clientLanguage.equals("jp") ) { req.setCharacterEncoding("SJIS"); res.setContentType("text/html; charset=SJIS"); } //缺省认为是英文浏览器 else { req.setCharacterEncoding("ISO-8859-1"); res.setContentType("text/html; charset=ISO-8859-1"); } ... //设置好request的解码方式和response的编码方式后,进行后续的操作。 //比如再转向到HelloWorld.gbk.jsp HelloWorld.big5.jsp HelloWorld.jis.jsp等 }而SERVLET缺省将字符集设置为ISO-8859-1也许是标准制定者认为英文的浏览器占大多数吧(而且按照ISO-8859-1方式输出界面往往也是正确的)。 求助一个小型的门户网站如何实现!!!! freemarker 和 struts2集成 请教高手:Java backend performance 各位都用什么写界面 cookie中文问题! 真郁闷!! 连接MySQL数据库的乱码问题 jsp编译时报错,哪位给看看吧。谢谢 想在源程序中把一段信息自动发到一个信箱中,不用配smtp可以实现吗? 关于bean操作数据库的一个问题。 我刚接触JSP,我是想将输入的字符转换为ASCII码,具体该怎么做呢? 在java中怎么去空格??? 这个问题对于高手很简单,可我却忙活了好几个小时(新手,没办法!)
/**
* Title: 含有中文的字符串转换成能正常显示中文的字符串
*
* Description: --beans scope 推荐: "page"或"application"
*
**/public class tranChinese
{
public String toChinese(String s)
{
if (s != null)
{
try
{
return new String(s.getBytes("iso-8859-1"), "GB2312");
}
catch (java.io.UnsupportedEncodingException e)
{
System.out.println(e.toString());
}
}
return s;
}public String toUnicode(String s)
{
if (s != null)
{
try
{
return new String(s.getBytes("GB2312"), "iso-8859-1");
}
catch (java.io.UnsupportedEncodingException e)
{
System.out.println(e.toString());
}
}
return s;
}
}
public static String U2C(String s)
{
String str = s;
try
{
if ( str == null ) return str;
byte[] u = str.getBytes("iso-8859-1");
return new String(u,"GB2312");
}
catch(java.io.UnsupportedEncodingException e)
{
e.printStackTrace();
return str;
}
}
java.net.URLEncoder.encode()用的是什么字符集啊?
String content = new String(request.getParameter("content").getBytes("ISO-8859-1"), "gb2312");
没人遇见过类似的问题?
我用java.net.URLDecoder.decode()也不行啊
<%@page contentType="text/html;charset=GBK"%>
java.net.URLEncoder.encode(content)输出全为%3F%3F%3F%3F%3F...?
怎么回事啊?
tempStr = java.net.URLEncoder.encode(tempStr);
在目标页取值时再
tempStr = java.net.URLDecoder.decode(tempStr);
否则等到的值为"".
但是注意,用了decode后就不要2中的转换了。2:用表单进行传值则目标页
byte[] tempByte = tempStr.getBytes("ISO8859-1");
tempStr = new String(tempStr);
~~~~可以在你的jsp页的开头设置编码:
<%
request.setCharacterEncoding("GBK")
%>
2.现在的不是读取参数的问题,而是发送request之前就出错了:不管我的content是什么java.net.URLEncoder.encode(content)输出全为%3F%3F%3F%3F%3F...
在目前的Servlet的规范中,如果不指定的话通过WEB提交时的输入ServletRequest和输出时的ServletResponse缺省都是ISO-8859-1方式编/码解码的(注意,这里的编码/解码方式是和操作系统环境中的语言环境是无关的)。因此,即使服务器操作系统的语言环境是中文,上面输入的请求仍然按英文解码成8个UNICODE字符,输出时仍按照英文再编码成8个字节,虽然这样在浏览器端如果设置是中文能够正确显示,但实际上读写的是“字节”,正确的方式是应该根据客户端浏览器设置ServletRequest和ServletResponse用相应语言的编码方式进行输入解码/输入编码,HelloUnicodeServlet.java就是这样一个监测客户端浏览器语言设置的例子:
当根据浏览器的头信息中的"Accept-Language"为zh-cn(中文)时,设置请求的解码方式和输出的字符集编码方式使用GBK:
//auto detect broswer's languages String clientLanguage = req.getHeader("Accept-Language"); //for Simplied Chinese if ( clientLanguage.equals("zh-cn") ) { req.setCharacterEncoding("GBK"); res.setContentType("text/html; charset=GBK"); }
输出为:
'世界你好' length=4ServletRequest's Charset Encoding = GBK ServletResponse's Charset Encoding = GBK char[0]='世' byte=22 \u16 short=19990 \u4E16 CJK_UNIFIED_IDEOGRAPHSchar[1]='界' byte=76 \u4C short=30028 \u754C CJK_UNIFIED_IDEOGRAPHSchar[2]='你' byte=96 \u60 short=20320 \u4F60 CJK_UNIFIED_IDEOGRAPHSchar[3]='好' byte=125 \u7D short=22909 \u597D CJK_UNIFIED_IDEOGRAPHS
再做一个试验:把程序开头部分的浏览器自动检测功能注释掉,再次的输出结果就是和目前很多应用一样其实是按ISO-8859-1方式解码/编码的“字节应用”了:'世界你好' length=8ServletRequest's Charset Encoding = null ServletResponse's Charset Encoding = ISO-8859-1 char[0]='? byte=-54 \uFFFFFFCA short=202 \uCA LATIN_1_SUPPLEMENTchar[1]='? byte=-64 \uFFFFFFC0 short=192 \uC0 LATIN_1_SUPPLEMENTchar[2]='? byte=-67 \uFFFFFFBD short=189 \uBD LATIN_1_SUPPLEMENTchar[3]='? byte=-25 \uFFFFFFE7 short=231 \uE7 LATIN_1_SUPPLEMENTchar[4]='? byte=-60 \uFFFFFFC4 short=196 \uC4 LATIN_1_SUPPLEMENTchar[5]='? byte=-29 \uFFFFFFE3 short=227 \uE3 LATIN_1_SUPPLEMENTchar[6]='? byte=-70 \uFFFFFFBA short=186 \uBA LATIN_1_SUPPLEMENTchar[7]='? byte=-61 \uFFFFFFC3 short=195 \uC3 LATIN_1_SUPPLEMENT
虽然这样的输出结果如果在浏览器中设置用中文字符集也能正确显示,但实际上处理的已经是“字节”而不是处理中文“字符”了。ServletRequest 和 ServletResponse 缺省使用ISO-8859-1字符集解码/编码的具体定义请参考:
http://java.sun.com/products/servlet/2.3/javadoc/javax/servlet/ServletRequest.html#setCharacterEncoding(java.lang.String)
http://java.sun.com/products/servlet/2.3/javadoc/javax/servlet/ServletResponse.html#setContentType()
以前能够配置让一个WEB应用能够在GBK方式编码的中文Windows2000服务器上和按ISO-8859-1方式编码的GNU/Linux上都能够正确的显示中文一直让我迷惑了很久。我仔细想了一下,后来终于想明白了,在一个国际化的应用中:ServletRequest和ServletResponse的编码/解码方式的确不应该根据服务器设置成固定的字符集,而应该是面向客户端语言环境进行输入/输出编码方式的自适应。一个按照国际化规范设计的WEB应用中:在Servlet的源代码中尽量不要有中文:因为在MVC模式中,Servlet主要是控制器(C)的角色,因此,应该通过ResourceBundle机制由Servlet控制转向到相应的显示器(JSP或者XSLT)中,所以应该将与本地界面语言相关的界面显示的部分从Servlet和后台的模块中完全剥离出来,放到相应的ResourceBundle文件中或者XSLT文件中。这样源程序里完全是英文,编译时完全不需要考虑字符集的问题。如果Servlet实在需要包含中文,则需要设置应用服务器的Javac编译选项,加上-encoding选项成系统缺省的字符集,如果把用中文编写的字符按照英文方式解码编译,然后再按照英文方式输出,虽然结果表面正确,实际上都成了面向“字节”编程。在Servlet层,应该像GOOGLE搜索引擎那样,设计成能够根据客户端浏览器的语言环境自适应输出,为了判断浏览器的语言Servlet中应该有类似以下的代码:
public void doGet (HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { //从HTTP请求的头信息中获取客户端的语言设置 String clientLanguage = req.getHeader("Accept-Language"); //简体中文浏览器 if ( clientLanguage.equals("zh-cn") ) { req.setCharacterEncoding("GBK"); res.setContentType("text/html; charset=GBK"); } //繁体中文浏览器 else if ( clientLanguage.equals("zh-tw") ) { req.setCharacterEncoding("BIG5"); res.setContentType("text/html; charset=BIG5"); } //日文浏览器 else if ( clientLanguage.equals("jp") ) { req.setCharacterEncoding("SJIS"); res.setContentType("text/html; charset=SJIS"); } //缺省认为是英文浏览器 else { req.setCharacterEncoding("ISO-8859-1"); res.setContentType("text/html; charset=ISO-8859-1"); } ... //设置好request的解码方式和response的编码方式后,进行后续的操作。 //比如再转向到HelloWorld.gbk.jsp HelloWorld.big5.jsp HelloWorld.jis.jsp等 }
而SERVLET缺省将字符集设置为ISO-8859-1也许是标准制定者认为英文的浏览器占大多数吧(而且按照ISO-8859-1方式输出界面往往也是正确的)。
在目前的Servlet的规范中,如果不指定的话通过WEB提交时的输入ServletRequest和输出时的ServletResponse缺省都是ISO-8859-1方式编/码解码的(注意,这里的编码/解码方式是和操作系统环境中的语言环境是无关的)。因此,即使服务器操作系统的语言环境是中文,上面输入的请求仍然按英文解码成8个UNICODE字符,输出时仍按照英文再编码成8个字节,虽然这样在浏览器端如果设置是中文能够正确显示,但实际上读写的是“字节”,正确的方式是应该根据客户端浏览器设置ServletRequest和ServletResponse用相应语言的编码方式进行输入解码/输入编码,HelloUnicodeServlet.java就是这样一个监测客户端浏览器语言设置的例子:
当根据浏览器的头信息中的"Accept-Language"为zh-cn(中文)时,设置请求的解码方式和输出的字符集编码方式使用GBK:
//auto detect broswer's languages String clientLanguage = req.getHeader("Accept-Language"); //for Simplied Chinese if ( clientLanguage.equals("zh-cn") ) { req.setCharacterEncoding("GBK"); res.setContentType("text/html; charset=GBK"); }
输出为:
'世界你好' length=4ServletRequest's Charset Encoding = GBK ServletResponse's Charset Encoding = GBK char[0]='世' byte=22 \u16 short=19990 \u4E16 CJK_UNIFIED_IDEOGRAPHSchar[1]='界' byte=76 \u4C short=30028 \u754C CJK_UNIFIED_IDEOGRAPHSchar[2]='你' byte=96 \u60 short=20320 \u4F60 CJK_UNIFIED_IDEOGRAPHSchar[3]='好' byte=125 \u7D short=22909 \u597D CJK_UNIFIED_IDEOGRAPHS
再做一个试验:把程序开头部分的浏览器自动检测功能注释掉,再次的输出结果就是和目前很多应用一样其实是按ISO-8859-1方式解码/编码的“字节应用”了:'世界你好' length=8ServletRequest's Charset Encoding = null ServletResponse's Charset Encoding = ISO-8859-1 char[0]='? byte=-54 \uFFFFFFCA short=202 \uCA LATIN_1_SUPPLEMENTchar[1]='? byte=-64 \uFFFFFFC0 short=192 \uC0 LATIN_1_SUPPLEMENTchar[2]='? byte=-67 \uFFFFFFBD short=189 \uBD LATIN_1_SUPPLEMENTchar[3]='? byte=-25 \uFFFFFFE7 short=231 \uE7 LATIN_1_SUPPLEMENTchar[4]='? byte=-60 \uFFFFFFC4 short=196 \uC4 LATIN_1_SUPPLEMENTchar[5]='? byte=-29 \uFFFFFFE3 short=227 \uE3 LATIN_1_SUPPLEMENTchar[6]='? byte=-70 \uFFFFFFBA short=186 \uBA LATIN_1_SUPPLEMENTchar[7]='? byte=-61 \uFFFFFFC3 short=195 \uC3 LATIN_1_SUPPLEMENT
虽然这样的输出结果如果在浏览器中设置用中文字符集也能正确显示,但实际上处理的已经是“字节”而不是处理中文“字符”了。ServletRequest 和 ServletResponse 缺省使用ISO-8859-1字符集解码/编码的具体定义请参考:
http://java.sun.com/products/servlet/2.3/javadoc/javax/servlet/ServletRequest.html#setCharacterEncoding(java.lang.String)
http://java.sun.com/products/servlet/2.3/javadoc/javax/servlet/ServletResponse.html#setContentType()
以前能够配置让一个WEB应用能够在GBK方式编码的中文Windows2000服务器上和按ISO-8859-1方式编码的GNU/Linux上都能够正确的显示中文一直让我迷惑了很久。我仔细想了一下,后来终于想明白了,在一个国际化的应用中:ServletRequest和ServletResponse的编码/解码方式的确不应该根据服务器设置成固定的字符集,而应该是面向客户端语言环境进行输入/输出编码方式的自适应。一个按照国际化规范设计的WEB应用中:在Servlet的源代码中尽量不要有中文:因为在MVC模式中,Servlet主要是控制器(C)的角色,因此,应该通过ResourceBundle机制由Servlet控制转向到相应的显示器(JSP或者XSLT)中,所以应该将与本地界面语言相关的界面显示的部分从Servlet和后台的模块中完全剥离出来,放到相应的ResourceBundle文件中或者XSLT文件中。这样源程序里完全是英文,编译时完全不需要考虑字符集的问题。如果Servlet实在需要包含中文,则需要设置应用服务器的Javac编译选项,加上-encoding选项成系统缺省的字符集,如果把用中文编写的字符按照英文方式解码编译,然后再按照英文方式输出,虽然结果表面正确,实际上都成了面向“字节”编程。在Servlet层,应该像GOOGLE搜索引擎那样,设计成能够根据客户端浏览器的语言环境自适应输出,为了判断浏览器的语言Servlet中应该有类似以下的代码:
public void doGet (HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { //从HTTP请求的头信息中获取客户端的语言设置 String clientLanguage = req.getHeader("Accept-Language"); //简体中文浏览器 if ( clientLanguage.equals("zh-cn") ) { req.setCharacterEncoding("GBK"); res.setContentType("text/html; charset=GBK"); } //繁体中文浏览器 else if ( clientLanguage.equals("zh-tw") ) { req.setCharacterEncoding("BIG5"); res.setContentType("text/html; charset=BIG5"); } //日文浏览器 else if ( clientLanguage.equals("jp") ) { req.setCharacterEncoding("SJIS"); res.setContentType("text/html; charset=SJIS"); } //缺省认为是英文浏览器 else { req.setCharacterEncoding("ISO-8859-1"); res.setContentType("text/html; charset=ISO-8859-1"); } ... //设置好request的解码方式和response的编码方式后,进行后续的操作。 //比如再转向到HelloWorld.gbk.jsp HelloWorld.big5.jsp HelloWorld.jis.jsp等 }
而SERVLET缺省将字符集设置为ISO-8859-1也许是标准制定者认为英文的浏览器占大多数吧(而且按照ISO-8859-1方式输出界面往往也是正确的)。