当我还在使用PrimeFaces v2.2.1时,我能够使用诸如<p:inputText>
和<p:editor>
之类的PrimeFaces输入组件键入unicode输入,例如中文,并检索输入状态良好的输入托管bean方法。
然而,在我升级到PrimeFaces v3.1.1后,所有这些字符都变成了Mojibake或问号。只有拉丁语输入才能正常,中文,阿拉伯语,希伯来语,西里尔语等字符会变得格格不入。
这是如何引起的?如何解决?
答案 0 :(得分:22)
通常,在创建/恢复视图时,JSF / Facelets会默认将请求参数字符编码设置为UTF-8。但是,如果在创建/恢复视图之前请求了任何请求参数,那么设置正确的字符编码为时已晚。请求参数将仅解析一次。
从2.x升级后,PrimeFaces 3.x失败的原因是PrimeFaces isAjaxRequest()
中的新PrimePartialViewContext
覆盖检查了请求参数:
@Override
public boolean isAjaxRequest() {
return getWrapped().isAjaxRequest()
|| FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().containsKey("javax.faces.partial.ajax");
}
默认情况下,isAjaxRequest()
(Mojarra / MyFaces之一,因为上面的PrimeFaces代码已通过getWrapped()
获得)检查请求标头如下,这不会影响请求参数编码作为请求获取请求标头时,不会解析参数:
if (ajaxRequest == null) {
ajaxRequest = "partial/ajax".equals(ctx.
getExternalContext().getRequestHeaderMap().get("Faces-Request"));
}
但是,在创建/恢复视图之前,任何阶段侦听器或系统事件侦听器或某些应用程序工厂都可以调用isAjaxRequest()
。因此,当您使用PrimeFaces 3.x时,将在设置正确的字符编码之前解析请求参数,因此使用服务器的默认编码,通常是ISO-8859-1。这会弄乱一切。
有几种方法可以解决它:
使用servlet filter设置ServletRequest#setCharacterEncoding()
和UTF-8。按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请求参数,您仍需要在服务器级别配置它。
如果您碰巧使用JSF实用程序库OmniFaces,则已在框the 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>
重新配置服务器以使用UTF-8而不是ISO-8859-1作为默认编码。对于Glassfish,可以在<glassfish-web-app>
文件的/WEB-INF/glassfish-web.xml
添加以下条目:
<parameter-encoding default-charset="UTF-8" />
Tomcat不支持它。它在URIEncoding
条目中具有<Context>
属性,但这仅适用于GET请求,而不适用于POST请求。
将其报告为PrimeFaces的错误。是否确实通过检查请求参数而不是像标准JSF和例如jQuery那样检查请求标头来检查HTTP请求是否为ajax请求的任何合法理由? PrimeFaces的core.js
JavaScript正在这样做。如果它将其设置为XMLHttpRequest
的请求标头会更好。
也许你会在调查这个问题时偶然发现互联网上某处的“解决方案”。这些解决方案不会在这种特定情况下起作用。说明如下。
设置XML序言:
<?xml version='1.0' encoding='UTF-8' ?>
这只告诉XML解析器在构建XML源代码之前使用UTF-8解码XML源代码。 Facelts实际使用的XML解析器在JSF view build time期间是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浏览器中有效。即便如此,它也是错误地做错了。永远不要使用它。所有真正的Web浏览器都将使用响应的Content-Type
标头中指定的charset属性。只要您没有指定accept-charset
属性,即使MSIE也会以正确的方式执行。
设置JVM参数:
-Dfile.encoding=UTF-8
这仅供Oracle(!)JVM用于读取和解析Java源文件。