前言
乱码问题已经遇到过好几次了,都是依靠搜索引擎碰运气解决问题,今天正好空下来,把以前搜集的几篇博客好好看了一下,对于乱码问题有点拨开云雾见青天的感觉。
这篇随笔只是个人用来做个小笔记的,写的不会很清楚,要想知道细节的强烈推荐看下面这两篇博客:
文件乱码原因概述
1. 缺少字体库
表现:出现字符用方框表示
解决:安装合适的字体库
2. 编码问题
表现:用问号表示字符
解决:编码的时候设置编码集,在Java中,一般是输出的时候使用的是字节流(FileOutPutStream)而不是字符流(Writter)
3. 解码问题
表现:出现奇怪的字符串
解决:解码的时候,用Reader进行解码,并设置编码集(默认会依赖JVM的系统环境,默认是 file.encoding 属性)
WEB乱码原因概述
1. Post 请求,不论是浏览器端还是服务器点,解码编码格式都由 Header中的 ContentType(“text/html; charset=utf-8″) 指定,所以只要不漏写,都不会有问题。
唯一的风险在于请求发送过程中,中间的代理器会不会修改这个值(一般不会有人去改)。
2. GET 请求,get 请求的URL 中的 PathInfo 和 QueryString 字符串的编码和解码是由浏览器和应用服务器的配置决定(Tomcat 服务器一般在 server.xml 中设定的,pathInfo 部分进行解码的字符集是在 connector 的 中定义的;QueryString 的解码字符集一般通过 useBodyEncodingForURI 设定,如果没有设定,Tomcat8 之前的版本默认使用的是 ISO-8859-1,但是 Tomcat 8 默认使用的是 UTF-8),所以在我们的程序中最好不要在 URL 中直接使用非 ASCII 字符,如果一定要用,就用 encodeURI() 进行编码。
3. Header 只支持 ASCII 字符集,将不在 ASCII 字符集内中的其他字符全部编码为 3F 即问号?,解决办法就是对中文文件名使用 url 编码后 URLEncoder.encode(filename,charset)再放到 Header 中。
protected voiddoGet(HttpServletRequest request, HttpServletResponse
response)throwsServletException, IOException {
String fileName= getDecodeParameter(request,"fileName");
String userName= getDecodeParameter(request, "username");
response.setHeader("Content-Disposition", "attachment; filename=\"" +URLEncoder.encode(fileName,"utf-8") + "\";userName=\"" +URLEncoder.encode(userName,"utf-8") + "\"");
}
另一种Header乱码处理思路,文件名用ASCII格式编码(这种方式需要浏览器支持,如果使用postman调试依旧是乱码):
//采用中文文件名需要在此处转码, 因为 Header 固定采用ASCII格式编码
response.setHeader("Content-Disposition","attachment;filename=" + MimeUtility.encodeWord(biFile.getName()));
MYSQL乱码原因概述
1. 数据库各层级间的编码格式不一致,需要转换代码格式,然后出错
排查方向:用问号代替字符
排查与修复可能使用的SQL:
# MySQL的系统变量(字符集相关的系统变量)
show variableslike 'character_set%';
# 查看当前MySQL版本支持的字符集
show charset;
showcharacter set;
# 查看MySQL数据库的字符集
show variableslike 'character_set_database';
showcreate database dbname; #--dbname为你要查看的数据库。
#查看MySQL表的字符集
showcreate tablexxxx;
##---------- 修改字符集
# 1:修改MySQL字段的字符集
# 修改字段的字符集语法如下所示,当然,成功的修改字符集是有限制的,具体参考10.1.7 Column Character SetConversion,修改前最好做好备份,充分测试。ALTER TABLE xxx MODIFY xxx VARCHAR(50) CHARACTER SETUTF8;
#2. 修改MySQL表的字符集alter table class charset=gbk;alter table class character setUTF8mb4;
#注意:上面命令只修改表的字符集,影响后续该表新增列的默认定义,已有列的字符集不受影响。
#同时修改表字符集和已有列字符集,并将已有数据进行字符集编码转换。可以使用类似下面脚本。alter table class convert to character setUTF8mb4;
#3. 修改MySQL数据库字符集
# 注意:只修改库的字符集,影响后续创建的表的默认定义;对于已创建的表的字符集不受影响。alter database database_name character setxxx;
#4:修改系统变量character_set_databaseset character_set_database=utf8mb4;set global character_set_database=utf8mb4;
#5:修改MySQL服务器字符集set global character_set_server=utf8mb4;
#6. 另外,SET NAMES 'charset_name' [COLLATE 'collation_name'] 相当于SET character_set_client = charset_name; SET character_set_results = charset_name; SET character_set_connection =charset_name;set names 'utf8mb4';
2. 输入的字符当前编码格式不支持,例如 mojo 表情和复杂繁体中文,需要使用 UTF8mb4
表现:字符不对应,例如应该是表情,展示的却是繁体字
修复:同上
MySLQ排序规则特征:
两个不同的字符集不能有相同的校对规则;
每个字符集有一个默认校对规则;
存在校对规则命名约定:以其相关的字符集名开始,中间包括一个语言名,并且以_ci(大小写不敏感)、_cs(大小写敏感)或_bin(二元)结束。