原文: http://gsdhaiji-cai.iteye.com/blog/1148049html
【01编码】——好久好久之前,为了表示二极管的通、分,咱们引入的高电平、低电平,以后又引入的一、0编码进行代替java
【ASCII编码】——好久之前,也就是上个世纪60年代,美国佬为了把计算机的“0101010”编码与文字进行对应起来,制定了一套ASCII编码方案。人老是自私的,他只对本身的语言进行编码,26个字母、数字、其余符号,只用了7位二进制数搞定,第一位用0表示,预留着。因此ASCII编码最多127编码mysql
【“二代”ASCII编码】——不仅仅是美国佬想把计算机语言和英文联系起来,其余国家也想把本身的语言关联起来,我法文、俄文就基于ASCII编码,利用上ASCII第一位(未使用)变成1,来对本身国家的语言进行编码。linux
介样,每个国家都基于ASCII,让第一位变成1,完成对本国的语言的编码。因为他们各干各的,没有沟通,从而致使了同一种编码出现不一样的文字。程序员
【gb2312编码】——咱们伟大的祖国80年代也开始对汉字进行编码,因为咱们的文字较多,即便是基于ASCII将第一位变成1,也不够咱们使用(国语博大精深拉),因此就制定了一套gb2312编码,使用2个字节表示。web
【BIG5编码】——我国的港澳地区,他们是使用繁体字(gb2312编码最初并无考虑到繁体字),怎么办了?他们就出了本身的区域编码BIG5ajax
【中国一统GBK编码】——为了统一汉字,迫切的须要设计出一种既能支持简体字又能表示繁体的新编码方案,GBK诞生了!他兼容了绝大部分gb2312编码(gb2312编码的文字用gbk能够读出来,可是不兼容BIG5编码)sql
【世界大统unicode编码】——各国编码各作各的,总不是意见好事,为了便于交流,国际社会引入了unicode——(uni统一的意思,code编码)把全部国家的文字都进行了编码。数据库
【统一后浪费空间问题】——统一是一件好事,可是也是有问题的。英文只要1个字节ASCII编码就能够表示,你unicode还须要2个字节或更多,致使unicode表示英文的时候前面有不少无用的000000000000000000,对吧。编程
【解决问题,UTF编码】——解决方法是使用utf8编码,它是基于unicode编码上的一种优化,英文使用1个字节,中文使用二、3个(绝大部分是3个,个别有看到二、4个的通常不用)字节。好处:我能屈能伸,我能够变化长度来保存,就不会浪费空间了吧。
来看看unicode和utf对应吧
<!--[if !supportLists]-->· <!--[endif]-->0000 0000-0000 007F | 0xxxxxxx
<!--[if !supportLists]-->· <!--[endif]-->0000 0080-0000 07FF | 110xxxxx 10xxxxxx
<!--[if !supportLists]-->· <!--[endif]-->0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
<!--[if !supportLists]-->· <!--[endif]-->0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
举例说明:
“汉”字的Unicode编码是0x6C49。0x6C49在0x0800-0xFFFF之间,使用用3字节模板了:1110xxxx 10xxxxxx 10xxxxxx。将0x6C49写成二进制是:0110 1100 0100 1001,用这个比特流依次代替模板后面的x,获得:11100110 10110001 10001001,十六进制E6 B1 89,转换成10进制就是230 这个就是咱们的UTF8编码,"汉".getBytes("utf-8") 获得-26 -79 -119,是负数,也是跟这里有关
汉 Unicode utf8
0x6c49 0xe6b189
从源文件àclass文件过程当中的转码状况。最终的class文件都是以unicode编码的,咱们前面所作的工做就是把各类不一样的编码转换为unicode编码,好比从GBK转换为unicode,从UTF-8转换为unicode。由于只有采用正确的编码来转码才能保证不出现乱码。Jvm在运行时其内部都是采用unicode编码的,其实在输出时,又会作一次编码的转换。
好比:Sysout.out.println(“咱们”)。通过正确的解码后”咱们”是unicode保存在内存中的,可是在向标准输出(控制台)输出时,jvm又作了一次转码,它会采用操做系统默认编码(中文操做系统是GBK),将内存中的unicode编码转换为GBK编码,而后输出到控制台。
参考文献:http://www.blogjava.net/zhangchao/archive/2011/05/26/351051.html
通常咱们是经过getBytes来进行编码,以下
public byte[] getBytes(String charsetName) //使用规定的编码
public byte[] getBytes(Charset charset) //使用规定的编码
public byte[] getBytes() //使用启动JVM设置的编码(若是没有设置通常是系统默认编码),避免使用,默认编码和平台有关
通常咱们经过new String来进行解码,以下
public String(byte bytes[], String charsetName)
public String(byte bytes[], Charset charset)
public String(byte bytes[])
原则1:使用某一种编码集对文字进行编码,就得使用同一种编码集进行解码
好比:“汉”是在java文件中的,此java文件是utf-8或者gbk编码的
getBytes使用utf-8编码,new String使用utf-8解密
new String("汉".getBytes("utf-8"), "utf-8"));
原则2:看清楚对方给你的是什么编码,使用逆过程进行编码、解码(像出栈操做),最终获得你想要文字
好比:对方进行了以下操做,将“汉”进行utf-8编码,而后使用iso8859-1进行解码生成对应的文字:,最后经过文本发送给你。对方可能的操做应该是:
String x = new String("汉".getBytes("utf-8"), "iso8859-1");
咱们须要对文本中文字x:进行iso8859-1编码,获得的是“汉”utf-8的译码,而后咱们在对“汉”进行解码获得其utf8的文字
new String(x.getBytes("iso8859-1"),"utf-8"));
原则3:慎用getBytes(),他是基于平台的,你得看看JVM启动的时候file.encoding这个属性值究竟是什么(请注意tomcat的启动JVM时候设置的编码)
源码:特别注意黄底部分
staticbyte[] encode(char[] ca, int off, int len) {
String csn = Charset.defaultCharset().name();
try {
return encode(csn, ca, off, len);
} catch (UnsupportedEncodingException x) {
warnUnsupportedCharset(csn);
}
try {
return encode("ISO-8859-1", ca, off, len);
} catch (UnsupportedEncodingException x) {
// If this code is hit during VM initialization, MessageUtils is
// the only way we will be able to get any kind of error message.
MessageUtils.err("ISO-8859-1 charset not available: "
+ x.toString());
// If we can not find ISO-8859-1 (a required encoding) then things
// are seriously wrong with the installation.
System.exit(1);
returnnull;
}
publicstatic Charset defaultCharset() {
if (defaultCharset == null) {
synchronized (Charset.class) {
java.security.PrivilegedAction pa =
new GetPropertyAction("file.encoding");
String csn = (String)AccessController.doPrivileged(pa);
Charset cs = lookup(csn);
if (cs != null)
defaultCharset = cs;
else
defaultCharset = forName("UTF-8");
}
}
return defaultCharset;
}
}
-Dfile.encoding解释:
在命令行中输入java,在给出的提示中会出现-D的说明:
-D<name>=<value>
set a system property
-D后面须要跟一个键值对,做用是经过命令行向java虚拟机传递一项系统属性
对-Dfile.encoding=UTF-8来讲就是设置系统属性file.encoding为UTF-8
在java.nio.charset包中的Charset.java中。这段话的意思说的很明确了,简单说就是默认字符集是在java虚拟机启动时决定的,后面没法动态改变了。默认字符集就是从file.encoding这个属性中获取的。
Java's file.encoding property on Windows platform
This property is used for the default encoding in Java, all readers and writers would default to using this property. file.encoding is set to the default locale of Windows operationg system since Java 1.4.2. System.getProperty("file.encoding") can be used to access this property. Code such as System.setProperty("file.encoding", "UTF-8") can be used to change this property. However, the default encoding can be not changed dynamically even this property can be changed. So the conclusion is that the default encoding can't change after JVM starts. java -dfile.encoding=UTF-8 can be used to set the default encoding when starting a JVM. I have searched for this option Java official documentation. But I can't find it.
参考文献:http://www.cnblogs.com/vigarbuaa/archive/2012/04/11/2442582.html
1、url编码规范
通常来讲,URL只能使用英文字母、阿拉伯数字和某些标点符号,不能使用其余文字和符号。好比,世界上有英文字母的网址“http://www.abc.com”,可是没有希腊字母的网址“http://www.aβγ.com”(读做阿尔法-贝塔-伽玛.com)。这是由于网络标准RFC 1738作了硬性规定:
"...Only alphanumerics [0-9a-zA-Z], the special characters "$-_.+!*'()," [not including the quotes - ed], and reserved characters used for their reserved purposes may be used unencoded within a URL."
“只有字母和数字[0-9a-zA-Z]、一些特殊符号“$-_.+!*'(),”[不包括双引号]、以及某些保留字,才能够不通过编码直接用于URL。”
这意味着,若是URL中有汉字,就必须编码后使用。可是麻烦的是,RFC 1738没有规定具体的编码方法,而是交给应用程序(浏览器)本身决定。这致使“URL编码”成为了一个混乱的领域。
参考文献:http://www.ruanyifeng.com/blog/2010/02/url_encoding.html
下面就让咱们看看,“URL编码”到底有多混乱。我会依次分析四种不一样的状况,在每一种状况中,浏览器的URL编码方法都不同。把它们的差别解释清楚以后,我再说如何用Javascript找到一个统一的编码方法。
2、状况1:网址路径中包含汉字
打开IE(我用的是8.0版),输入网址“http://zh.wikipedia.org/wiki/春节”。注意,“春节”这两个字此时是网址路径的一部分。
查看HTTP请求的头信息,会发现IE实际查询的网址是“http://zh.wikipedia.org/wiki/%E6%98%A5%E8%8A%82”。也就是说,IE自动将“春节”编码成了“%E6%98%A5%E8%8A%82”。
咱们知道,“春”和“节”的utf-8编码分别是“E6 98 A5”和“E8 8A 82”,所以,“%E6%98%A5%E8%8A%82”就是按照顺序,在每一个字节前加上%而获得的。(具体的转码方法,请参考我写的《字符编码笔记》。)
在Firefox中测试,也获得了一样的结果。因此,结论1就是,网址路径的编码,用的是utf-8编码。
3、状况2:查询字符串包含汉字
在IE中输入网址“http://www.baidu.com/s?wd=春节”。注意,“春节”这两个字此时属于查询字符串,不属于网址路径,不要与状况1混淆。
查看HTTP请求的头信息,会发现IE将“春节”转化成了一个乱码。
切换到十六进制方式,才能清楚地看到,“春节”被转成了“B4 BA BD DA”。
咱们知道,“春”和“节”的GB2312编码(个人操做系统“Windows XP”中文版的默认编码)分别是“B4 BA”和“BD DA”。所以,IE实际上就是将查询字符串,以GB2312编码的格式发送出去。
Firefox的处理方法,略有不一样。它发送的HTTP Head是“wd=%B4%BA%BD%DA”。也就是说,一样采用GB2312编码,可是在每一个字节前加上了%。
因此,结论2就是,查询字符串的编码,用的是操做系统的默认编码。(我使用谷歌浏览器,他会是使用utf-8编码的)
4、状况3:Get方法生成的URL包含汉字
前面说的是直接输入网址的状况,可是更常见的状况是,在已打开的网页上,直接用Get或Post方法发出HTTP请求。
根据台湾中兴大学吕瑞麟老师的试验,这时的编码方法由网页的编码决定,也就是由HTML源码中字符集的设定决定。
<meta http-equiv="Content-Type" content="text/html;charset=xxxx">
若是上面这一行最后的charset是UTF-8,则URL就以UTF-8编码;若是是GB2312,URL就以GB2312编码。
举例来讲,百度是GB2312编码,Google是UTF-8编码。所以,从它们的搜索框中搜索同一个词“春节”,生成的查询字符串是不同的。
百度生成的是%B4%BA%BD%DA,这是GB2312编码。
Google生成的是%E6%98%A5%E8%8A%82,这是UTF-8编码。
因此,结论3就是,GET和POST方法的编码,用的是网页的编码。
参考文献:http://www.ruanyifeng.com/blog/2010/02/url_encoding.html
5、状况4:Ajax调用的URL包含汉字
前面三种状况都是由浏览器发出HTTP请求,最后一种状况则是由Javascript生成HTTP请求,也就是Ajax调用。仍是根据吕瑞麟老师的文章,在这种状况下,IE和Firefox的处理方式彻底不同。
举例来讲,有这样两行代码:
url = url + "?q=" +document.myform.elements[0].value; // 假定用户在表单中提交的值是“春节”这两个字
http_request.open('GET', url, true);
那么,不管网页使用什么字符集,IE传送给服务器的老是“q=%B4%BA%BD%DA”,而Firefox传送给服务器的老是“q=%E6%98%A5%E8%8A%82”。也就是说,在Ajax调用中,IE老是采用GB2312编码(操做系统的默认编码),而Firefox老是采用utf-8编码。这就是咱们的结论4。
6、Javascript函数:escape()
好了,到此为止,四种状况都说完了。
假定前面你都看懂了,那么此时你应该会感到很头痛。由于,实在太混乱了。不一样的操做系统、不一样的浏览器、不一样的网页字符集,将致使彻底不一样的编码结果。若是程序员要把每一种结果都考虑进去,是否是太恐怖了?有没有办法,可以保证客户端只用一种编码方法向服务器发出请求?
回答是有的,就是使用Javascript先对URL编码,而后再向服务器提交,不要给浏览器插手的机会。由于Javascript的输出老是一致的,因此就保证了服务器获得的数据是格式统一的。
Javascript语言用于编码的函数,一共有三个,最古老的一个就是escape()。虽然这个函数如今已经不提倡使用了,可是因为历史缘由,不少地方还在使用它,因此有必要先从它讲起。
实际上,escape()不能直接用于URL编码,它的真正做用是返回一个字符的Unicode编码值。好比“春节”的返回结果是%u6625%u8282,也就是说在Unicode字符集中,“春”是第6625个(十六进制)字符,“节”是第8282个(十六进制)字符。
它的具体规则是,除了ASCII字母、数字、标点符号“@ * _ + - . /”之外,对其余全部字符进行编码。在\u0000到\u00ff之间的符号被转成%xx的形式,其他符号被转成%uxxxx的形式。对应的解码函数是unescape()。
因此,“Hello World”的escape()编码就是“Hello%20World”。由于空格的Unicode值是20(十六进制)。
还有两个地方须要注意。
首先,不管网页的原始编码是什么,一旦被Javascript编码,就都变为unicode字符。也就是说,Javascipt函数的输入和输出,默认都是Unicode字符。这一点对下面两个函数也适用。
其次,escape()不对“+”编码。可是咱们知道,网页在提交表单的时候,若是有空格,则会被转化为+字符。服务器处理数据的时候,会把+号处理成空格。因此,使用的时候要当心。
7、Javascript函数:encodeURI()
encodeURI()是Javascript中真正用来对URL编码的函数。
它着眼于对整个URL进行编码,所以除了常见的符号之外,对其余一些在网址中有特殊含义的符号“; / ? : @ & = + $ , #”,也不进行编码。编码后,它输出符号的utf-8形式,而且在每一个字节前加上%。
它对应的解码函数是decodeURI()。
须要注意的是,它不对单引号'编码。
8、Javascript函数:encodeURIComponent()
最后一个Javascript编码函数是encodeURIComponent()。与encodeURI()的区别是,它用于对URL的组成部分进行个别编码,而不用于对整个URL进行编码。
所以,“; / ? : @ & = + $ , #”,这些在encodeURI()中不被编码的符号,在encodeURIComponent()中通通会被编码。至于具体的编码方法,二者是同样。
它对应的解码函数是decodeURIComponent()。
参考文献:http://www.ruanyifeng.com/blog/2010/02/url_encoding.html
在第二节中,说道:慎用getBytes(),他是基于平台的,tomcat中JVM启动的时候file.encoding这个属性值究竟是什么,由谁决定?
Linux修改catalina.sh文件
JAVA_OPTS=”-server -Dfile.encoding=GBK -Xms=512m -Xmx1024m -XX:PermSize=128m -XX:MaxPermSize=256m -verbose:gc -Xloggc:${CATALINA_HOME}/logs/gc.log`date +%Y-%m-%d-%H-%M` -XX:+UseConcMarkSweepGC -XX:+CMSIncrementalMode -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -noclassgc”
若是你像上面这样告诉JVM,启动我tomcat容器的时候,使用GBK来编码,后续的getBytes返回的就是GBK编码的东西,这点特别在部署的tomcat的时候注意。
get提交的tomcat从4.x以后不是使用request.setCharacterEncoding("字符集"),从这里获取,它直接使用直接对参数进行编码,这个编码他是从tomcat的配置文件中获取<Connector port="8080" protocol="HTTP/1.1" maxThreads="150" connectionTimeout="20000" redirectPort="8443" URIEncoding="UTF-8"/>
对于post须要在web.xml里面配置拦截器,主要是在程序第一次从request里面获取参数以前把request给设定了具体的编码
publicvoid doFilter(ServletRequest req, ServletResponse resp,FilterChain chain)throws IOException, ServletException {
req.setCharacterEncoding(encoding);//这里是过滤器,直接设置编码
HttpServletRequest request = (HttpServletRequest)req;
HttpServletResponse response = (HttpServletResponse)resp;
ActionContext.setContext(request, response);
chain.doFilter(req,resp);
ActionContext.removeContext();
}
还有一点须要注意的是:你在web.xml里面配置过滤器的优先级是否是最高,必定要在request出现以前拦截。
你还记得jsp页面中有下面这句话么?pageEncoding="utf-8"告诉tomcat,你编译我jsp文件的时候使用他来编译,若是这句话没有,他默认使用charset=utf-8"这句话来编译,同时注意保存jsp的时候使用编码也应该与pageEncoding="utf-8"保持一致
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
你还记得下面这句话么?由他来告诉浏览器使用什么编码的
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
须要以root用户身份登录才能够查看数据库编码方式(以root用户身份登录的命令为:
>mysql -u root –p,以后两次输入root用户的密码),查看数据库的编码方式命令为:
>show variables like 'character%';
+--------------------------+----------------------------+
| Variable_name | Value |
+--------------------------+----------------------------+
| character_set_client | latin1 |
| character_set_connection | latin1 |
| character_set_database | latin1 |
| character_set_filesystem | binary |
| character_set_results | latin1 |
| character_set_server | latin1 |
| character_set_system | utf8 |
| character_sets_dir | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
从以上信息可知数据库的编码为latin1,须要修改成gbk或者是utf8;
其中,character_set_client为客户端编码方式;character_set_connection为创建链接使用的编码;character_set_database数据库的编码;
character_set_results结果集的编码;
character_set_server数据库服务器的编码;
只要保证以上四个采用的编码方式同样,就不会出现乱码问题。
中止MySQL的运行
/etc/init.d/mysql start (stop) 为启动和中止服务器
MySQL主配置文件为my.cnf,通常目录为/etc/mysql
var/lib/mysql/ 放置的是数据库表文件夹,这里的mysql至关于windows下mysql的date文件夹
当咱们须要修改MySQL数据库的默认编码时,须要编辑my.cnf文件进行编码修改,在linux下修改mysql的配置文件my.cnf,文件位置默认/etc/my.cnf文件
找到客户端配置[client] 在下面添加
default-character-set=utf8 默认字符集为utf8
在找到[mysqld] 添加
default-character-set=utf8 默认字符集为utf8
init_connect='SET NAMES utf8' (设定链接mysql数据库时使用utf8编码,以让mysql数据库为utf8运行)
Mysql经过客户端发送到控制台展现以前是utf8,可是console是使用系统的默认编码(gbk),因此在中文的时候发生了乱码显示,可是不影响程序操做,只是显示的时候有问题。
如何解决了?
方法一:(只对当前窗口有用,推荐使用)
输入:set names gbk
方法二:将控制台展现编码改为utf8(对全部的窗口,不推荐)
一、打开CMD.exe命令行窗口 二、经过 chcp命令改变代码页,UTF-8的代码页为65001 F:\trash>chcp 65001执行该操做后,代码页就被变成UTF-8了。可是,在窗口中仍旧不能正确显示UTF-8字符。 三、修改窗口属性,改变字体 在命令行标题栏上点击右键,选择"属性"->"字体",将字体修改成True Type字体"Lucida Console",而后点击肯定将属性应用到当前窗口。 四、经过以上操做并不能彻底解决问题,由于显示出来的内容有可能不彻底。能够先最小化,而后最大化命令行窗口,文件的内容就完整的显示出来了。