又遇JAVA中文乱码“坑”

本文介绍了一种在Java Web项目中遇到的中文乱码问题及其解决方法。问题出现在从数据库读取并展示文本模板时,数据库使用BLOB类型存储字节码。通过对编码流程的深入分析,最终确定乱码是由编码不一致导致,并给出了解决方案。
摘要由CSDN通过智能技术生成

前言

对于中文乱码的问题,我一向是比较害怕的,因为,,,一直都没搞明白过,但是,最近在调试公司一个项目,遇到了一个“奇怪”的中文乱码的 问题,花了一个晚上,终于搞明白了。为了避免以后再次踩坑,也希望能帮到遇到同样困境的童鞋,所以在此简单记录一下。

问题描述

问题的背景大概是这样,这是一个JAVA WEB项目,有一个需求是提供一种文本的模板,用户可以编辑,保存。考虑到文本内容特别长,我们数据库中使用BLOB类型来存储文本数据,它对应的JAVA的byte[]。一次,我在本地(Windows)启动服务调试代码,然后浏览器编辑上传了一个模板,我预览的时候,居然中文乱码了,乱码了!!!要知道,这个功能之前在服务器一直是正常运行,没有发生过乱码的问题。

解决过程

怎么办?其实我可以不管这个问题的,反正服务器是好的嘛!但是,以我的性格,这种问题一定要搞清楚我心里才安心。
首先,我想到的是,检查数据库原始的文本是否乱码。我通过Navicat工具去数据库里复制出来那段文本,能正常显示中文,只是在浏览器预览的时候乱码了。
看来,是程序读的时候出的问题。我在检查读取这段文本代码的时候发现,后台做了一个本地文件缓存,先将模板先写入本地文件,然后直接读取文件内容,下面是缓存文件。
这里写图片描述
这里写图片描述
通过上面代码可以发现,这里原封不动的把数据库读出来的字节码写入到了文件。就说明,数据库的数据和文件的数据是完全相同的,这个时候,我习惯性的检查了缓存文件的编码格式,WTF,居然是ANSI

这就让我很不解了,明明DB里面的默认编码格式是UTF-8,为什么写入文件就变成了ANSI呢?

这里值得注意的一点是,明明写入文件的时候用的是字节流,按道理来说跟字符集没有关系的,只有使用字符流的时候才会涉及字符编码问题。 按照这个逻辑的话,除非存入数据库里面的字节码有问题,但是我从数据库复制出来查看明明是没有问题的啊,为什么会有这样的矛盾呢?
带着这个疑问,我决定跟踪一下存入数据库的步骤。

首先,我确认了从浏览器HTTP传到后台接收的字符串变量vm中是没有问题的。

然后,我发现了这样一段代码
这里写图片描述
原来,从Stringbyte[]的转化过程,使用了

vm.getBytes();

跟踪进去查看源码发现,调用了系统默认的字符集来实现从stringbyte[]的编码。
这里写图片描述
而我Windows默认正好是ANSI,也就是GBK的编码。乱码原因很有可能就是因为encode的时候使用的是GBK而decode的时候使用的是UTF-8(decode的时候是根据数据库指定的编码,经过证实,就是UTF-8),两种编码不匹配。

为了验证这个猜想,我更改tomcat了的一个参数
这里写图片描述
重新启动tomcat,再次尝试提交模板,果然,这时候默认的字符集编码变成了UTF-8,再次预览的时候,乱码消失,搞定!

解决方案

其实上面的方法只是我用来验证这个猜想的,至于解决方案,我还是采取了保险一点办法,在String转化成byte[]的时候,指定UTF-8,毕竟,谁能保证服务器上的默认字符集一定是UTF-8呢?

vm.getBytes("UTF-8");

===========分割线================

好气哦,这么一个小BUG折腾我半天,其实,这还没有结束。不知道胖友们注意到一个坑没有。在之前我一直相信数据库的数据没有问题,你看,数据库默认utf-8字符集,vm的内容复制出来看也没有乱码,可是,这到底是哪里不对呢?
其实,仔细一想,这个问题还真的不难解释。

  • 首先,blob字段是存的字节码,这根本不关乎数据库的字符集;
  • 其次,之所以我的Navicat读取的vm数据没有乱码,这其实是一个错误的巧合。存入数据库的时候使用的是我本机的默认字符集编码,而解析的时候,Navicat把读取到的字节码转化成人能够理解的字符,也使用的我本机默认的字符集,这样使用同样字符集encode和decode正好没有出现乱码。
  • 上面这条解释其实也印证了为什么之前模板的数据用Navicat查看是有乱码的。
    这里写图片描述

===========分割线================

PS:以上,有什么的问题,欢迎提问,或者有什么错误的地方,也欢迎赐教 !

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值