15

まだPrimeFacesv2.2.1を使用していたとき、中国語などのUnicode入力を<p:inputText>andなどのPrimeFaces入力コンポーネント<p:editor>で入力し、マネージドBeanメソッドで入力を適切な形で取得することができました。

ただし、PrimeFaces v3.1.1にアップグレードすると、これらの文字はすべて文字化けまたは疑問符になります。ラテン語の入力のみが問題なく機能します。不正な形式になるのは、中国語、アラビア語、ヘブライ語、キリル文字などの文字です。

これはどのように発生し、どうすれば解決できますか?

4

1 に答える 1

27

序章

通常、JSF / Faceletsは、ビューの作成/復元時に、要求パラメーターの文字エンコードをデフォルトでUTF-8に設定します。ただし、ビューが作成/復元される前に要求パラメーターが要求された場合、適切な文字エンコードを設定するには遅すぎます。つまり、リクエストパラメータは1回だけ解析されます。

PrimeFacesエンコーディングが失敗する

2.xからのアップグレード後にPrimeFaces3.xで失敗したのは、要求パラメーターをチェックするisAjaxRequest()PrimeFacesの新しいオーバーライドが原因です。PrimePartialViewContext

@Override
public boolean isAjaxRequest() {
    return getWrapped().isAjaxRequest()
            || FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().containsKey("javax.faces.partial.ajax");
}

デフォルトでは、isAjaxRequest()(上記のPrimeFacesコードによって取得されたMojarra / MyFacesの1つgetWrapped())は、要求ヘッダーが取得されたときに要求パラメーターが解析されないため、要求パラメーターのエンコードに影響を与えない次のように要求ヘッダーをチェックします。

    if (ajaxRequest == null) {
        ajaxRequest = "partial/ajax".equals(ctx.
            getExternalContext().getRequestHeaderMap().get("Faces-Request"));
    }

ただし、ビューが作成/復元される前にisAjaxRequest()、任意のフェーズリスナー、システムイベントリスナー、または一部のアプリケーションファクトリによって呼び出される場合があります。したがって、PrimeFaces 3.xを使用している場合、適切な文字エンコードが設定される前に要求パラメーターが解析されるため、サーバーのデフォルトのエンコード(通常はISO-8859-1)が使用されます。これはすべてを台無しにします。

ソリューション

それを修正するいくつかの方法があります:

  1. UTF-8で設定するサーブレットフィルタを使用します。ちなみに、この問題の影響を受けないため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()GETリクエストパラメータではなく、POSTリクエストパラメータのエンコーディングのみを設定することを考慮する必要があります。GETリクエストパラメータの場合は、サーバーレベルで設定する必要があります。

    JSFユーティリティライブラリOmniFacesを使用する場合、そのようなフィルタはすでにボックスから提供されていますCharacterEncodingFilterweb.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>
    

  2. デフォルトのエンコーディングとしてISO-8859-1の代わりにUTF-8を使用するようにサーバーを再構成します。Glassfishの場合は<glassfish-web-app>/WEB-INF/glassfish-web.xmlファイルに次のエントリを追加する必要があります。

    <parameter-encoding default-charset="UTF-8" />
    

    Tomcatはそれをサポートしていません。URIEncodingエントリに属性があります<Context>が、これはGETリクエストにのみ適用され、POSTリクエストには適用されません。


  3. バグとしてPrimeFacesに報告してください。標準のJSFやjQueryの場合のように、リクエストヘッダーではなくリクエストパラメータをチェックすることで、HTTPリクエストがajaxリクエストであることを確認する正当な理由は本当にありますか?PrimeFacesのcore.jsJavaScriptがそれを行っています。のリクエストヘッダーとして設定した方が良いでしょうXMLHttpRequest


動作しないソリューション

おそらく、この問題を調査しているときに、インターネット上のどこかで「解決策」の下に出くわすでしょう。これらのソリューションは、この特定のケースでは機能しません。説明は次のとおりです。

  • XMLプロローグの設定:

    <?xml version='1.0' encoding='UTF-8' ?>
    

    これは、XMLパーサーにUTF-8を使用してXMLソースをデコードしてから、その周りにXMLツリーを構築するように指示するだけです。Faceltsによって実際に使用されているXMLパーサーは、JSFビューのビルド時にSAXです。この部分は、HTTP要求/応答エンコーディングとはまったく関係がありません。

  • HTMLメタタグの設定:

    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    

    http(s)://ページがURIを介してHTTP経由で提供される場合、HTMLメタタグは無視されます。file://これは、ページがクライアントによってローカルディスクシステムにHTMLファイルとして保存され、ブラウザのURIによって再度開かれた場合にのみ使用されます。

  • HTMLフォームの設定はcharset属性を受け入れます:

    <h:form accept-charset="UTF-8">
    

    最近のブラウザはこれを無視します。これは、MicrosoftInternetExplorerブラウザでのみ効果があります。それでも、それは間違ってやっています。絶対に使用しないでください。Content-Typeすべての実際のWebブラウザーは、代わりに応答のヘッダーで指定されたcharset属性を使用します。accept-charset属性を指定しない限り、MSIEでも正しい方法で実行されます。

  • JVM引数の設定:

    -Dfile.encoding=UTF-8
    

    これは、Javaソースファイルを読み取って解析するためにOracle(!)JVMによってのみ使用されます。

于 2012-03-23T12:40:16.743 に答える