JSP页面编译成Servlet类文件过程中所涉及到的编码问题

当请求一个JSP页面时,一般的都需要经历下面几个阶段:

1、应用服务器根据JSP页面生成一个Java文件

2、应用服务器调用java.exe将Java文件编译成一个Servlet对应的class文件

3、用户的浏览器请求JSP对应的Servlet,Web容器起一个线程执行Servlet,将数据返回给客户端浏览器

4、用户的IE根据返回的数据,将结果显示给用户。

 

    第一步中应用服务器根据Jsp页面生成一个Java文件时,需要读取源Jsp页面到内存中,然后以某种编码方式生成Servlet类文件,这一读的过程会涉及到采用什么编码方式来读取的问题?这里先看一下结论:如页面中设置了pageEncoding="XX",则服务器在读取Jsp页面时,就会使用上面设置的XX来读取,如果没有设置,再看是否设置了contentType="text/html; charset=XXX" ,如果设置了,则用charset中指定的编码方式来读取。如果这两个都没有指定时,则使用默认的编码方式ISO8859-1来读取

以上是读取的过程,当把Jsp页面读取到内存后,在内存中以Unicode编码存在,这时需要根据Jsp文件生成Servlet类文件,既然要定文件,这里又会涉及到编码问题,这里该使用什么编码方式来输出到文件呢?先看结论:Tomcact是使用UTF-8编码方式来输出的 ,这也是理所当然的,因为页面上会有不同的各种语言。

 

 

下面来证实上面的两个结论。

 

    首先我们写一个Jsp页面gbk.jsp,从文件名就可知我们创建一个以GBK编码方式保存的Jsp文件。

下面是我创建并设置好编码方式的过程:

 

Jsp代码 复制代码
  1. <%@ page language="java" %>   
  2. <html>   
  3.     <body>   
  4.         <form name=form1 action="" method="get">   
  5.             <input type="text" name="textParam1" size="50 px" value="國a">   
  6.             <br>   
  7.             <input type="file" name="fileParam" size="50 px" value="">   
  8.             <br>   
  9.             <input type="button" value="submit" οnclick="submitForm()">   
  10.         </form>   
  11.         <script type="text/javascript">    
  12.             function submitForm(){    
  13.                 //注释   
  14.                 var str ="國a";    
  15.                 form1.action = "http://localhost:8088/gb2312rs.jsp?qryParam1=" +   
  16.                  encodeURIComponent(str) + "&qryParam2="+  encodeURIComponent(form1.textParam1.value) ;   
  17.                 form1.submit();    
  18.             }    
  19.         </script>   
  20.     </body>   
  21. </html>  

     

     

    保存后,我们开始访问一下,浏览器显示如下:

        从上图看出浏览器使用的是ISO编码方式,所以上面文本框里显示正常才怪呢~!但当我们把浏览器的编码方式换成GBK时,看是什么样,~!~#@!¥,晕~!找了半天浏览器上面根本就没有GBK这一编码方式,中文的就只有GB2312,我们就选一下GB2312试试看,如下图:


         咦~!我们选择是GB2312怎么也可显示出繁体字啊?其实浏览器中的GB2312就是用的操作系统默认的编码GBK来显示的,至于解释请看《Java中的字符集编码入门(三)GB2312,GBK与中文网页 》。好奇心没有后继续往下看。

     

        我们打开服务器帮我们生成的Servlet类文件,其中输出中文的地方代码片断如下:

     

        我们发现中文“注释”与“國”字,都变成了乱码。既我们知道了上面结论:该文件是UTF-8编码格式的,那我就以UTF-8来读读这个文件,读代码如下:

     

    Java代码 复制代码
    1. String fileName = "E:/tomcat-5.5.23/work/Catalina/localhost/HttpStream/org/apache/jsp/gbk_jsp.java";   
    2. PrintWriter pw = new PrintWriter(new OutputStreamWriter(new FileOutputStream("e:/tmp/gbk_jsp.java"), "UTF-8"));   
    3. BufferedReader br = new BufferedReader(new InputStreamReader(   
    4.         new FileInputStream(fileName), "utf-8"));   
    5. String readContent = null;   
    6. while ((readContent = br.readLine()) != null) {   
    7.     pw.write(readContent+"\r\n");   
    8.     pw.flush();                
    9. }   
    10. pw.close();  

    读出的文件片断如下:

        从上面输出的结果可以进一步证明生成的Sevlet就是UTF-8编码方式的存储的,因为这两个文件内容乱码显示的样子都是一样的。

     

        从最开始来看在浏览器中能正常显示,那说明生成的Servlet类文件真实的内容没有毁坏,不然不可能在浏览器中能正常显示的,我们要坚信这一点。那既然文件内容没有毁坏,为什么生成的Servlet类文件却显示的是乱码呢?

     

    经过我的一些分析,原因大致如下:

        服务器在读取Jsp源文件时是采用的ISO8859-1来读取的(这是因为页没有配置任何编码信息),而Jsp源文件本身却又是GBK编码的,这一读的过程为字符解码过程,且又是以ISO8859-1来解的(会把GBK编码每个字节映射到ISO8859-1字符集下,而每个字节的大小为0-255,在ISO8859-1字符集里是可以找到对应的字符来替代的),这一转换过程并不会丢失任何编码信息,只是字符的显示方式不同而已了(GBK是一个个汉字的显示,而ISO却是半个半个地显示)。

        而在读取完后放在内存里以Unicode形式存在(即ISO字符以Unicode编码存储,而非原来ISO编码,这一过程由Java完成,但ISO的编码实质上与Unicode编码是一样的,只是所占字节数不一样),再以UTF-8输出时,由于这些Unicode字符在UTF-8字符集编码里是存在的,并为上面显示的那些字符(实质上这些字符就是ISO字符集中的字符),也不会造成编码信息丢失。

     

        既然我们知道了是这样一过程:GBK文件——》以ISO8859-1来读(解码)——》以UTF-8输出(编码),那我现在还她一个眉目清秀,先以UTF-8来读生成的Servlet文件(解码),然后以ISO8859-1来编码(这样就回到了服务器以ISO8859-1读取的内容了),最后以GBK来解码(就回到了最原始的Jsp文件了),最后...当然是现原型了(狐狸精一个啊,不过还是挺美的哦),一切显示正常,回到了过去。

    以下是代码实现:

    Java代码 复制代码
    1. String fileName = "E:/tomcat-5.5.23/work/Catalina/localhost/HttpStream/org/apache/jsp/gbk_jsp.java";   
    2. PrintWriter pw = new PrintWriter(new OutputStreamWriter(new FileOutputStream(   
    3.         "e:/tmp/gbk_jsp.java"), "UTF-8"));   
    4. BufferedReader br = new BufferedReader(new InputStreamReader(   
    5.         new FileInputStream(fileName), "utf-8"));   
    6. String readContent = null;   
    7. while ((readContent = br.readLine()) != null) {   
    8.     pw.write(new String(readContent.getBytes("iso8859-1"), "gbk") + "\r\n");   
    9.     pw.flush();   
    10. }   
    11. pw.close();  

        结果如何,看看下面小小的截图便知:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值