美文网首页TomcatJava学习笔记程序员
Servlet常见乱码及解决办法

Servlet常见乱码及解决办法

作者: lkee6760 | 来源:发表于2017-03-01 22:55 被阅读401次

    内容概要:

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

    显示结果

    图片.png

    控制台乱码

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

    显示结果:

    图片.png
    1. 原因分析
      请求对象使用的是UTF-8编码,而服务器用ISO-8859-1解码,结果中文不能正常显示
    2. 解决办法
    3. 分析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");
    
    图片.png
    2.分析2:将浏览器的编码信息通过请求头传递给服务器,让服务器使用UTF-8编码
    request.setCharacterEncoding("UTF-8");
    

    图片.png

    html网页乱码

    1. 现象: response.getWriter().write("<font color='green'>登录成功!</font>");输出在页面上的出现问号
      显示结果:
      图片.png
    2. 原因分析
      服务器默认编码集是ISO-8859-1,浏览器默认编码是GBK,传入浏览器后,浏览器解码错误,出现问号。
    3. 解决方法
    • 解决办法1:
      把响应对象用GBK编码,传到浏览器,浏览器用默认字符集解码
    response.setCharacterEncoding("GBK");
    

    显示结果:

    图片.png
    • 解决办法2:
      将响应对象用UTF-8编码,并且通知浏览器使用UTF-8解码:
      如果只设置响应对象使用UTF-8编码(3个字节),使用GBK解码(2个字节)页面会多一些字符
    response.setCharacterEncoding("UTF-8");
    response.setContentType("text/html;charset=UTF-8");
    

    显示结果:

    图片.png
    解决办法3:
    直接通知浏览器使用UTF-8字符集解码即可
    response.setContentType("text/html;charset=UTF-8");
    

    显示结果:

    图片.png

    下载文件中文乱码

    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();
    
    图片.png
    1. 原因分析
    • 通过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();
    

    显示结果

    图片.png

    小结

    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. 其实乱码问题有一劳永逸的方法,暂不讨论。

    相关文章

      网友评论

        本文标题:Servlet常见乱码及解决办法

        本文链接:https://www.haomeiwen.com/subject/qwgcgttx.html