Servlet 中文乱码问题及解决方案剖析

一、常识了解
 
1.GBK包含GB2312,即如果通过GB2312编码后可以通过GBK解码,反之可能不成立;
2.java.nio.charset.Charset.defaultCharset() 获得平台默认字符编码;
3.getBytes() 是通过平台默认字符集进行编码;
 
二、中文乱码出现
 
在学习任何一门技术时,经常会有初学者遇到中文乱码问题,比如MySQL,是因为在安装时没有设置;而在Servlet中,也会遇到中文乱码问题;
比如:
OutputStream out = response.getOutputStream();
out.write(String );
输出中文时可能会出现乱码;
比如:
[java]   view plain   copy
  1. protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {  
  2.           
  3.         OutputStream out = response.getOutputStream();  
  4.         String data = "博客";  
  5.         out.write(data.getBytes("UTF-8"));  
  6.     }  

输出乱码的问题是程序用UTF-8编码,而浏览器用GB2312解码,因此会出现乱码;
 
Servlet乱码分为request乱码和response乱码;
 spring用拦截器解决乱码问题
 <!-- 过滤器 将所有请求的request编码为utf-8-->
表单应该用post方式提交
< filter>
<filter-name>encodingFilter</filter-name>
<filter-class>
org.springframework.web.filter.CharacterEncodingFilter
</filter-class>
<init-param>
<param-name> encoding </param-name>
<param-value> UTF-8 </param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
三、response中文乱码
 
在网上很有效的解决方法是添加:
response.setCharacterEncoding("UTF-8");
解决不了,后来又搜到一条解决方法是:
respnse.setHeader("content-type","text/html;charset=UTF-8");
两句都填上,后来终于解决了这个问题;
  
问题1:
 
我们这里先来说明一下错误的原因,下图是显示乱码的流程图:

 
response.setContentType("text/html;charset=UTF-8");  目的是为了控制浏览器的行为,即控制浏览器用UTF-8进行解码;
response.setCharacterEncoding("UTF-8"); 的 目的是用于response.getWriter()输出的字符流的乱码问题,如果是response.getOutputStream()是不需要此种解决方案的;因为这句话的意思是为了将response对象中的数据以UTF-8解码后发向浏览器;
 
解决方案流程图:

 
问题2
问题代码如下:
[java]   view plain   copy
  1. protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {  
  2.         PrintWriter out = response.getWriter();  
  3.         String data = "博客";  
  4.         out.println(data);    
  5.     }  

浏览器输出: ??
原因 :"博客"首先被封装在response对象中,因为IE和WEB服务器之间不能传输文本,然后就通过ISO-8859-1进行编码,但是ISO-8859-1中没有“博客”的编码,因此输出“??”表示没有编码;
 
错误代码流程图:

 
  由于GET方式提交的任何数据在服务器端一定会以ISO-8859-1的方式进行解码,所以服务器端可以先按ISO-8859-1的方式获取字节数组,在将该数组转变成UTF-8对应的字符串形式

  1. String username = request.getParameter(“username”);
  2. username = new String(username.getBytes(“iso-8859-1),“UTF-8);
而解决方案是:response.setCharacterEncoding("GB2312"); 设置response使用的码表
 
解决方案流程图:
 

 
补充:通过<meta>标签模拟response头;
<meta http-equiv="content-type" content="text/html"/> 等价于 response.setContentType("text/html");
 
四、request乱码问题
 
request请求分为post和get,对于不同的请求方式有不同的解决乱码的方案;
 
1.post请求乱码
 
错误原因:

 
解决方案:

 
2.get请求乱码
 

 
一 找出问题的根源
   乱码可能出现的地方:1 jsp页面中 
                       2 jsp页面之间相互传参的参数
                       3 与数据库中数据的存取
   基本归纳为以上几种。

二 寻找解决方案
   1 出现在jsp页面中,是由于没有设置jsp页面的中文字符编码。
   2 出现在jsp页面之间相互传参,是由于参数没有设置正确的字符编码。
   3 以上2个问题解决了,那么存到数据库中,自然就不存在乱码。除非你对存入到数据库里的数据再次进行编码。 
三解决方法:  
1的解决方法 
<%   @ page contentType   =   "   text/html;charset=gb2312   "       %>  
加上这句解决jsp页面中的中文乱码显示,tomcat编译完后向客户端输出的html文件不是采

用中文编码,所以会导致乱码产生。

2的解决方法
2.1   <%   request.setCharacterEncoding(   "   gb2312   "   );   %>  
加上这句解决jsp页面中的中文参数传递乱码。
因为 浏览器默认使用的编码是“UTF-8” 发送请求参数。
我们把它改为"gb2312"就ok了。

2.2 String(request.getParameter("name").getBytes("ISO8859_1"),"GB2312");
这句的意思是,把传来的参数全部编码转换成gb2312,这样做的缺点是每次传来一个参数

都要这样写,很麻烦。

