通过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
有几种方法可以解决这个问题:
- 
使用一个用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>
 
- 
重新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请求。
 
- 
将其报告为PrimeFaces的错误。 是否真的有任何合法的理由检查HTTP请求是一个Ajax请求通过检查请求参数而不是请求标题,就像你会为标准的JSF和例如jQuery? PrimeFaces的 core.jsJavaScript正在这样做。 如果将它设置为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源文件。