`
jguangyou
  • 浏览: 375673 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

tomcat 下jsp乱码的原因分析(上)

 
阅读更多

转自 http://blog.csdn.net/jgwei/article/details/40819577

 

tomcat 下jsp乱码

我们先看一个例子(包含2个文件一个test.jsp , 和result.jsp): 

test.jsp

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <%@ page language="java" isThreadSafe="true" pageEncoding="utf8" %>  
  2. <%@ page contentType="text/html; charset=gbk"%>  
  3.   
  4. <html>  
  5. <head>  
  6. <title></title>  
  7. <!--<meta http-equiv="Content-Type" content="text/html; charset=gbk">-->  
  8. <META HTTP-EQUIV="pragma" CONTENT="no-cache">  
  9. <META HTTP-EQUIV="Cache-Control" CONTENT="no-cache, must-revalidate">  
  10. <META HTTP-EQUIV="expires" CONTENT="Mon, 23 Jan 1978 20:52:30 GMT">  
  11. </head>  
  12. <body>  
  13.   
  14. <form name="form1" action="result.jsp" method="get" target="">  
  15.   <INPUT TYPE="text" NAME="abc">  
  16.   <INPUT TYPE="submit" VALUE="submit">  
  17. </form>  
  18.   
  19. </body>  
  20. </html>  


result.jsp

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <%@ page language="java" isThreadSafe="true" pageEncoding="utf8" %>  
  2. <%@ page contentType="text/html; charset=utf8"%>  
  3.   
  4. <html>  
  5. <head>  
  6. <title></title>  
  7. <!--<meta http-equiv="Content-Type" content="text/html; charset=gbk">-->  
  8. <META HTTP-EQUIV="pragma" CONTENT="no-cache">  
  9. <META HTTP-EQUIV="Cache-Control" CONTENT="no-cache, must-revalidate">  
  10. <META HTTP-EQUIV="expires" CONTENT="Mon, 23 Jan 1978 20:52:30 GMT">  
  11. </head>  
  12. <body>  
  13. <%  
  14.  //request.setCharacterEncoding("utf8");  
  15.  String abc = request.getParameter("abc");  
  16.  if(abc == null) {  
  17.    out.println("空值");  
  18.   }  
  19.   else   
  20.   {    
  21.     out.println("原始编码:");  
  22.     out.println(abc);  
  23.     out.println("</br>");  
  24.     out.println("utf8编码:");  
  25.     String abc1 = new String(abc.getBytes("ISO-8859-1"),"utf8");    
  26.     System.out.println(abc1);     
  27.     out.println(abc1);    
  28.     out.println("</br>");  
  29.     out.println("gbk编码:");  
  30.     String abc2 = new String(abc.getBytes("ISO-8859-1"),"gbk");       
  31.     out.println(abc2);   
  32.   }       
  33. %>  
  34.   
  35. </br>  
  36. </br>  
  37. </br>  
  38.   
  39. <a href="test.jsp">返回</a>  
  40.   
  41. </body>  
  42. </html>  

 

这是2个测试用网页,功能很简单, 就是在把test.jsp页面输入框中输入的内容提交到result.jsp页面然后显示 。麻雀虽小五脏俱全, 乱码时候涉及的要素这个jsp文件里面都有了。 首先我们先搞清这样几个重要的概念。

 

1、文件的编码

2、浏览器的编码

3、字符串的解码、编码

4、容器的编码,这里的容器就是tomcat。 这个页面的运行在tomcat内部, 一切都受到它的控制。

下面咱们结合上面那个jsp文件来对上面4点一一来说明:

1、文件的编码

我们日常使用记事本或者其他文本工具的时候, 写一个文本文档, 然后点击“另存”的时候, 会弹出一个对话框, 里面都会有让你选择encoding 这样一个选项。只是咱们默认都是gbk。 如图:

为啥需要这么多编码? 如果这个地方你就有困惑的话, 就需要好好补补计算机基础知识, 然后再来看下面的内容。

 好咱们再说下jsp,jsp是什么?其实就是servlet, 但是比servlet多一个步骤, 恰恰是多的这个步骤,这个步骤是什么? 就是在tomcat的work路径下面每个jsp都会被tomcat自动解析成一个servlet文件。注意:我们编写的jsp在运行的时候变成了servlet, 这样是不是就存在2个文件了(一个我们自己编写的jsp, 一个tomcat根据jsp自动产生的servelet)。特别说明这个servlet是自动生成的。 这个地方就有像你刚刚在记事本里面点“另存”一样, 需要设置这个另存的文件的编码的。 不然这个servlet会已何种编码生成? jsp的发明者就设定了这样个语法: 

 

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <%@ page language="java" isThreadSafe="true" pageEncoding="gbk" %>  

 

pageEncoding 就是做这个用的。所以你的这个jsp文件的编码是utf8, 这个pageEncoding  就设置成utf8, 要一致, 否则, 从jsp生成的servlet就乱码了(当然是里面有中文的时候)。

2、浏览器的编码

 好了jsp可以编译成正确的servlet, 在浏览器中也可以正常看到了。 

如图, 在浏览器的设置里面可以看到“编码”这个选项, 注意页面显示正常的时候,编码选择在utf-8, 如果我们这时候把浏览器的页面编码选择成“gbk“ , 就乱码了。

为啥会这样呢?

我们再看看源码中, 有这样一句:

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <%@ page contentType="text/html;charset=utf8"%>  

这就是servlet说, 我要返回utf8编码的内容, 同时浏览器才可以使用utf8的编码识别返回的页面, 如果使用其他编码的话, 自然出现乱码。这点我们可以打开tomcat下面jsp自动生成的那个servlet, 会看到如下代码:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)  
  2.       throws java.io.IOException, javax.servlet.ServletException {  
  3.   
  4.   final javax.servlet.jsp.PageContext pageContext;  
  5.   javax.servlet.http.HttpSession session = null;  
  6.   final javax.servlet.ServletContext application;  
  7.   final javax.servlet.ServletConfig config;  
  8.   javax.servlet.jsp.JspWriter out = null;  
  9.   final java.lang.Object page = this;  
  10.   javax.servlet.jsp.JspWriter _jspx_out = null;  
  11.   javax.servlet.jsp.PageContext _jspx_page_context = null;  
  12.   
  13.   
  14.   try {  
  15.     response.setContentType("text/html;charset=utf8");  
  16.     pageContext = _jspxFactory.getPageContext(this, request, response,  
  17.                 nulltrue8192true);  
  18.     _jspx_page_context = pageContext;  
  19.     application = pageContext.getServletContext();  

 

通过代码, 我们可以清楚的看到, servlet里面明确设置了response.setContentType("text/html;charset=utf8");

通用我们使用工具也可以在浏览器里面看到这样的标示:


编码一致: servlet 和浏览器配合一致, 才可以正常显示。

我们如果把源码中做下修改:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <pre class="html" name="code"><%@ page contentType="text/html;charset=gbk"%>  



 


那么servlet中的源码就变成了:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)  
  2.       throws java.io.IOException, javax.servlet.ServletException {  
  3.   
  4.   final javax.servlet.jsp.PageContext pageContext;  
  5.   javax.servlet.http.HttpSession session = null;  
  6.   final javax.servlet.ServletContext application;  
  7.   final javax.servlet.ServletConfig config;  
  8.   javax.servlet.jsp.JspWriter out = null;  
  9.   final java.lang.Object page = this;  
  10.   javax.servlet.jsp.JspWriter _jspx_out = null;  
  11.   javax.servlet.jsp.PageContext _jspx_page_context = null;  
  12.   
  13.   
  14.   try {  
  15.     response.setContentType("text/html;charset=gbk");  
  16.     pageContext = _jspxFactory.getPageContext(this, request, response,  
  17.                 nulltrue8192true);  


servlet中设置编码的地方变成了response.setContentType("text/html;charset=gbk");

浏览器接收到网页内容的地方也变成了gbk

 

这个地方还有另外一个写法, jsp直接按照html的语法写就可以

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <meta http-equiv="Content-Type" content="text/html; charset=utf-8">  

这个的作用和jsp的写法

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <%@ page contentType="text/html;charset=gbk"%>  

等效, 2者是等效的, 后者是jsp语法, 前者是html脚本。 这点可以通过查看jsp生成的servlet的源码验证jsp语法的作用。

到目前为止我们可以发现显示的时候只是关系到浏览器如何识别读取到的页面的编码。只要页面本身里面没有乱码, 还是可以通过手工切换浏览器的编码来适应页面的编码。当然如果你的程序仅仅是一个页面用了显示数据的话, 这个charset你可以随便写, 对你的程序不会产生任何影响, 是服务器告诉浏览器如何解析编码。 但是这个太不理想, 因为一个系统往往是N多的页面组成的, 那就会产生影响了, 咱们下面就来讨论下。

3、字符串的解码、编码

好了, 讲了半天都是单页面的显示, 总算开始提交以下页面了。 首先我们把test.jsp 和result.jsp 的页面的头都设置成

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <%@ page language="java" isThreadSafe="true" pageEncoding="utf8" %>  
  2. <%@ page contentType="text/html; charset=utf8"%>  

在浏览器中访问test.jsp, 输入“中文”

点提交以后:

从页面上看 有乱码, 但是也有正常的。 好先不管其他, 再做个试验:

把test.jsp 的头改成【注意这里只是修改了test.jsp的编码, result.jsp仍然是utf8】:

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <%@ page language="java" isThreadSafe="true" pageEncoding="utf8" %>  
  2. <%@ page contentType="text/html; charset=gbk"%>  

然后再重复以上提交步骤, 结果如图:

我们把二者的结果对比下, 可以很清楚的看到区别, 结合我们修改的test.jsp 的编码, 是不是可以得出这样的结论:

test.jsp的charset编码utf8 ---------------------> result.jsp 里面utf8编码显示正常,  而其他的乱码

test.jsp的charset编码gbk ---------------------> result.jsp 里面gbk编码显示正常,而其他的乱码

而且和result.jsp的charset的编码无关, 不管其是utf8或者gbk, 原因上文已经分析过了

我们的在result.jsp这样接受test.jsp 发送过来的内容

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. String abc = request.getParameter("abc");  
  2.  if(abc == null) {  
  3.    out.println("空值");  
  4.   }  
  5.   else   
  6.   {    
  7.     out.println("原始编码:");  
  8.     out.println(abc);    
  9.     out.println(java.util.Arrays.toString(abc.getBytes("ISO-8859-1")));   
  10.     out.println(new String(abc.getBytes("ISO-8859-1")));  
  11.     out.println("utf8编码:");  
  12. <span style="color:#ff6666;">    String abc1 = new String(abc.getBytes("ISO-8859-1"),"utf8"); </span>   
  13.     System.out.println(abc1);     
  14.     out.println(abc1);    
  15.     out.println("gbk编码:");  
  16.   <span style="color:#ff6666;">  String abc2 = new String(abc.getBytes("ISO-8859-1"),"gbk"); </span>      
  17.     out.println(abc2);   
  18.   }       


看下红色的部分, 就是解码的语句,

例如:

new String(abc.getBytes("ISO-8859-1"),"gbk"); 

就是把iso8859编码的字符串变成编码为gbk的字符串,如果先让你的最终结果对, 就要保证你的原始的字符串是iso8859编码的。

问题又来了。 为啥要在前面按照iso8859来呢? 我们明明在test.jsp中用的是是gbk或者utf8, 怎么会冒出个iso8859呢? 讲到这里, 不能不引出我们的幕后英雄tomcat。

4、容器的编码,这里的容器就是tomcat。 这个页面的运行在tomcat内部, 一切都受到它的控制。

test.jsp 和 result.jsp 都是放在容器tomcat中, 生成servlet是tomcat做的, 浏览器请求一个url地址, 端口监听、接收数据都是tomcat做的。 什么时候才是result.jsp

运行的时候?

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. String abc = request.getParameter("abc");  

这个才是第一句代码。 但是这个时候abc已经就是iso8859的编码了。怎么会这样的呢? 我们打开tomcat的源码一窥究竟。

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. request.getParameter  

实际调用的是

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. org.apache.catalina.core.ApplicationHttpRequest.getParameter  

然后调用

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. org.apache.catalina.core.ApplicationHttpRequest.parseParameters  

最后调用了

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. org.apache.catalina.core.ApplicationHttpRequest.mergeParameters  

让我们看看mergeParameters的具体实现:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /** 
  2.  * Merge the parameters from the saved query parameter string (if any), <br> 
  3.  * and the parameters already present on this request (if any), <br> 
  4.  * such that the parameter values from the query string show up first if there are duplicate parameter names. 
  5.  */  
  6. private void mergeParameters(){  
  7.     if ((queryParamString == null) || (queryParamString.length() < 1))  
  8.         return;  
  9.     HashMap queryParameters = new HashMap();  
  10.     String encoding = getCharacterEncoding();  
  11.     if (encoding == null)  
  12.         encoding = "ISO-8859-1";  
  13.     try{  
  14.         RequestUtil.parseParameters(queryParameters, queryParamString, encoding);  
  15.     }catch (Exception e){  
  16.         ;  
  17.     }  
  18.     Iterator keys = parameters.keySet().iterator();  
  19.     while (keys.hasNext()){  
  20.         String key = (String) keys.next();  
  21.         Object value = queryParameters.get(key);  
  22.         if (value == null){  
  23.             queryParameters.put(key, parameters.get(key));  
  24.             continue;  
  25.         }  
  26.         queryParameters.put(key, mergeValues(value, parameters.get(key)));  
  27.     }  
  28.     parameters = queryParameters;  
  29. }  


是不是很明白了,当encoding没有设置的时候, 就是ISO-8859-1, tomcat帮你把接收到的数据统统编码。

所以整个过程就变成了这样: 

test.jsp  -------------------------------------->   tomcat --------------------------------------------> result.jsp

gbk/utf8 ===================== > iso8859 =========================> iso8859还原gbk/utf8

所以有了最原始的解码方法, 也就是自己纯手工解码

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. String abc1 = new String(abc.getBytes("ISO-8859-1"),"utf8");    
  2. String abc2 = new String(abc.getBytes("ISO-8859-1"),"gbk");    

虽然原始、繁琐, 但是这个最基本的方式方法。体现了这个解码的过程。

总结:

jsp乱码的几个基本的原因大概就是这样。 只要明白了以上的道理,合理的运用文件的编码、页面的编码、以及对应的解码,应该就可以避免这些问题的出现。 

这里重点于这些问题的原因,等有时间再总结下tomcat下面统一处理jsp乱码的方式方法。以上都是一家之言, 对与不对希望各位多交流。

分享到:
评论

相关推荐

    jsp 乱码详解(jsp,mysql,tomcat)

    jsp 乱码详解(jsp,mysql,tomcat) 基本涵盖所有的乱码解决方法。使用的utf-8作为例子

    如何解决Tomcat下中文乱码问题?

    总结来说,解决Tomcat下的中文乱码问题,关键在于确保JSP页面的编码与服务器设置一致,并在处理表单提交时正确设置请求的字符编码。在实际开发中,推荐使用UTF-8作为统一的编码标准,因为UTF-8能够兼容各种语言,...

    解决Tomcat中文乱码

    在Tomcat环境下运行Web应用程序时,如果页面或请求中包含了中文字符,可能会出现乱码的情况。这种乱码现象通常是由于字符编码设置不一致导致的。Tomcat默认使用的字符集是ISO-8859-1,而大多数中文网页和文件采用的...

    tomcat与servlet乱码解决办法

    本文主要围绕Tomcat服务器下JSP页面以及Servlet中的乱码问题进行深入分析,并提供相应的解决方案。 #### 二、JSP页面乱码原因及解决方法 ##### 2.1 JSP页面乱码的原因 JSP页面中的乱码通常由以下几个因素引起: 1....

    彻底解决 Tomcat 5 下文字乱码问题 - JSP日志 - ※一路风尘※

    在IT行业中,尤其是在Web开发领域,Tomcat是一个广泛使用的开源应用服务器,主要处理Java Servlet和JSP...通过这些步骤,开发者能够有效避免和解决Tomcat 5下的文字乱码问题,使得JSP日志和其他文本数据能够正常显示。

    JSP乱码 N种解决方案

    本文将深入探讨“JSP乱码”的多种解决方案,并提供实用的解决策略。 1. **理解字符编码的基本概念** - 字符编码是计算机对文字进行存储和处理的标准,常见的有ASCII、GBK、UTF-8等。 - JSP页面默认使用ISO-8859-1...

    weblogic和tomcat 下载附件乱码问题

    本文将详细探讨WebLogic与Tomcat环境下解决下载附件乱码问题的方法。 #### 一、问题背景 在Web应用程序中,当用户点击下载链接后,浏览器会根据服务器返回的信息来判断如何处理这个下载请求。如果服务器返回的...

    jsp乱码解决方案 本方案解决了jsp常见的乱码问题

    ### jsp乱码解决方案 #### 一、引言 在Web开发中,特别是使用Java Server Pages (JSP)进行开发时,字符编码问题是一个经常遇到的技术难题。如果处理不当,很容易导致网页显示乱码,影响用户体验及数据的正确性。...

    解决tomcat中文乱码问题.doc

    综上所述,通过合理设置JSP页面编码、配置请求过滤器以及进行必要的编码转换,可以有效解决Tomcat环境下中文乱码的问题。在实际应用中,还需要根据具体情况选择合适的解决方案,并注意保持前后端编码的一致性。

    TOMCAT乱码问题

    造成乱码的原因是tomcat对表单提交和GET请求的处理方式不同。Tomcat4和Tomcat5处理乱码的方法不同,在Tomcat5中,需要使用Filter设置字符集为GBK来解决乱码问题。 解决方法一:使用Filter设置字符集 1. 实现一个...

    解决jsp页面乱码

    解决jsp页面乱码,页面信息配置,tomcat配置以及各种信息配置

    JSP中文乱码问题分析及处理方法

    ### JSP中文乱码问题分析及处理方法 #### 一、问题根源剖析 JSP(Java Server Pages)作为Web开发中的一种技术,广泛应用于动态网页的生成。然而,在处理中文字符时,JSP经常会遇到“乱码”问题,即中文字符无法...

    JSP中文乱码处理JSP中文乱码处理

    当Web容器(如Tomcat)将JSP编译为Servlet时,它会读取硬盘上的JSP文件。如果没有指定pageEncoding,JSP规范规定默认编码为ISO-8859-1,但不同的Web容器可能会有所不同。在JSP文件中明确指定pageEncoding可以避免...

    Tomcat和jsp的乱码处理和Myeclipse光标跳动的解决

    本篇文章将详细探讨“Tomcat和jsp的乱码处理”以及“Myeclipse光标跳动的解决”这两个关键知识点。 首先,我们来解决“Tomcat和jsp的乱码处理”。在部署和运行基于Java的Web应用时,Tomcat服务器和jsp页面对中文...

    Struts+Hibernate+MyEclipse+Tomcat+MySQL的乱码之解决篇

    在本篇文章中,我们将深入探讨如何解决Struts + Hibernate + MyEclipse + Tomcat + MySQL环境中出现的乱码问题。该问题通常出现在处理中文字符时,由于编码设置不当导致中文显示为乱码或无法正常读取。为了确保系统...

    jsp中文乱码问题jsp中文乱码问题详解

    jsp中文乱码问题详解 在jsp中文乱码问题中,乱码的出现是由于编码格式不一致所导致的。在jsp文件中,存在三个地方的编码格式:jsp文件的存储格式、解码格式和控制浏览器的解码方式。如果这三个地方的编码格式不一致...

    jsp页面乱码处理

    #### JSP乱码的根本原因 JSP页面的乱码通常源自字符编码不一致,即不同环节使用的编码格式不匹配。例如,Java后端使用的是Unicode编码,而前端浏览器使用的是GBK(GB2312扩展);MySQL数据库默认使用的是UTF-8。...

    Tomcat中Get和Post出现乱码的解决办法

    "Tomcat中Get和Post出现乱码的解决办法" 在 Tomcat 中,Get 和 Post 方法都可能出现乱码问题,这主要是由于编码问题引起的。在本文中,我们将详细介绍 Tomcat 中 Get 和 Post 方法出现乱码的解决办法。 一、乱码...

    jsp乱码的3种解决方法

    本文将详细讲解三种解决JSP乱码的方法。 ### 1. 设置页面编码 JSP页面的编码设置是解决乱码问题的基础。在JSP文件的顶部,使用`&lt;%@ page&gt;`指令设置页面编码。例如: ```jsp ;charset=UTF-8" language="java" %&gt; `...

Global site tag (gtag.js) - Google Analytics