这个学期我们开了JSP课,让我们最头痛的一件事就是中文字符乱码的问题,虽然老师也给讲了,但是本人资质愚钝,依然没懂,希望能有学长指点一二,在这里谢谢了。问题是这个样子:
1
OutputStream  out=response.getOutputStream();
        out1.write("中国".getBytes());
当我用字节流向浏览器输出中文时,居然没有乱码,记得老师说过,servlet 默认指定的字符集是iso8859-1
我用的是IE浏览器,据老师讲,凡是支持中文的浏览器,都支持gb2312,那么,当我向浏览器输出汉字的话,它应该乱码才对,但是没有。我想知道为什么。
2
        PrintWriter out = response.getWriter();
out.write("中国"); 
当我用字符流向浏览器输出中国时,它果断乱码了,我搞不明白,为什么 字节流不会乱码,而字符流就乱码了。
求大神指教,谢谢了。

解决方案 »

  1.   

    看看tomcat这段源码public ServletOutputStream getOutputStream() throws IOException
    {
    stream = createOutputStream();///创建response的2进制的输出流
    return stream;
    }public PrintWriter getWriter() throws IOException
    {
    ResponseStream newStream = (ResponseStream)createOutputStream();////////创建2进制流
    OutputStreamWriter osr = new OutputStreamWriter(newStream, getCharacterEncoding());
    writer = new ResponseWriter(osr, newStream);///得到response的字符输出流
    }public String getCharacterEncoding()//////response的编码,默认是ISO-8859-1的
    {
    if(encoding == null)//////////////////////////////////如果没有指定编码
    {
    return "ISO-8859-1";
    } else
    {
    return encoding;
    }
    }public void setContentType(String type);设置response的类型和编码
    {
    encoding = RequestUtil.parseCharacterEncoding(type);////////得到指定的编码
    if(encoding == null)
    {
    encoding = "ISO-8859-1";//////////////////////////如果沒有指定编码方式
    }
     else{
    contentType = type + ";charset=" + encoding;
    }
    }
    "中国" 转编码为iso_8859_1 肯定乱麻
      

  2.   

    response.setContentType这个方法应该知道吧,是指定输出类型的,默认是text/html
    用java.net.URLEncoder类,这个是html格式网络传输文本数据时编码用的,
    text/html就会把程序里需要输出的内容利用java.net.URLEncoder解析html传输时需要的格式,
    如果你是用PrintWriter去输出的话,因为你没设定字符编码格式,
    所以默认编码格式是iso-8859-1,
    那么服务器会用URLEncoder.encode("中国", "iso-8859-1")
    就是以iso-8859-1的格式去编码字符串"中国",
    然后再把编码后的字符串发送给客户端浏览器,客户段浏览器是按照自己的编码格式,
    比如是gbk,那么就是URLDecoder.decode(接收的字符串, "gbk")解码,
    那么自然得到的就是??
    而"中国".getBytes()这个得到的是一个长度为4的byte数组,
    而且是用OutputStream直接发送的,不需要经过服务器编码,直接发送给客户浏览器,
    客户浏览器也不需要解码,类似于得到new String("中国".getBytes(),"gbk")这样的一个字符串,
    所以用outputstream输出没有出现乱码情况。
    最后,以上过程只是为了理解方便才用URLEncoder和URLDecoder,
    http网络传输协议的解码和编码真实过程要复杂很多,并不是这么简单。
      

  3.   

    简单的理解就是response.writer是以字符形式输出,需要服务器指定字符格式进行编码后再发送给客户浏览器,
    由于服务器默认字符格式是iso-8859-1,而浏览器默认字符格式为gbk,自然得到的是不正确的结果,
    response.getOutputStream是直接以低级流形式输出,不需要经过服务器编码,
    由于java内部汉字的unicode编码是和GBK的汉字编码是一样的,
    所以客户段这边能正常显示。
      

  4.   

    这个不用纠结。你们以后会学到Filter过滤器。写一个类,web.xml中配置一下。整个应用都不会再乱码了。所以不用纠结这些。
    乱码的原因:(去查同一张码表,没有乱码;查A表加密,查B表解密,当然得不到正确的密码了,自然乱码了。)编码码表==解码码表,就不会乱码。完全没必要研究这些小问题。只要知道怎么去解决乱码就行了。用过滤器就好了。
      

  5.   

    4楼说的对,但是我如果弄不明白,心里会不舒服,再碰到类似的问题心里就慌张不知所措了,还是弄明白的好。
    我把上面的代码稍微改一下,
    OutputStream  out=response.getOutputStream();
             out1.write("中国".getBytes("utf-8"));
    这样改的话肯定乱码了。
    我还有一点不明白就是三楼学长的这句话 :
    response.getOutputStream是直接以低级流形式输出,不需要经过服务器编码,
    既然低级流不需要经过服务器编码,我又指定了编码集,服务器又照做了,是不是说,服务器有个缺省的方式-对于字节流缺省编码集的情况下,服务器不会编码,如果指定了则会按指定的编码。
    不知道我这样理解对不对。
      

  6.   

    你这样理解是对的,应该说string.getBytes(),
    里面就是按java默认unicode进行编码而获得字节叔祖的。
    out.write("中国".getBytes("utf-8"));
    这个得到的流是"utf-8"编码格式的字节流,在客户端浏览器是用gbk编码格式来解码的,当然是乱码,
    如果你把浏览器编码改成utf-8那么就能正确显示了,
    如果还不能理解你可以输出下
    System.out.println(Arrays.toString("中国".getBytes("utf-8")));
    System.out.println(Arrays.toString("中国".getBytes("gbk")));
    System.out.println(Arrays.toString("中国".getBytes()));
    你会发现"中国".getBytes()其实和"中国".getBytes("gbk")是相等的。
      

  7.   

    不是服务器默认的编码格式,而是是string.getBytes()这个应该是按照java(api里是指平台)默认的编码格式得到的字节数组
    java api里面的
    getBytes
    public byte[] getBytes()使用平台的默认字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。 
    所以你getBytes这步就已经获得了指定编码的字节数组了。
      

  8.   

    据老师说,tomcat服务器是一个纯java编写的服务器,也就是说,tomcat是运行在java虚拟机里的吧?那么一个web应用中普通的java类也和tomcat是运行在一个虚拟机中的吗?他们之间的关系是什么样子的?求指教。
      

  9.   

    哦 。我明白了。谢谢各位。我明白自己最大的错误时在哪了。出了问题没去看API.学到了很多。谢谢各位。