通过PrimeFacesinput组件检索的Unicodeinput已损坏

当我还在使用PrimeFaces v2.2.1时,我能够使用PrimeFacesinput组件(如<p:inputText><p:editor>inputunicodeinput,例如中文,并在托pipebean方法中检索input状态良好。

但是,升级到PrimeFaces v3.1.1后,所有这些字符都变成了Mojibake或问号。 只有拉丁文的input才算正常,是中文,阿拉伯文,希伯来文,西里尔文等变得格格不入的文字。

这是如何造成的,我该如何解决?

介绍

通常情况下,JSF / Facelets默认已经在创build/恢复视图时将请求参数字符编码设置为UTF-8。 但是,如果在创build/恢复视图之前请求了任何请求参数,那么设置正确的字符编码为时已晚。 请求参数将只被parsing一次。

PrimeFaces编码失败

从2.x升级之后,PrimeFaces 3.x中的失败是由PrimeFaces的PrimePartialViewContext的新的isAjaxRequest()覆盖引起的,它检查了一个请求参数:

 @Override public boolean isAjaxRequest() { return getWrapped().isAjaxRequest() || FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().containsKey("javax.faces.partial.ajax"); } 

默认情况下, isAjaxRequest() (Mojarra / MyFaces中的一个,如上面的PrimeFaces代码已经通过getWrapped()获得)检查请求头,如下所示,不会影响请求参数编码,因为当请求参数不会被parsing时一个请求头被获取:

  if (ajaxRequest == null) { ajaxRequest = "partial/ajax".equals(ctx. getExternalContext().getRequestHeaderMap().get("Faces-Request")); } 

但是,在创build/恢复视图之前isAjaxRequest()可以由任何阶段侦听器或系统事件侦听器或某个应用程序工厂调用。 因此,当您使用PrimeFaces 3.x时,请求参数将设置正确的字符编码之前parsing,因此使用服务器的默认编码(通常是ISO-8859-1)。 这将弄乱一切。

解决scheme

有几种方法可以解决这个问题:

  1. 使用一个用UTF-8设置ServletRequest#setCharacterEncoding()的servletfilter 。 通过ServletResponse#setCharacterEncoding()设置响应编码ServletResponse#setCharacterEncoding()是不必要的,因为它不会受到这个问题的影响。

     @WebFilter("/*") public class CharacterEncodingFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException { request.setCharacterEncoding("UTF-8"); chain.doFilter(request, response); } // ... } 

    您只需要考虑到HttpServletRequest#setCharacterEncoding()仅设置POST请求参数的编码,而不是GET请求参数。 对于GET请求参数,您仍然需要在服务器级别进行configuration。

    如果您碰巧使用JSF实用程序库OmniFaces ,则已经提供了这种filter, 即CharacterEncodingFilter 。 只需在web.xml中将其安装为第一个过滤条目:

     <filter> <filter-name>characterEncodingFilter</filter-name> <filter-class>org.omnifaces.filter.CharacterEncodingFilter</filter-class> </filter> <filter-mapping> <filter-name>characterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> 

  2. 重新configuration服务器以使用UTF-8而不是ISO-8859-1作为默认编码。 在Glassfish的情况下,这将是添加以下条目到/WEB-INF/glassfish-web.xml文件的<glassfish-web-app>的问题:

     <parameter-encoding default-charset="UTF-8" /> 

    Tomcat不支持它。 它在<Context>条目中具有URIEncoding属性,但这仅适用于GET请求,而不适用于POST请求。


  3. 将其报告为PrimeFaces的错误。 是否真的有任何合法的理由检查HTTP请求是一个Ajax请求通过检查请求参数而不是请求标题,就像你会为标准的JSF和例如jQuery? PrimeFaces的core.js JavaScript正在这样做。 如果将它设置为XMLHttpRequest的请求标头,会更好。


解决scheme不工作

也许你会在调查这个问题的时候偶然发现互联网上某个地方的“解决scheme”。 这些解决scheme在这个特定情况下不会有效。 解释如下。

  • 设置XML序言:

     <?xml version='1.0' encoding='UTF-8' ?> 

    这只会告诉XMLparsing器在构buildXML树之前使用UTF-8对XML源进行解码。 JSF 视图构build时 ,Facelts实际使用的XMLparsing器是SAX。 这部分与HTTP请求/响应编码完全没有关系。

  • 设置HTML元标记:

     <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> 

    当通过http(s):// URI通过HTTP提供页面时,HTML元标记将被忽略。 只有当客户端的页面被保存为本地磁盘系统上的HTML文件,然后在浏览器中通过file:// URI重新打开时才会使用。

  • 设置HTML表单接受字符集属性:

     <h:form accept-charset="UTF-8"> 

    现代浏览器忽略这一点。 这仅在Microsoft Internet Explorer浏览器中有效。 即使这样做是错误的。 永远不要使用它。 所有真正的浏览器将使用响应的Content-Type头中指定的charset属性。 即使你没有指定accept-charset属性,即使MSIE也会这样做。

  • 设置JVM参数:

     -Dfile.encoding=UTF-8 

    这只能由Oracle(!)JVM用来读取和parsingJava源文件。