通过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.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源文件。