同样可通过设置server.xml配置文件来实现。
<   Connector
port   ="8080"                  maxHttpHeaderSize   ="8192"  
               maxThreads   ="150"    minSpareThreads   ="25"    maxSpareThreads   ="75"  
               enableLookups   ="false"    redirectPort   ="8443"    acceptCount   ="100"  
               connectionTimeout   ="20000"    disableUploadTimeout   ="true"      URIEncoding   ="gb2312"  />  
但是这样就应用到整个webapp中去了。

另:  <%   @page pageEncoding   =   "   gb2312   "   %>  
此句是为了让jsp编译器能正确地解码含有中文字符的jsp页面。

其它方法还可以修改web.xml文件,配置一个过滤器。其原理都一样,只是换种方式而已。
有的书上专门写了一个函数来解决乱码,实际上对比一下就知道那种解决方法的好与坏。
回过头来一看,解决乱码也不过如此。
ok,实际就加上这3句搞定问题。
<%   @page pageEncoding   =   "   gb2312   "   %>  
<%   @ page contentType   =   "   text/html;charset=gb2312   "       %>  
<%   request.setCharacterEncoding(   "   gb2312   "   );   %>  
 
servlet有关乱码
其它方法还可以修改web.xml文件,配置一个过滤器。其原理都一样,只是换种方式而已。
有的书上专门写了一个函数来解决乱码,实际上对比一下就知道那种解决方法的好与坏。
回过头来一看,解决乱码也不过如此。
ok,实际就加上这3句搞定问题。
<%   @page pageEncoding   =   "   gb2312   "   %>  
<%   @ page contentType   =   "   text/html;charset=gb2312   "       %>  
<%   request.setCharacterEncoding(   "   gb2312   "   );   %>  
 
servlet有关乱码
 
 
今天在部署一个webservices程序的时候,从页面获取数据的servlet出现了乱码问题,在servlet中我已经把request.setCharacterEncoding("GB2312");这段文字加入到代码中去,但是还是出现乱麻问题。
 到网上找资料,如下:JAVA是Unicode编码,你先转换成ISO8859-1,然后再转换成GBK或是GB2312.
   
java 代码
  1. request.setCharacterEncoding("ISO8859-1");    
  2. ad=request.getParameter("name");    
  3. byte[] temp3 = ad.getBytes("GBK");    
  4. String str = new String(temp3);   

这样就是中文啦! 
还有一种更简单的方法,就是直接在服务器里设置编码转换。用的是TOMCAT5.0.28。 
在..\Tomcat   5.0\conf目录里找到SERVER.XML文件,用写字板打开它,设置如下: 
里面增加一个属性就可以了,URIEncoding="GBK"
测试通过,搞定, 然后就是request.setCharacterEncoding("GB2312")这句话到底起了什么作用,如果它不能解决乱麻问题,我们用它来起什么作用, 整理资料如下:
    (一) JSP页面上是中文,但是看的是后是乱码:
解决的办法就是在JSP页面的编码的地方,因为Jsp转成Java文件时的编码问题,默认的话有的服务器是ISO-8859-1,如果一个JSP中直接输入了中文,Jsp把它当作 ISO8859-1来处理是肯定有问题的,这一点,我们可以通过查看Jasper所生成的Java中间文件来确认

(二) 当用Request对象获取客户提交的汉字代码的时候,会出现乱码:
解决的办法是:要配置一个filter,也就是一个Servelet的过滤器,代码如下:
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain)throws IOException, ServletException {

request.setCharacterEncoding("GBK");

// 传递控制到下一个过滤器
chain.doFilter(request, response);
}
配置web.xml
<filter></filter>
<filter-name></filter-name>Set Character Encoding
<filter-class></filter-class>SetCharacterEncodingFilter

