J2EE Web组件中中文及相关的问题(四)

类别:Java 点击:0 评论:0 推荐:
 

5.        使用过滤器

实际中我们处理客户端数据时,大多数时候都是在JavaBean中实现的,我们当然可以在会话Bean中把decoding掺合进去,但没有谁愿意这么做,而事实上我们可能会有很多的Bean,这种做法是维护和更新所不能容许的。我们还可以在JSPs/Servlets中通过ServletRequest.setCharaterEncoding(String encoding)来设置,但在众多JSPs/Servlets中这么做也是件令人讨厌的事。最理想的办法是一劳永逸——只在一个地方进行编码和解码的处理,那就是在过滤器(Filter)中。我们只要在过滤器中对客户提交的数据正确解码了,就不用JSPs/Servlets/JavaBeans来操心了。我们的客户可能是大陆的,也可能是台湾省的,也就是说我们至少还得为区分GB2312和Big5来操心了,最理想的就是让它们提交上来的数据都是UTF-8编码的,那就不用决定decoding了,这里我们可以通过第四种方法来让服务器影响浏览器选择encoding,即设置响应头中的Content-Type,让所有的JSP和Servlet的响应实体的编码都是UTF-8,那么浏览器也就会选择我们所使用的UTF-8来编码提交的数据。

package filters;

import java.io.IOException;

import javax.servlet.Filter;

import javax.servlet.FilterChain;

import javax.servlet.FilterConfig;

import javax.servlet.ServletException;

import javax.servlet.ServletRequest;

import javax.servlet.ServletResponse;

import javax.servlet.http.HttpServletRequest;

 

public class EncodingFilter implements Filter

{

       private FilterConfig config;

       private String defalutEncodeing;

       public void init(FilterConfig config)

       {

              this.config = config;

              defalutEncodeing = config.getInitParameter("encoding");

       }

       public void doFilter(ServletRequest request, ServletResponse response,

                                           FilterChain chain)        throws IOException,ServletException

       {

              request.setCharacterEncoding(defalutEncodeing);

              String uri = ((HttpServletRequest)request).getRequestURI();

              if(uri.indexOf(".jsp") != -1 || uri.indexOf("servlet") != -1)

                     response.setContentType("text/html;charset=" + defalutEncodeing);

              System.out.println("Filter set the encoding of the response to " +

                                             response.getCharacterEncoding());

              chain.doFilter(request, response);

       }

       public void destroy()

       {

              //...

       }

}

