在开发中,总会碰到各种中文乱码问题,下面稍作总结。
1、数据库的乱码
出现乱码问题,我们第一反应应该是:是否数据库字符编码设置有问题。以mysql为例,装好mysql后进入安装目录,打开my.ini配置文件查看mysql设置的编码。在my.ini中有两处设置字符编码的地方,分别是[mysql]下的default-character-set及[mysqld]下的default-character-set。熟悉linux的朋友都知道以d结尾的表示服务端,如你想那样,[mysql]设置的字符编码是客户端的,[mysqld]设置的字符编码是mysql服务器端的编码。我们的数据就是存储在mysql服务器端的,为了能存下任何字符编码的数据,我们一般设置[mysqld]下的default-character-set=utf8(注意,不是utf-8)。代表客户端的[mysql]下的default-character-set应该怎么设置呢,一般朋友可能也设置成utf8,这可能会出问题的。如果这样设置的话,当我们"运行cmd"打开DOS窗口,通过"mysql -uroot -p123"命令进入mysql的客户端后,我们是不能插入中文的。道理很简单,这是因为我们的操作系统的字符编码是GBK(或GBK兼容),我们在DOS窗口输入的中文(如:insert into test values('中文'))自然也是GBK的,而我们[mysql]设置的却是utf8,因为不兼容所以会出错。当然,如果我们使用相关mysql的GUI客户端工具,进行相关设置,即使[mysql]设置成utf8也没问题。但如果通过DOS窗口登陆mysql客户端时,一般要设置[mysql]下的default-character-set=GBK。
总结:[mysql]下default-character-set=GBK,[mysqld]下default-character-set=utf8
2、使用GET请求的乱码
如果一个请求是GET方式时,比如<a href="url">标签指定的请求如form表单以GET方式提交,我们可以在浏览器地址栏上看到类似http://localhost/proj/a.do?title=%C4%E3%BA%C3 这样的URL。像这样2个(%加上2位16进制数)表示一个中文,这是用ISO8859-1(即lantin1)进行的编码。对于这样用GET请求的URL中的中文字符,我们是不能通过设置request.setCharacterEncoding("UTF-8")来解决的。
解决方法有两种:
第一种方法是用 title = new String(title.getBytes("ISO8859-1"), "UTF-8"); 来对每个有中文的请求参数进行解码再编码,这种方法比较繁琐;
第二种方法是修改tomcat的server.xml配置文件,把<Connector port="8080" ...>修改成 <Connector port="8080" ... URLEncoding="UTF-8">,即在<Connector>元素中指定其URLEncoding="UTF-8",其默认值为lantin1。这属性指定了URL的编码,设置成UTF-8后,地址栏上就不会再出现 a.do?title=%C4%E3%BA%C3 之类的内容了,而是 a.do?title=中文 。
这种方法的缺点是,其它项目或该项目其它地方可能会因为修改而引入了新的中文编码问题,比如使用这种方法之后,有些地方使用了第一种方法处理好了的中文将会再次变成乱码。这种方法不常用,可能牵一发而动全身。
3、使用POST请求的乱码
对于form表单以POST提交的请求,可以用request.setCharacterEncoding("UTF-8")来解决。至于为什么这种方法对POST请求有效而对GET请求无效,请参考HTTP协议中GET与POST请求的差别,简单来讲就是GET请求的内容放在请求头里,POST请求是放在请求体来。一般来讲我们可以通过给项目增加一个字符集过滤器来一次性解决POST请求的中文乱码。过滤器里的内容非常简单,就是调用request.setCharacterEncoding(encoding),encoding是我们要设置的字符集。过滤器可以自己编写,也可以使用spring提供的org.springframework.web.filter.CharacterEncodingFilter。
综上所述我们在中文乱码这个问题上,一般的做法如下:
a、编码集用UTF-8而不是GBK
b、给我们的应用加上一个字符集过滤器
c、所有的Form表单都以POST进行提交
d、用链接<a href="a.do?name=中文">进行的提交,最好用new String(title.getBytes("ISO8859-1"), "UTF-8")来解决而不是修改tomcat的配置文件
------------------------------------------------
这段时间做网站又再次的碰到了老掉牙的中文乱码问题,实在是揪心啊,感觉一点进步都没有,每次解决了下次又出现了。这次下定决心想授人以渔而不是鱼了。
解决这个问题的万金油当然是按照乱码从生成到结束的整个过程着手分析,以下是流程分析:
- 源头在数据库,首先你要保证你在数据库中搜出来的结果不是乱码;如果是乱码,那么必然你数据库的字符集没有改为需要的中文字符集,例如mysql,这时候较为简单只需要在my.ini或my.cnf中改下就可以了;
- 这个时候,servlet容器访问数据库,把字符读取过来,那么第二个就是jdbc驱动了,这步一般不会有问题,经验上告诉我也没有碰到过啥问题;
- 如果用持久层框架的话,例如ibatis,就要小心它那边有没有对从数据库里取出来的东西转码的可能了,取出来本来是中文正常的,结果ibatis用啥latin1一转又出问题了。如果问题出在这里,有个比较容易的调试办法,就是打日志,这种持久层框架一般都可以在debug级别打出真正和数据库交互的sql语句,同样也会打出从数据库拿到以后的字符,如果这时字符时乱码,说明问题在这里出现了,需要改对应持久层框架的字符编码方式了;
- 服务器端渲染层,例如你如果使用velocity的话,就需要对输出的内容进行渲染,而渲染的时候,velocity也有可能改变你的编码,将原本好好的utf8改成万恶的latin1。而原本自带的apache-velocity确实是默认为英文环境的,所以如果你不把velocity.properties文件加到对应的WEB-INF/下,那么显示出来的永远是乱码;
- 浏览器端渲染层,这个也是网上说的最多的,如果浏览器端这边都不是以中文编码显示的话,前面各部分所做的任何努力都付诸流水了。即:<meta http-equiv =Content-Type content ="text/html; charset=utf8" >
现在终于知道为什么字符集问题困扰了这么多人,主要是他出错的机会实在是太高了,以上的这5条完全只是本人经验,随着应用的复杂,中文乱码问题出错的几率会更大,谁叫我们的技术比别人落后呢,规范都被他们定去了。