Jsf 通过PrimeFaces输入组件检索的Unicode输入已损坏

Jsf 通过PrimeFaces输入组件检索的Unicode输入已损坏,jsf,unicode,primefaces,character-encoding,mojibake,Jsf,Unicode,Primefaces,Character Encoding,Mojibake,当我还在使用PrimeFacesV2.2.1时,我能够使用PrimeFaces输入组件(如和)键入unicode输入,如中文,并在managed bean方法中以良好的状态检索输入 然而,在我升级到PrimeFacesV3.1.1之后,所有这些字符都变成了Mojibake或问号。只有拉丁语输入是正确的,它是汉语、阿拉伯语、希伯来语、西里尔语等格式错误的字符 这是如何造成的?我如何解决它?引言 通常,在创建/恢复视图时,JSF/Facelets会在默认情况下将请求参数character encod

当我还在使用PrimeFacesV2.2.1时,我能够使用PrimeFaces输入组件(如
)键入unicode输入,如中文,并在managed bean方法中以良好的状态检索输入

然而,在我升级到PrimeFacesV3.1.1之后,所有这些字符都变成了Mojibake或问号。只有拉丁语输入是正确的,它是汉语、阿拉伯语、希伯来语、西里尔语等格式错误的字符

这是如何造成的?我如何解决它?

引言 通常,在创建/恢复视图时,JSF/Facelets会在默认情况下将请求参数character encoding设置为UTF-8。但是,如果在创建/恢复视图之前请求了任何请求参数,那么设置正确的字符编码就太晚了。请求参数将只解析一次

素数编码失败 从2.x升级后,它在PrimeFaces 3.x中失败是由于PrimeFaces中新的
isAjaxRequest()
override'
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设置的。顺便说一下,设置响应编码是不必要的,因为它不会受到此问题的影响

    @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()
    只设置请求后参数的编码,而不设置GET请求参数的编码。对于GET请求参数,您仍然需要在服务器级别对其进行配置

    如果您碰巧使用了JSF实用程序库,那么已经提供了这样一个过滤器。只需将其安装在
    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>
    
    Tomcat不支持它。它在
    条目中具有
    URIEncoding
    属性,但这仅适用于GET请求,而不适用于POST请求


  • 将其作为错误报告给PrimeFaces。通过检查请求参数而不是像对标准JSF和例如jQuery那样的请求头来检查HTTP请求是否是ajax请求,真的有什么正当的理由吗?PrimeFaces的
    core.js
    JavaScript就是这样做的。如果将其设置为
    XMLHttpRequest
    的请求头,效果会更好


  • 不起作用的解决方案 在调查这个问题时,也许你会在互联网上的某个地方偶然发现以下“解决方案”。这些解决方案在这种特定情况下是行不通的。解释如下

    • 设置XML prolog:

      <?xml version='1.0' encoding='UTF-8' ?>
      
      现代浏览器忽略了这一点。这仅在Microsoft Internet Explorer浏览器中有效。即便如此,它也做得不对。永远不要使用它。所有真正的WebBrowser将改为使用响应的
      内容类型
      标题中指定的字符集属性。只要您不指定
      accept charset
      属性,即使是MSIE也会以正确的方式执行此操作

    • 设置JVM参数:

      -Dfile.encoding=UTF-8
      
      这仅由Oracle(!)JVM用于读取和解析Java源文件


    感谢您的精彩帖子。我昨天遇到了这个问题,在找到过滤器解决方案之前,已经将其隔离到
    p:commandButton
    。你的调查证明了这一点。这是一个严重的错误,因为每次单击“保存”按钮都会复制错误的编码字符。很抱歉回复太晚。我今天刚刚测试了您的解决方案。第二种解决方案不能解决问题。我还尝试使用
    过滤器
    ,但效果不太好。目前,我的应用程序中有两个过滤器:PrimeFaces的Fileupload过滤器和我自己的过滤器。我将
    HttpServletRequest#setCharacterEncoding()
    添加到我自己的过滤器中。如果在调用另一个筛选器之前调用PrimeFaces的筛选器,是否会导致问题?您的新问题似乎只与使用
    System.out.println()
    打印提交的数据有关。stdout(系统输出将写入的地方)是否也配置为使用UTF-8?在Eclipse中,您可以在窗口>首选项>常规>工作空间>文本文件编码中进行设置。请注意,不需要同时使用筛选器和服务器配置。两者中的一个就足够了。DB持久性问题似乎只与JDBC连接使用的字符编码有关。它是否也配置为使用UTF-8?例如,众所周知MySQL错误地使用了客户端平台编码。无论如何,要解决这个问题和任何未来的问题,请阅读@BalusC:事实上,我遵循了这篇文章,并使用UTF-8字符集重新创建了整个数据库。但是,我被困在必须为JDBC连接设置
    useUnicode=yes&characterEncoding=UTF-8
    的部分。我已经使用GlassFish管理控制台创建了我的JDBC连接池和JDBC资源。您能告诉我如何将上述两个属性应用于JDBC连接吗?
    <h:form accept-charset="UTF-8">
    
    -Dfile.encoding=UTF-8