在Context的web.xml中进行如下配置:

  <filter>

    <filter-name>Encoding Filter</filter-name>

    <filter-class>filters.EncodingFilter</filter-class>

    <init-param>

      <param-name>encoding</param-name>

      <param-value>UTF-8</param-value>

    </init-param>

  </filter>

 

  <filter-mapping>

    <filter-name>Encoding Filter</filter-name>

    <url-pattern>/*</url-pattern>

  </filter-mapping>

可用一个test.jsp测试却发现,浏览器的输出并没有像我们预想的那样好,test.jsp源代码如下:

<%@ page pageEncoding="GBK"%>

<%String str = "在JSP中,编码已经被过滤器设置成:" + response.getCharacterEncoding();

System.out.println(str);%>

<%=str%>

它的输出如图3-3和图3-4,在客户端出现了乱码是没办法的事,因为通过服务器的输出我们可以发现在过滤器中,编码的确已经被设置成UTF-8,但在JSP中,编码又被设置成了ISO-8859-1。用过滤器对JSP编码设置失败,所以JSP的输出也失败了,我们看到了乱码。

图 3-3 对过滤器对JSP文件预设置编码失败

 图 3-4 服务器输出说明在JSP中编码又被设置为ISO8859-1

但一段Servlet代码却证明了过滤器本来已经成功进行了设置。

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import javax.servlet.ServletException;

import java.io.IOException;

import java.io.PrintWriter;

public class encoding extends HttpServlet {

    protected void doGet(HttpServletRequest request, HttpServletResponse response)

    throws ServletException, IOException {

              PrintWriter out = response.getWriter();

              String str = "在Servlet中,编码是:" + response.getCharacterEncoding();

              System.out.println(str);

              out.println(str);

              out.flush();

    }

}

你可以在有过滤器和没有过滤器的情况下做实验,结果应该发现在有过滤器状态下,服务器端和客户端均正确得到了UTF-8的输出,在没有过滤器的状态下,服务器端正确输出编码为ISO-8859-1,客户端却输出了乱码,不管是JSP时的乱码还是无过滤器Servlet的乱码,这些都是可以理解的,因为当没有对JSP明确设置page的contentType指令,JSP引擎自动把它设置为ISO-8859-1,而用ISO-8859-1来编码中文,当然只有得到乱码了。

现在可以说利用过滤器来设置响应实体编码,以达到控制浏览器提交数据的编码的希望是没有意义了,没有谁会用Servlet来输出含Form的HTML页。但在过滤器中设置用户提交的数据的编码码还是有意义的。对于JSP我们还是可以妥协到在每个JSP中来定义contentType,也许在一JSP文件中定义contentType,而其他JSP文件对这个文件使用静态包含是可行的。

<%--encoding.jsp--%>

<%@ page contentType=”text/html;charset=UTF-8”%>

静态包含

<%--form.jsp--%>

<%@ page pageEncoding="GBK"%>

<%@ include file="encoding.jsp"%>

<%String name = request.getParameter("name");%>

<html>

  <head>

    <title>Form</title>

  </head>

  <body>

    <form method="POST" action="test.jsp">

      <label>请输入您的姓名</label>

      <input type="text" name="name" size="20">

      <input type="submit" value="提交">

    </form>

<%if(name != null && !name.equals("")){

      //%><p>您的姓名是:<%=name%></p><%

}%>

  </body>

</html>

在这里,我们对客户提交的数据的解码是在过滤器Encoding Filter中完成的。form.jsp中的<%@ page pageEncoding="GBK"%>是不能省略到encoding.jsp中去,很明显它只对使用了它的JSP文件有效,而且不会在include指令中传递到包含文件中去的。

6.        URI的中文字符串

通常情况下,我们都会尽力避免在URI(Uniform Resource Indentifier,统一资源标识符,定义在RFC2396中)中出现非英文字符,但不是所有的时候都能避免,而且这种避免可能加大我们的开发成本或运行效率。如果想直接用含中文的URL(Uniform Resource Locator,统一资源定位符,定义在RFC1738中,是URI的子集)对服务器上的Web资源进行访问,那是不行的。比如:

http://localhost/我是中国人.html

是不能访问到服务器上的“我是中国人.html”,因为浏览器(我使用的是MSIE6.0b)会无条件对该URL用UTF-8来编码:

http://localhost/%E6%88%91%E6%98%AF%E4%B8%AD%E5%9B%BD%E4%BA%BA.
html

而服务器却用系统缺省编码来解码这个URL,即相当于执行了

java.net.URLDecoder.decoder(url);

这个动作。不过这个方法已经不被赞成使用了(Deprecated),而应该使用新的方法

   public String decode(String url, String charset)

    服务器使用缺省的GBK来解码URI,而浏览器却很难做到使用GBK来编码URI,JavaScript中有三个用来编码URI的全局函数

l          encodeURI(uri)

l          encodeURIComponent(uri)

l          escape(uri)

前面两个函数出现在IE5.5+中,它们用UTF-8来对参数uri编码,并返回编码的字符串;最后那个函数已经不被赞成使用了(Deprecated),它直接使用“%”加字符的Unicode内码来表示字符,如

escape(“我是中国人”)=%u6211%u662F%u4E2D%u56FD%u4EBA

这样,我们只好借助java.net.URLEncoder来编码URI了,如

<%-- encodeURL.jsp--%>

<%String file = “我是中国人.html”;

  url = java.net.URLEncoder.encode(file, "GBK");%>

<a href=”<%=url%>”><%=file%></a>

这样,我们就实现了访问文件名中含中文字符的Web文件。其实这种即增加开发成本,又牺牲服务器效率的做法是没有多大意义的,没有谁会故意非用个中文文件名不可。

在HttpServletRequest中,请求查询字符串(通过方法getQueryString()获得)即不是URI(通过方法getRequestURI()获得)的一部份,也不是URL(通过方法getRequestURIL()获得)的一部份,服务器使用URLDecoder解码URL时,丝毫不对它产生影响,可以说它是被独处理的,而我们前面所使用的过滤器Encoding Filter里面的

request.setCharacterEncoding(defalutEncodeing);

却会对它产生影响。让我们来看一个实验,该实验加载了过滤器Encoding Filter:

<script>

//浏览不会自动编码查询字符串中的非英文字符

function encodingHref(obj)

{

    obj.href = encodeURI(obj.href);

}

</script>

<a href="test.jsp?name=胡洲" onclick="encodingHref(this)">go</a>

test.jsp的源代码如下:

<%@ page contentType="text/html;charset=GBK"%>

pathInfo = <%=request.getPathInfo()%><br>

pathTranslated = <%=request.getPathTranslated()%><br>

contextPath = <%=request.getContextPath()%><br>

queryString = <%=request.getQueryString()%><br>

requestURI = <%=request.getRequestURI()%><br>

requestURL = <%=request.getRequestURL()%><br>

servletPath = <%=request.getServletPath()%><br>

name = <%=request.getParameter("name")%>

输出如图3-5:

图3-5

输出的结果是我们希望的。我们还可以在服务器端使用JSP代码:

<a href=”test.jsp?name=<%=URLEncoder.encode(“胡洲”, “UTF-8”)%>”>go</a>

事先编码好请求的URI,使用JavaScript代码编码查询字符串和使用JSP代码比起来,两者各有所长。

本文地址:http://com.8s8s.com/it/it17093.htm