<filter-mapping></filter-mapping>
<filter-name></filter-name>Set Character Encoding
<url-pattern></url-pattern>/*

如果你的还是出现这种情况的话你就往下看看是不是你出现了第四中情况,你的Form提交的数据是不是用get提交的,一般来说用post提交的话是没有问题的,如果是的话,你就看看第四中解决的办法。
 
还有就是对含有汉字字符的信息进行处理,处理的代码是:
public String toUni(String gbStr){
String uniStr = "";
if(gbStr == null){
gbStr = "";
}
try{
byte[] tempByte = gbStr.getBytes("GB2312");
uniStr = new String(tempByte,"ISO8859_1");
}catch(Exception ex){
}
return uniStr;
}
}
你也可以在直接的转换,首先你将获取的字符串用ISO-8859-1进行编码,然后将这个编码存放到一个字节数组中,然后将这个数组转化成字符串对象就可以了,例如:
String str=request.getParameter(“girl”);
Byte B[]=str.getBytes(“ISO-8859-1”);
Str=new String(B);
通过上述转换的话,提交的任何信息都能正确的显示。
(三)  在Formget请求在服务端用request. getParameter(“name”)时返回的是乱码;按tomcat的做法设置Filter也没有用或者用 request.setCharacterEncoding("GBK");也不管用问题是出在处理参数传递的方法上 :如果在servlet中用 doGet(HttpServletRequest request, HttpServletResponse response)方法进行处理的话前面即使是写了:
request.setCharacterEncoding("GBK");
response.setContentType("text/html;charset=GBK");
也是不起作用的,返回的中文还是乱码!!!如果把这个函数改成doPost(HttpServletRequest request, HttpServletResponse response)一切就OK了。
同样,在用两个JSP页面处理表单输入之所以能显示中文是因为用的是post方法传递的,改成get方法依旧不行。
由此可见在servlet中用doGet()方法或是在JSP中用get方法进行处理要注意。这毕竟涉及到要通过浏览器传递参数信息,很有可能引起常用字符集的冲突或是不匹配。
// 这个地方理解为request.setCharacterEncoding("GBK");set的是request中的body,而不是header部分,get请求时把参数放在url后边,不是放在body中,所以这个时候request.setCharacterEncoding("GBK")就没有起到作用,换到post提交就没有问题了,经测试通过 ,

解决的办法是:
1) 打开tomcat的server.xml文件,找到区块,加入如下一行:
URIEncoding=”GBK”
完整的应如下:
<connector uriencoding="GBK" maxthreads="150" debug="0" redirectport="8443" port="8080" enablelookups="false" maxsparethreads="75" minsparethreads="25" connectiontimeout="20000" disableuploadtimeout="true" acceptcount="100"></connector>

2)重启tomcat,一切OK。
tomact.org给的解释
This specifies the character encoding used to decode the URI bytes, after %xx decoding the URL. If not specified, ISO-8859-1 will be used. 也就是说转换了URI的bytes,request.setCharacterEncoding("GBK")把request也转换了,问题就ok了!

(四) JSP页面上有中文,按钮上面也有中文,但是通过服务器查看页面的时候出现乱码:
解决的办法是:首先在JSP文件中不应该直接包含本地化的消息文本,而是应该通过<bean:message>标签从Resource Bundle中获得文本。应该把你的中文文本放到Application.properties文件中,这个文件放在WEB-INF/classes/* 下,例如我在页面里有姓名,年龄两个label,我首先就是要建一个Application.properties,里面的内容应该是name=”姓名” age=”年龄”,然后我把这个文件放到WEB-INF/classes/properties/下,接下来根据 Application.properties文件,对他进行编码转化,创建一个中文资源文件,假定名字是 Application_cn.properties。在JDK中提供了native2ascii命令,他能够实现字符编码的转换。在DOS环境中找到你放置Application.properties的这个文件的目录,在DOS环境中执行一下命令,将生成按GBK编码的中文资源文件 Application_cn.properties:native2ascii ?encoding gbk Application.properties Application_cn.properties执行以上命令以后将生成如下内容的Application_cn.properties文件: name=u59d3u540d age=u5e74u9f84,在Struts-config.xml中配置:<message-resources parameter="properties.Application_cn"></message-resources>。到这一步,基本上完成了一大半,接着你就要在JSP页面上写 ,到名字的那个label是要写<bean:message key="”name”">,这样的化在页面上出现的时候就会出现中文的姓名,年龄这个也是一样,按钮上汉字的处理也是同样的。
(五) 写入到数据库是乱码:
解决的方法:要配置一个filter,也就是一个Servelet的过滤器,代码如同第二种时候一样。
如果你是通过JDBC直接链接数据库的时候,配置的代码如下:jdbc:mysql://localhost:3306/workshopdb? useUnicode=true&characterEncoding=GBK,这样保证到数据库中的代码是不是乱码。
如果你是通过数据源链接的化你不能按照这样的写法了,首先你就要写在配置文件中,在tomcat 5.0.19中配置数据源的地方是在C:Tomcat 5.0confCatalinalocalhost这个下面,我建立的工程是workshop,放置的目录是webapp下面,workshop.xml 的配置文件如下:


<context debug="0" path="/workshop" docbase="workshop"></context>reloadable="true" >

<resource name="jdbc/WorkshopDB"></resource>auth="Container"
type="javax.sql.DataSource" />

<resourceparams name="jdbc/WorkshopDB"></resourceparams>
<parameter></parameter> 
<name></name>factory
<value></value>org.apache.commons.dbcp.BasicDataSourceFactory

<parameter></parameter> 
<name></name>maxActive
<value></value>100

<parameter></parameter> 
<name></name>maxIdle
<value></value>30



<parameter></parameter> 
<name></name>maxWait
<value></value>10000


<parameter></parameter> 
<name></name>username
<value></value>root

<parameter></parameter> 
<name></name>password
<value></value>



<parameter></parameter> 
<name></name>driverClassName
<value></value>com.mysql.jdbc.Driver

<parameter></parameter> 
<name></name>url
<value></value>




粗体的地方要特别的注意,和JDBC直接链接的时候是有区别的,如果你是配置正确的化,当你输入中文的时候到数据库中就是中文了,有一点要注意的是你在显示数据的页面也是要用这行代码的。需要注意的是有的前台的人员在写代码的是后用Dreamver写的,写了一个Form的时候把他改成了一个jsp,这样有一个地方要注意了,那就是在Dreamver中Action的提交方式是request的,你需要把他该过来,因为在jsp的提交的过程中紧紧就是POST和 GET两种方式,但是这两种方式提交的代码在编码方面还是有很大不同的,这个在后面的地方进行说明。</bean:message></bean:message>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值