一、出现乱码的原因
首先看一张图:
微观——字符在保存时的编码格式如果和要显示的解码格式不一致的话,就会出现乱码。 (注:上图左侧如一个终端是freemarker模板文件,一个终端是java应用程序,如果freemarker在传输过程中编码字符集与java应用程序针对传输数据的解码字符集不同的话,就会出现乱码现象)
宏观——Web应用中,从底层数据库编码、Web应用程序编码到视图编码,如果有一项不一致的话,就会出现乱码。
再看看下边这张图:
说明(从JVM内部和外部看待字符编码问题):
1、Java文件编译后形成class文件:
这里Java文件的编码可能有多种多样,但Java编译器会自动将这些编码按照Java文件的编码格式正确读取后产生class文件,这里的class文件编码是Unicode编码(具体说是UTF-16编码)。不管在编译前java文件使用何种编码,在编译后成class后,他们都是一样的——Unicode编码表示。
2、JVM中的编码:
JVM加载class文件读取时候使用Unicode编码方式正确读取class文件。
3、内存中字符串的编码:
内存中的字符串不仅仅局限于从class代码中直接加载而来的字符串,还有一些字符串是从文本文件中读取的,还有的是通过数据库读取的,还有可能是从字节数组构建的,然而他们基本上都不是Unicode编码的,原因很简单,存储优化。因此就需要处理各种各样的编码问题,在处理之前,必须明确“源”的编码,然后用指定的编码方式正确读取到内存中。
小结:由此看来,java应用程序(具体说是JVM)内部具有一定的编码转换机制,或者说它具有一定的编码容错能力。
紧接着,我们从整体(从View、DB、Java文件、class文件)去看待字符编码,如下图:
看好最初两张图,再看这个图就很简单了,只不过多了两点:
其一,class文件在保存过程中是用UTF编码格式存储,常用UTF-16格式,因为UTF-16比起UTF-8,好处在于大部分字符都以固定长度的字节 (2字节) 储存,但UTF-16却无法兼容于ASCII编码。
其二,JVM与操作系统的交互同样存在编码问题,默认情况下,中文Windows操作系统采用GBK编码,而Linux默认采用ISO8859-1编码。如果中文web应用项目部署在Linux系统时,要进行有效编码设置。
二、解决乱码最好方式
明确指定整个应用系统统一字符集——UTF-8最优
原因:
其一,兼容所有(字符)语言(具体来说这是Unicode编码的优点),即包括全世界常用文字,提高了字符间的转换性,满足跨语言、跨平台进行文本转换、处理的要求。
其二、兼容ISO8859-1
UTF-8兼容ISO8859-1,对于大多数常用字符集(ASCII中0-127字符)它只使用单字节,而对于其它常用字符,它使用3字节(如大部分的中文字符),因为web应用程序中,以英文字符传输及显示最多,针对英文字符采用单字节格式传输,而UTF-16采用双字节传输。明显,UTF-8能减少传输成本。
操作:找到应用系统的所有出入口,使用UTF-8去“结扎”它(全部配置编码格式为UTF-8)