内容概要:
1.数据库乱码
2.控制台乱码
3.html网页乱码
4.下载文件文件名乱码
准备工作
1.查询"中国"的编码表:常见的中文编码表有GBK
和UTF-8
GBK编码:-42 -48 -71 -6
UTF-8编码:-28 -72 -83 -27 -101 -67
UTF-8字节码用ISO-8859-1解码的结果:ä¸å›½
GBK字节码用ISO-8859-1解码的结果:Öйú
2.建数据库
数据库结构
Field Type Null Key Default Extra
-------- ------------ ------ ------ ------- --------
uid varchar(32) NO PRI (NULL)
username varchar(100) YES UNI (NULL)
password varchar(100) YES (NULL)
email varchar(100) YES (NULL)
name varchar(100) YES (NULL)
sex varchar(10) YES (NULL)
3. 制作带<form action="/day15_test/RegisterServlet" method="post">
表单的html
网页,提交表单到Servlet
中,Servlet
获取表单信息写入数据库。
数据库乱码
- 现象:提交表单,使用
QueryRunner
向表格添加数据,中文内容乱码,显示西欧字符
QueryRunner qr = new QueryRunner(C3p0Utils.getDataSource());
String name = request.getParameter("name");
int row = qr.update("insert into user values(uid,username,password,email,name,sex)");
图片.png
显然乱码字符是由“中国”的
UTF-8
字节码用ISO-8859-1
解码的结果。
- 分析
- 可能原因1:数据库内部编码设置错误,查询mysql的默认字符集,查看安装目录下的
my.ini
文件,ctrl+f
查找default-character-set
是否为utf8
,如果不是改成utf8
;经过查找,是utf8
字符集,没有问题 - 可能原因2:请求对象使用的是
UTF-8
字符集编码,但是服务器使用ISO-8859-1
解码,服务器与数据库之间通过字符流传递数据,所以出现西欧乱码,只需将请求对象添加编码信息,要求服务器使用UTF-8
解码即可:
request.setCharacterEncoding("UTF-8");
显示结果
控制台乱码
- 现象:控制台打印表单录入的信息出现乱码
String name = request.getParameter("name");
System.out.println(username + " " + password + " " + email + " " + name + " " + sex);
显示结果:
- 原因分析
请求对象使用的是UTF-8
编码,而服务器用ISO-8859-1
解码,结果中文不能正常显示 - 解决办法
- 分析1:从浏览器获取
UTF-8
编码的内容,传输到服务器后,通过ISO-8859-1
解码西欧字符(但是内部字节码没有发生变化),再通过字符流传输到eclipse
的控制台,eclipse
用UTF-8
解码(个人习惯设置),自然都是问号了;
这个流至始至终没有变的就是底层的字节码,所以只需用ISO-8859-1
解码,在用UTF-8
重新编码就可以了。
String name = request.getParameter("name");
name = new String(name.getBytes("ISO-8859-1"), "UTF-8");
图片.png
2.分析2:将浏览器的编码信息通过请求头传递给服务器,让服务器使用
UTF-8
编码
request.setCharacterEncoding("UTF-8");
图片.png
html网页乱码
- 现象:
response.getWriter().write("<font color='green'>登录成功!</font>");
输出在页面上的出现问号
显示结果:
图片.png - 原因分析
服务器默认编码集是ISO-8859-1
,浏览器默认编码是GBK
,传入浏览器后,浏览器解码错误,出现问号。 - 解决方法
-
解决办法1:
把响应对象用GBK
编码,传到浏览器,浏览器用默认字符集解码
response.setCharacterEncoding("GBK");
显示结果:
-
解决办法2:
将响应对象用UTF-8
编码,并且通知浏览器使用UTF-8
解码:
如果只设置响应对象使用UTF-8
编码(3个字节),使用GBK
解码(2个字节)页面会多一些字符
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
显示结果:
解决办法3:
直接通知浏览器使用
UTF-8
字符集解码即可
response.setContentType("text/html;charset=UTF-8");
显示结果:
下载文件中文乱码
- 现象:制作一个下载超链接
<a href="/day15_test/DownLoadServlet?filename=你好.rar">你好.rar</a>
下载文件,当有中文是,文件名不显示。
DownLoadServlet
源码
String filename = request.getParameter("filename");
filename = new String(filename.getBytes("ISO-8859-1"), "UTF-8");
//强制下载
response.setContentType(this.getServletContext().getMimeType("/resource/" + filename));
response.setHeader("Content-Disposition", "attachment; filename =" + filename);
//下载本质就是io流
InputStream is = this.getServletContext().getResourceAsStream("/resource/" + filename);
OutputStream os = response.getOutputStream();
byte[] b = new byte[1024 * 8];
int len = 0;
while((len = is.read(b)) != -1) {
os.write(b, 0, len);
}
os.flush();is.close();os.close();
图片.png
- 原因分析
- 通过
String filename = request.getParameter("filename");
获取文件全名,然后System.out.println(filename);
在控制台上输出乱码,具体原因请参考本文第二条控制台乱码原因。 -
response.setContentType()
获取文件的拓展名,文件拓展名都是西欧字符,不会产生乱码。 -
response.setHeader("Content-Disposition", "attachment; filename =" + filename);
这条代码意思是将文件名传到浏览器,服务器默认将filename.getBytes("ISO-8859-1")
解码发到服务器,而filename
是UTF-8
编码的,发送到服务器自然会乱码。 -
InputStream is = this.getServletContext().getResourceAsStream("/resource/" + filename);
;filename
已经解码成UTF-8
,而且没有外传,不会发生乱码现象。
- 解决办法
办法1:
将filename
用UTF-8
解码,在用ISO-8859-1
编码,服务器将filename
用ISO-8859-1
解码,发送到浏览器,浏览器在使用UTF-8
解码。
String filenameDownlaod = new String(filename.getBytes("UTF-8"), "ISO-8859-1");
InputStream is = this.getServletContext().getResourceAsStream("/resource/" + filenameDownlaod);
办法2:
上一个方法显然很绕,宗旨就是服务器传给浏览器能看懂的字节码,那么String filename = request.getParameter("filename");
获取到的filename
就是浏览器传过来的,自然能看懂了,在解决本地乱码问题时String newFilename = new String(filename.getBytes("ISO-8859-1"), "UTF-8");
新定义一个文件名用于本地,发给浏览器用filename
,自然就解决乱码问题了。完整代码如下
String filename = request.getParameter("filename");
String newFilename = new String(filename.getBytes("ISO-8859-1"), "UTF-8");
response.setContentType(this.getServletContext().getMimeType("/resource/" + newFilename));
response.setHeader("Content-Disposition", "attachment; filename =" + filename);
InputStream is = this.getServletContext().getResourceAsStream("/resource/" + newFilename);
OutputStream os = response.getOutputStream();
byte[] b = new byte[1024 * 8];
int len = 0;
while((len = is.read(b)) != -1) {
os.write(b, 0, len);
}
os.flush();is.close();os.close();
显示结果
小结
- 解决中文乱码主旨就是解码表和编码表一致;
- 本文只说明
post
方式乱码的情况,get
方式没有讨论,其实可以使用控制台乱码的解决办法; - 还遇到一个问题暂时没有解决,留待以后...
以下两个方法单独出现都能够正常显示跳转页面信息,但是同时出现时出现乱码现象:
response.getWriter().write(request.getMethod());
request.getRequestDispatcher("FailToRegist.html").forward(request, response);
而下面的两个方法同时出现不出现乱码,疑惑?字节流与字符流的关系
response.getOutputStream().write(request.getMethod().getBytes());
request.getRequestDispatcher("FailToRegist.html").forward(request, response)
- 参考Servlet 中文乱码问题及解决方案剖析(博客园-xiazdong);
- 其实乱码问题有一劳永逸的方法,暂不讨论。
网友评论