Servlet常见乱码及解决办法

内容概要:

1.数据库乱码
2.控制台乱码
3.html网页乱码
4.下载文件文件名乱码

准备工作

1.查询"中国"的编码表:常见的中文编码表有GBKUTF-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获取表单信息写入数据库。

数据库乱码

  1. 现象:提交表单,使用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)");
复制代码

显然乱码字符是由“中国”的 UTF-8字节码用 ISO-8859-1解码的结果。 2. 分析

  1. 可能原因1:数据库内部编码设置错误,查询mysql的默认字符集,查看安装目录下的my.ini文件,ctrl+f查找default-character-set是否为utf8,如果不是改成utf8;经过查找,是utf8字符集,没有问题
  2. 可能原因2:请求对象使用的是UTF-8字符集编码,但是服务器使用ISO-8859-1解码,服务器与数据库之间通过字符流传递数据,所以出现西欧乱码,只需将请求对象添加编码信息,要求服务器使用UTF-8解码即可:
request.setCharacterEncoding("UTF-8");
复制代码

显示结果

控制台乱码

  1. 现象:控制台打印表单录入的信息出现乱码
String name = request.getParameter("name");
System.out.println(username + " " + password + " " + email + " " + name + " " + sex);
复制代码

显示结果:

2. 原因分析 请求对象使用的是 UTF-8编码,而服务器用 ISO-8859-1解码,结果中文不能正常显示 3. 解决办法

  1. 分析1:从浏览器获取UTF-8编码的内容,传输到服务器后,通过ISO-8859-1解码西欧字符(但是内部字节码没有发生变化),再通过字符流传输到eclipse的控制台,eclipseUTF-8解码(个人习惯设置),自然都是问号了; 这个流至始至终没有变的就是底层的字节码,所以只需用ISO-8859-1解码,在用UTF-8重新编码就可以了。
String name = request.getParameter("name");
name = new String(name.getBytes("ISO-8859-1"), "UTF-8");
复制代码

2.分析2:将浏览器的编码信息通过请求头传递给服务器,让服务器使用 UTF-8编码

request.setCharacterEncoding("UTF-8");
复制代码

html网页乱码

  1. 现象: response.getWriter().write("<font color='green'>登录成功!</font>");输出在页面上的出现问号 显示结果:
  2. 原因分析 服务器默认编码集是ISO-8859-1,浏览器默认编码是GBK,传入浏览器后,浏览器解码错误,出现问号。
  3. 解决方法
  • 解决办法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");
复制代码

显示结果:

下载文件中文乱码

  1. 现象:制作一个下载超链接<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();
复制代码

2. 原因分析

  • 通过String filename = request.getParameter("filename");获取文件全名,然后System.out.println(filename);在控制台上输出乱码,具体原因请参考本文第二条控制台乱码原因。
  • response.setContentType()获取文件的拓展名,文件拓展名都是西欧字符,不会产生乱码。
  • response.setHeader("Content-Disposition", "attachment; filename =" + filename);这条代码意思是将文件名传到浏览器,服务器默认将filename.getBytes("ISO-8859-1")解码发到服务器,而filenameUTF-8编码的,发送到服务器自然会乱码。
  • InputStream is = this.getServletContext().getResourceAsStream("/resource/" + filename);filename已经解码成UTF-8,而且没有外传,不会发生乱码现象。
  1. 解决办法 办法1:filenameUTF-8解码,在用ISO-8859-1编码,服务器将filenameISO-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();
复制代码

显示结果

小结

  1. 解决中文乱码主旨就是解码表和编码表一致;
  2. 本文只说明post方式乱码的情况,get方式没有讨论,其实可以使用控制台乱码的解决办法;
  3. 还遇到一个问题暂时没有解决,留待以后...
以下两个方法单独出现都能够正常显示跳转页面信息,但是同时出现时出现乱码现象:
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)
复制代码
  1. 参考Servlet 中文乱码问题及解决方案剖析(博客园-xiazdong)
  2. 其实乱码问题有一劳永逸的方法,暂不讨论。

转载于:https://juejin.im/post/5a34e6c26fb9a045211ec70e

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值