<p:inputText>
当我还在使用 PrimeFaces v2.2.1 时,我能够使用 PrimeFaces 输入组件(例如和)输入 unicode 输入(例如中文)<p:editor>
,并在托管 bean 方法中以良好的形式检索输入。
但是,在我升级到 PrimeFaces v3.1.1 后,所有这些字符都变成了 Mojibake 或问号。只有拉丁文输入正常,是中文、阿拉伯文、希伯来文、西里尔文等字符格式错误。
这是如何引起的,我该如何解决?
<p:inputText>
当我还在使用 PrimeFaces v2.2.1 时,我能够使用 PrimeFaces 输入组件(例如和)输入 unicode 输入(例如中文)<p:editor>
,并在托管 bean 方法中以良好的形式检索输入。
但是,在我升级到 PrimeFaces v3.1.1 后,所有这些字符都变成了 Mojibake 或问号。只有拉丁文输入正常,是中文、阿拉伯文、希伯来文、西里尔文等字符格式错误。
这是如何引起的,我该如何解决?
通常,JSF/Facelets 在创建/恢复视图时已经默认将请求参数字符编码设置为 UTF-8。但是如果在创建/恢复视图之前请求了任何请求参数,那么设置正确的字符编码为时已晚。请求参数将只被解析一次。
从 2.x 升级后在 PrimeFaces 3.x 中失败是由检查请求参数isAjaxRequest()
的 PrimeFaces 中的新覆盖引起的: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。这会搞砸一切。
有几种方法可以修复它:
使用设置为 UTF-8的servlet 过滤器。ServletRequest#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 请求参数,您仍然需要在服务器级别对其进行配置。
如果您碰巧使用 JSF 实用程序库OmniFaces,那么已经提供了这样的过滤器,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
.
也许您在调查此问题时会在 Internet 上的某个地方偶然发现以下“解决方案”。这些解决方案在这种特定情况下永远不会起作用。解释如下。
设置 XML 序言:
<?xml version='1.0' encoding='UTF-8' ?>
这只是告诉 XML 解析器在围绕它构建 XML 树之前使用 UTF-8 对 XML 源进行解码。在 JSF视图构建期间,Facelts 实际使用的 XML 解析器是 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
响应标头中指定的字符集属性。只要您不指定accept-charset
属性,即使 MSIE 也会以正确的方式执行此操作。
设置 JVM 参数:
-Dfile.encoding=UTF-8
这仅由 Oracle(!) JVM 用于读取和解析 Java 源文件。