首先声明,以下内容不一定正确,但是合理:
今天在写一个Web项目时用get方式携带着一些中文参数发送到服务器,服务器接收,验证合理性,然后插入数据库
整个过程中产生了几次乱码现象,一开始很是费解,尝试各种网上的解决方案无果后开始自己思考和测试,发现了一些端倪,故做个记录,也请看这个帖子的人讨论一下其正确性。
首先从get方法的URL中接收中文参数,然后在接收端直接获取后输出的话产生了第一次乱码现象,这个原因是
URL提交过来是按照ISO-8859-1编码方式编码的,一开始误以为URL的编码方式可以用URLEncoder去设置,其实URLDecoder做的只是表面上的工作,而并非修改了机器底层存储的0和1,所谓表面工作,就好比,“你”这个字用符号$1代替(这里只是随便举个例子)然后在服务器端用URLDecoder把字面上的$1还原回"你",有点像在字面上进行了加密解密工作,其实实际上这些中文字还是以ISO-8859-1编码提交到了tomcat,假设“你”这个字以ISO-8859-1编码存储在底层的数据是0101,当Tomcat接收到了0101后把他用String
s封装起来,这个时候如果你打印system.out.println(s)时就有可能出现乱码,究其原因是因为,你的本地默认编码不是ISO-8859-1,这样的话Java会把0101显示为按照本机默认编码所对应的那个符号,通过cmd chcp命令可以查看本机默认编码,我的机器是GBK,假如在GBK中0101代表“@”符号的话,这时候你打印出来的就是@,所以如果你想打印的时候不出现乱码,可以通过String s = new String(s.getBytes("ISO-8859-1"),"本机默认编码方式"),将编码进行一下转换后再输出,这样“你”这个字就会从ISO-8859-1的0101转化成本机默认编码所对应的那个01序列,比如在GBK下“你”对应1010,那么这时候s在底层的存储就从0101变成了1010,有时候你可能还会发现如果你进行这样的转化也可以得到正确的中文输出:String(s.getBytes("ISO-8859-1"),"GB2312")(假设本机编码为GBK),这是因为GB2312是GBK的子集,GBK是GB2312的扩充版,所以这样做虽然大部分时候是正确的,但是当遇到GBK中包含而GB2312中不包含的字符时,显示就会出错。
然后我把这个乱码问题解决了后将数据写入数据库当中,再从MySql的命令行select一下发现又乱码了,原因是我的数据库jdbc:mysql://127.0.0.1:3306/open_push?characterEncoding=UTF-8导致的,因为上一步我已经将编码转化为了GBK,然后我却告诉数据库我给你的数据是UTF-8编码的(假如数据库中表存放数据是按照GB2312存放的),这样数据库就会以为你给他的汉字是UTF-8的编码方式而不是GBK,他在将你给他的汉字转化成GB2312编码方式的时候就是去查询的UTF-8转GB2312的编码转化表而不是GBK转GB2312的编码转化表,这样就造成了转码错误,自然显示的数据就不会正确了,所以你要不想出现乱码问题就必须老老实实的告诉数据库你给他的数据是按照什么编码方式来编码的,这就是设置characterEncoding的作用,假如你给的编码是GBK,你就需要设置characterEncoding=GBK,假如你给的是UTF-8就设置characterEncoding=UTF-8,这时候你可能会发现你在数据库的命令行中select的一下还是出现了乱码,你会惊奇我明明告诉了数据库我给你的是UTF-8编码了呀,为什么还给我展示的是乱码,我猜想这可能不能怪数据库,因为数据库确确实实是按照UTF-8给你存储的数据,只不过你select出来以后,命令行展示给你看这个过程采用的还是你的本地默认编码GBK,所以就导致了select出来的显示的是乱码,如果你修改一下你机器的默认编码方式为UTF-8的话,显示的结果就会是正确的。