关于java字符编码的理解

字符是各种文字和符号的总称,包括各个国家文字、标点符号、图形符号、数字等。字符集是多个字符的集合,字符集种类较多,每个字符集包含的字符个数不同,常见字符集有:ASCII字符集、ISO 8859字符集、GB2312字符集、BIG5字符集、GB18030字符集、Unicode字符集等。计算机要准确的处理各种字符集文字,需要进行字符编码,以便计算机能够识别和存储各种文字。如Unicode字符集可依不同需要以UTF-8、UTF-16、UTF-32等方式编码。

编码和字符集不同。字符集只是字符的集合,不一定适合作网络传送、处理,有时须经编码后才能应用。对于一个字符集来说要正确编码转码一个字符需要三个关键元素:字库表、编码字符集、字符编码。字库表是一个相当于所有可读或者可显示字符的数据库,字库表决定了整个字符集能够展现表示的所有字符的范围。编码字符集,即用一个编码值来表示一个字符在字库中的位置。字符编码,将编码字符集和实际存储数值之间的转换关系。

 

正确使用字符串的getBytes方法

         java提供了将String转化为byte[]的几种方法,具体说明如下:

        

         不带参数的方法使用平台的默认字符集,另外两个方法都是按照指定字符集获取字节数组,window下默认的字符集是GBK,验证方式如下:

         进入cmd --> 点击标题栏右键 --> 属性 --> 选项 --> 当前代码页

         

         Linux下,输入:echo $LANG进行验证(默认是UTF-8)

        

         当调用无参getBytes()方法时,实际上先获取默认字符集Charset.defaultCharset(),然后根据该字符集进行获取字节数组;为了实现更加灵活的控制,java引入了file.encoding属性,JVM启动之前如果未指定file.encoding这个属性,这个属性就会默认为操作系统编码方式, JVM启动如果指定了file.encoding这个属性,整个项目都会用这个属性(file.encoding在运行时设置无效)。

 

         下面使用一个简单的测试例子来说明

                  

        

        

         通过上面的了解,无参的getBytes方法会存在很多不确定性,会与预期的不一致,所以不要使用缺省的方法,应当根据约定的编码方式进行转换处理。

        

java的URL编码和解码

        

javascript的URL编码和解码

         encodeURI()

         ecodeURI()

Javascript中真正用来对URL编码的函数。对整个URL进行编码,因此除了常见的符号以外,对其他一些在网址中有特殊含义的符号“; / ? : @ & = + $ , #”,也不进行编码。编码后,它输出符号的UTF-8形式,并且在每个字节前加上%

         encodeURIComponent()

         decodeURIComponent()

它用于对URL的组成部分进行个别编码,而不用于对整个URL进行编码。在encodeURI()中不被编码的符号,在encodeURIComponent()中统统会被编码。至于具体的编码方法,两者是一样

         在web应用中,经常会出现乱码问题,本质上是由于编码不一致导致,下面对Form表单的POST提交方式进行分析

         

         为了避免出现乱码,需要保存编码一致

         String nameB = request.getParameter("name");

         String nameA = new String(nameB.getBytes("编码B"),"编码A");//还原为发送请求真实的编码

         1、文档编码(网页右键 --> 编码)

           

         决定文档编码主要来自文件的描述

         JSP:<%@ page language="java" contentType="text/html; charset=GBK" pageEncoding="GBK"%>

    HTML:<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

   

    JSP示例(GBK编码):

                   name对应的值“立思辰”进行了双字节转码(GBK)%C1%A2%CB%BC%B3%BD

                  

    HTML示例(UTF-8编码):

                   name对应的值“立思辰”进行了三字节转码(UTF-8)%E7%AB%8B%E6%80%9D%E8%BE%B0

                 

         2、服务器解码

            tomcat中,如果未指定character encoding ,则默认使用ISO-8859-1 

            上述JSP 表单提交时,通过从ISO-8859-1GBK转换即可

             String nameISO = request.getParameter("name");

        String nameGBK = new String(nameISO.getBytes("ISO-8859-1"),"GBK");

                  

                   上述HTML 表单提交时,通过从ISO-8859-1UTF-8转换即可

            String nameISO = request.getParameter("name");

        String nameUTF8 = new String(nameISO.getBytes("ISO-8859-1"),"UTF-8");

       

                   在实际应用中,为了避免每次获取参数都进行转码,有以下几种方式

                   A、在每个servlet/JSP中设置request.setCharacterEncoding(String charEncoding)

            JSP示例(GBK编码):

                                     request.setCharacterEncoding("GBK");

                                     String nameGBK = request.getParameter("name");

            HTML示例(UTF-8编码):

                                     request.setCharacterEncoding("UTF-8");

                                     String nameUTF8 = request.getParameter("name");

           

        B、设置统一的过滤器设置request.setCharacterEncoding(String charEncoding)

                      通过过滤器统一设置字符编码(不需要在每个文件中进行设置)

                           

                            Servlet中只要直接获取参数值String nameGBK = request.getParameter("name");

这种方式,也是目前比较流行的处理方式,项目使用约定好的字符编码,前后保持一致,对于特殊的servlet/jsp 可以在开始位置进行重置request.setCharacterEncoding

                  

         form表单的提交get方式

        

        

         地址栏效果,等价与在浏览器地址栏输入地址访问,对应的值按照GBK进行编码

        

         第一个语句打印乱码,第二个能正常显示

 

 

         ajax提交

        

         相应的servlet自动按照UTF-8进行解析

         

         当第一次执行request.getParameter() 进行参数解析,优先解析Url参数,再解析body部分

         决定body解析编码的依次是:

         1、是否设置request.setCharacterEncoding()

         2、是否设置header 中Content-type 对应的charset

         3、以上都没设置,默认ISO-8859-1

         决定url解析编码:

         1、server.xml 设置URIEncoding

                  

                   这样对于上面模拟的form get提交方式就能正常获取参数值

         2、server.xml 设置useBodyEncodingForURI="true"

                  

                   这种方式需要在调用前进行设置request.setCharacterEncoding()

         3、server.xml 设置URIEncoding和useBodyEncodingForURI

                  

设置useBodyEncodingForURI为true时,如果未进行setCharacterEncoding则使用URIEncoding对应的编码进行解析,若设置了CharacterEncoding,这按照设定的字符编码值进行解析

         4、上述都未设置,则使用默认编码(ISO-8859-1)进行解析

 

         在前后交互时需要避免UTF8和GBK之间的相互转码

         前台:

                 

         后台:

                 

         输出:

                  

         引起这种现象的本质原因在于两个字符集特点所引发的,一个汉字UTF-8是3个字节,GBK则是2个字节。