1、第十五章,国际化和JSP中文乱码处理,课程内容,国际化问题 中文乱码处理问题,课程定位,什么是国际化,网站实现国际化,主要是为了将资源进行全球共享。 首先,要我们来了解一下,网站是如何实现全球资源共享的。我们在浏览器地址栏中输入“中央电视台”的中文网址:“http:”。 我们发现,在网页的头栏中,可以选择“繁体”或其它语种阅读网站内容,如图中白色方框所框起部分。,什么是国际化,国际化又称为I18N,它的由来是因为它的英文是Internationalization,以I开头,N结尾,总共有18个字母(本地化的英文是Localization,所以称为L10N)。国际化问题主要包含下列四种内容:,日
2、期格式、时间格式 数字 货币 其它一些特殊字符,HTML字符实体与Unicode字符标准,HTML字符实体定义了用特定的字符序列显示单字符的功能。 它由三部分构成:以“”。要注意的是,实体对大小写是敏感的。Unicode字符标准由Unicode协会定制,它是一个字符编码系统,支持相互转换、处理和显示全球不同语言的文本内容。 Unicode使用“uxxxx”表示一个字符,它的前256个字符和ISO-8859-1标准(Latin-1)的256个字符是一致的。,JSP中文乱码处理,首先我们先来看一个小例子,在一个JSP页面中,只写入以下一句代码:然后运行程序,将出现如图所示的一串乱码:,为什么会出现
3、乱码,其实,大部分Java应用服务器都是在使用英语的国家中开发出来的,由于缺乏某些字符集(中文、日文、韩文等)的应用环境,这些应用服务器在处理HTTP请求时就存在一些中文处理的问题,于是这就成为了困扰JSP和Servlet开发者的难题。 最直观的解决方法就是在浏览器的菜单栏中依次选择“查看”“编码”“简体中文(GB2312)”,如图所示,然后浏览器就会正确的显示出中文来。具体操作如图所示:,乱码的原因,我们都知道,西欧语系都用一个字节来存储字符,而东方以汉语为主的语系都是用两个字节来存储字符。 在Web应用中,当客户端向服务器提交请求的时候,提交的信息一般用本地字符集进行编码,如中文采用GB2
4、312或GBK字符集(GBK是GB2312的扩展),英文或西欧文字采用ISO-8859-1字符集。 由于Java程序中一律采用Unicode处理字符串,当JSP文件转成Java文件时,大部分服务器默认使用ISO-8859-1字符集来进行编码,所以出现乱码问题也是在所难免的(这一点,我们可以通过查看Jasper所生成的Java中间文件来确认)。于是,就要求我们在编写程序的时候,进行编码转换。,解决显示乱码问题,只需要在程序第一行加上以下代码就可以处理中文乱码问题了。再次运行程序,效果如图所示:,方案一,方案: 在上个例子中,我们采取的是使用伪指令来指明输出页面所使用的字符集,JSP引擎会将伪指令
5、转换为HTTP应答的头部:contentType=“text/html;charset=GBK”。 这样,浏览器就会输出GBK编码的中文页面。采取这个方案可以解决页面普通的中文输出。在现实开发中,有时需要同时写入下面两行代码。,解决输入乱码问题,浏览器在将表单的内容以POST方式提交到服务器时,却没有包含charset字符集,而且将中文信息以%xx的形式(xx是十六进制数)进行编码。 例如汉字“中”的GB2312内码为0xD6D0,在HTTP请求中就变成了%D6%D0,根据RFC2616的规定,如果在HTTP请求中未指明字符集,就使用ISO-8859-1编码,这样“中”字在处理时变成了两个字符
6、,分别为“u00D6”和“u00D0”,而返回到客户端时变成了两个不可显示的字符,浏览器一般显示成“?”。 下面我们来做一个测试,编写两个简单的JSP页面,第一个JSP页面以POST方式向第二个页面提交信息,第二个页面得到信息之后直接打印出来。页面代码如下:,test.jsp: 输入中文进行测试getinfo.jsp:测试表单的提交信息客户端提交的信息:然后就可以启动服务器测试程序了,在test.jsp页面的文本框中输入“中华人民共和国”,如图所示:,点击“ok”按钮,我们看到getinfo.jsp将得到的中文信息以一串问号显示出来了,方案二,不管是在JSP页面还是在Servlet中,只要在接
7、收信息之前加上以下代码就可以了。request.setCharacterEncoding(“GB2312“); 当然,在Servlet中要输出信息时,也需要对输出信息指定编码类型,如下:response.setContentsType(“text/html;charset= GB2312“);下面我们就对getinfo.jsp稍加修改,指定客户端请求以“GB2312”类型对信息进行编码,如下:接下来再次测试程序,发现问题得到了解决,中文信息正确显示出来了。如图所示:,注意:这种解决方式只对POST提交方式有效,如果客户端是以GET方式或者URL重写的方式提交的中文信息,可能它就无用武之地了。,
8、参数传递乱码问题,在Web应用中,客户端提交请求信息时,在某些情况下需要用到GET提交方式。 有时,在以URL重写方式传递信息时,也会传递中文信息。 这两种方式如果用方案二是无法解决中文乱码问题的。我们先来看一个测试,还是需要两个JSP页面。如下: refer.jsp输入中文进行测试下一页,info.jsp测试中文信息传递的中文信息:在refer.jsp中分别用GET方式和URL重写方式向info.jsp提交中文字符串“我爱我家”,我们发现,当使用GET方式提交时,URL变成了如下所示:http:/localhost:8080/Web/info.jsp?test=%CE%D2%B0%AE%CE
9、%D2%BC%D2而用URL重写方式传递参数时,URL是:http:/localhost:8080/Web/info.jsp?test=我爱我家,虽然在info.jsp中用到了request.setCharacterEncoding(“GB2312“);,可浏览器显示出来的还是一堆乱码,两种情况下,都把“我爱我家”显示成了“?”,如图所示:,方案三,只要是经过URL传递参数的,系统会默认采用“ISO-8859-1”的编码方式对信息进行编码 request.setCharacterEncoding(“GB2312”) 只能对按照变量和值相对应的传递方式进行中文处理。 只需要在输出中文信息之前,再
10、对指定信息进行编码就能解决问题,代码如下:在实际开发中,如果只有一两处需要转换,可以采用这个方法,如果需要转换的数据比较多的情况下,我们就可以把转换函数封装起来,然后在需要编码的页面来调用这个函数。 下面我们就来开发这个函数,代码如下:,tocn.jsp: ,然后我们在info.jsp中来调这个函数,具体代码如下:测试中文信息传递的中文信息:,采用这种方法亦能解决向数据库添加信息时出现的乱码问题。,方案四,如果使用的是TOMCAT服务器,可以修改server.xml中两个部分,如下:重启服务器就可以了。,方案五,可以开发一个过滤器。 开发这样的一个过滤器有它的优点和缺点,缺点是只对POST提交
11、方式有效,对GET提交方式不起作用。优点是可以对整个Web应用下的资源进行过滤。,本章总结,国际化问题 中文乱码处理问题,动手实践:区域时间显示,本地化编程应用,显示不同地区的时间显示格式,目标 显示不同地区的时间。 编写一个选择地区信息页面,在此页面中添加一个下拉列表和一个“提交”按钮。选择下拉列表中的地区信息后,点击“提交”按钮,将会把选择的地区信息提交至Servelt程序中进行处理,并向客户端返回所选地区的名称及当前时间(时间的显示格式为所选地区的时间格式)。 (1)首先在“choice.jsp”页面中,选择不同的地区信息。例如“中国”,如图所示:,(2)地区选择完成后,点击“提交”按钮
12、,显示效果如图所示:,(3)再次返回“choice.jsp”页面。选择“俄罗斯”,点击“提交”按钮,显示效果如图所示:,(4)选择“西班牙”,点击“提交”按钮,显示效果如图所示:,基本思路,(1)接收客户端提交的地区信息。 (2)将地区信息进行中文乱码处理。 (3)按照得到的地区信息输出该地区的时间显示格式。 在这个Servlet中,需要指定字符集为“UTF-8”,然后利用“gb2312”对客户端提交的中文信息进行重新编码。在输出时间格式时需要生成特定语种的Locale对象,如: Locale lo=new Locale(“zh“, “); 然后使用Locale对象生成一个对时间进行格式化的D
13、ateFormat对象,如: DateFormat df = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, lo); 最后使用df.format(new Date()输出与特定Locale相关的时间。,(1)选择地区信息的JSP页面,不同地区的时间显示格式请选择地区:中国美国韩国俄罗斯西班牙日本,Servlet,package test;import javax.servlet.*;import javax.servlet.http.*;import java.io.*;import java.util.*;i
14、mport java.text.*;import java.text.DateFormat;public class ShowServlet extends HttpServlet private String CONTENT_TYPE =“text/html; charset=UTF-8“;private Locale lo;private DateFormat df;public void,doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException
15、/中文处理request.setCharacterEncoding(“gb2312“);String area=request.getParameter(“area“);reponse.setContentType(CONTENT_TYPE);PrintWriter out = response.getWriter();if(area!=null)out.println(area);,if (area.equals(“中国“) lo = new Locale(“zh“, “);df = DateFormat.getDateTimeInstance(DateFormat.LONG,DateFor
16、mat.LONG, lo);out.println(“in China“);out.println(“ + df.format(new Date() + “); else if (area.equals(“美国“) lo = new Locale(“en“, “US“);df = DateFormat.getDateTimeInstance(DateFormat.LONG,DateFormat.LONG, lo);,out.println(“in America“);out.println(“ + df.format(new Date() + “); else if (area.equals(
17、“韩国“) lo = new Locale(“ko“, “);df = DateFormat.getDateTimeInstance(DateFormat.LONG,DateFormat.LONG, lo);out.println(“in Korea“);,out.println(“ + df.format(new Date() + “); else if (area.equals(“俄罗斯“) lo = new Locale(“ru“, “); df = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, lo);
18、out.println(“in Russia“);out.println(“ + df.format(new Date() + “); else if (area.equals(“西班牙“) lo = new Locale(“es“, “);,df = DateFormat.getDateTimeInstance(DateFormat.LONG,DateFormat.LONG, lo);out.println(“in Espana“);out.println(“ + df.format(new Date() + “); else if (area.equals(“日本“) lo = new Locale(“ja“, “); df = DateFormat.getDateTimeInstance(DateFormat.LONG,DateFormat.LONG, lo);out.printn(“in Japan“);out.println(“ + df.format(new Date() +“); out.close();,