JSP乱码问题

[size=large][/size]http://panqunjun.blogcn.com/articles/jsp%e4%b9%b1%e7%a0%81%e9%97%ae%e9%a2%98-%e5%8e%9f.html


这个问题实在是JSP开发的经典!看到很多人为之困惑。
网上搜索到了很多文章,我看多不怎么正确的,因为Tomcat4和Tomcat5是不一样的。
这里我使用的是apache-tomcat-5.5.25。



乱码有三点:
1)文件流:读JSP文件,生成Servlet文件。
2)socket流:Servlet运行后,在缓存中的字符串的编码,也就是contentType编码。
3)request.getParameter()是乱码,这个是最复杂的!



执行过程:.jsp -> .java -> buffer -> flush buffer



1)文件流
.jsp -> .java
.jsp文件本身有一个文件编码格式。
然后,JSP的<%@page%>标签可以设置contentType和pageEncoding,
对应的.java设置是response.setContentType,pageEncoding可以不用写,
如果pageEncoding写的话,在将.jsp转化为.java时,是按照该编码进行解码的。
(默认情况下,contenType = null,encoding = ISO-8859-1)
response设置这个主要是最终以该编码格式的字符串写给客户端的浏览器接收到以后,
客户端浏览器会根据HTTP头部“Content-Type”自动调整浏览器的编码类型,
然后才能被正确显示。
容器在将JSP页面转化为.java代码的时候,是按照contentType和pageEncoding的信息
进行对JSP文件的解码,然后按照特定的逻辑生成的.java文件(.java文件是按照UTF-8编码的)。



所以,.jsp文件本身和它的contentType和pageEncoding编码一定要一致,否则生成的
.java文件里面就可能有乱码。
在eclipse中,根据contentType信息会自动智能的进行调整。
如果用记事本编写的话,就有可能出乱码了。



2)socket流
.java -> buffer
运行.java代码,在内存中会有一个buffer,这个buffer理解为字符串。
然后,这个buffer是通过contentType和pageEncoding的编码格式进行编码的,
这样就保证了发给客户的字符串buffer和Content-Type的编码头部是一致的。



buffer -> flush buffer
最后,服务器从内存中将字符串刷新给客户了。



3)request.getParameter()是乱码
其实,这个很简单,只是Tomcat4和Tomcat5处理是不一样的。
Tomcat4,我没有用过,但是,看了一些文章后,也让我知道是什么个意思了。
是说,Tomcat4处理get和post是一样的,默认是用iso-8859-1解码的。
所以,很多人说用Filter来设置request的编码就可以解决问题了。
而Tomcat5对get和post处理是分开了,可以说这样一来,Tomcat5的处理方法更加细致了,
它已经包含了Tomcat4的功能,但是,对我们开发人员来说,这个角落里面的一个小细节的变动
会造成很多人犯错误的。



下面一组测试,使用apache-tomcat-5.5.25测试。
   req.getParameter("name") 提交格式
get   ?(乱码    按照contentType设置的编码,每个字节用%分隔。
post   ?    同上
URL中输入中文  ?    系统默认编码



怎么才能得到中文?
get: URLEncode  先用iso-8859-1编码回去,再用contentType解码。
post: URLEncode  同上
URL: 中文  先用iso-8859-1编码回去,再用系统编码解码。



问题出在哪里?
就是客户端浏览器在做get和post提交数据的时候,浏览器是按照contentType设置编码的,每个字节用%分隔。
提交到Tomcat后,Tomcat使用iso-8859-1进行解码的,所以得到肯定是乱码。
比如,我们经常是这样处理的:
String name = req.getParameter("name");
name = new String(name.getBytes("iso-8859-1"), "utf-8"); // 先编码回去,再用utf-8解码的。



那么有没有一种能够让大家满意的解决方案呢?
当然是有的。
找到Tomcat的server.xml
然后,设置
<Connector port="8080" maxHttpHeaderSize="8192"
               maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
               enableLookups="false" redirectPort="8443" acceptCount="100"
               connectionTimeout="20000" disableUploadTimeout="true"
               URIEncoding="utf-8" useBodyEncodingForURI="true" />
解释一下:
URIEncoding="utf-8":是指定义对客户端浏览器的get请求中URI的解码。
问题是,如果只是设置了URIEncoding而没有设置useBodyEncodingForURI的话,那么只能保证get请求是可以正常
显示的。
因为,Tomcat5处理get是用URIEncoding设置的,处理post是通过设置request.setCharacterEncoding()和
useBodyEncodingForURI="true"实现的。



useBodyEncodingForURI="true":这个是和Tomcat4保持兼容用的,默认为false。
设置为true的话,就可以用过滤器进行设置request.setCharacterEncoding()编码来统一处理get和post了。




小结:
1)保证生成的Servlet代码正确。
必须保证.jsp文件和contentType和pageEncoding编码格式一致。



2)保证Servlet输出的编码正确。
必须保证.java文件里面设置的编码response.setContentType是正确的。



3)保证request.getParameter()正确。
通过设置useBodyEncodingForURI="true",再使用一个Filter设置request.setCharacterEncoding()编码。




举个例子:
修改server.xml:useBodyEncodingForURI="true"保持Tomcat4的风格(URIEncoding="utf-8"不需要的)



sample.jsp:<%@ page language="java" contentType="text/html; charset=utf-8"%>
sample.jsp本身是用UTF-8编码的,这个用eclipse是自动的。



CharsetFilter.java:设置request.setCharacterEncoding("utf-8");


SampleServlet.java:如果要输出中文的话,记得在得到PrintWriter之前,
先“resp.setContentType("text/html;charset=utf-8");”,然后,在输出。

 

你可能感兴趣的:(jsp)