Pergunta

Quando eu ainda estava usando o PrimeFaces v2.2.1, consegui digitar uma entrada unicode, como chinês, com um componente de entrada PrimeFaces, como <p:inputText> e <p:editor>, e recupere a entrada em boas condições no método de bean gerenciado.

No entanto, depois de atualizar para PrimeFaces v3.1.1, todos esses caracteres se tornaram Mojibake ou pontos de interrogação.Apenas a entrada em latim funciona bem, são os caracteres chineses, árabes, hebraicos, cirílicos, etc. que ficam malformados.

Como isso é causado e como posso resolvê-lo?

Foi útil?

Solução

Introdução

Normalmente, JSF/Facelets definirá a codificação de caracteres do parâmetro de solicitação para UTF-8 por padrão já quando a visualização for criada/restaurada.Mas se algum parâmetro de solicitação for solicitado antes a visualização foi criada/restaurada, então é tarde demais para definir a codificação de caracteres adequada.Os parâmetros da solicitação serão analisados ​​apenas uma vez.

Falha na codificação PrimeFaces

A falha no PrimeFaces 3.x após a atualização do 2.x é causada pelo novo isAjaxRequest() substituir no PrimeFaces' PrimePartialViewContext que verifica um parâmetro de solicitação:

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

Por padrão, o isAjaxRequest() (o de Mojarra/MyFaces, como o código PrimeFaces acima foi obtido por getWrapped()) verifica o cabeçalho da solicitação da seguinte maneira, o que não afeta a codificação dos parâmetros da solicitação, pois os parâmetros da solicitação não serão analisados ​​quando um cabeçalho da solicitação for obtido:

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

No entanto, o isAjaxRequest() pode ser chamado por qualquer ouvinte de fase ou ouvinte de evento do sistema ou alguma fábrica de aplicativos antes a visualização foi criada/restaurada.Então, quando você estiver usando PrimeFaces 3.x, os parâmetros da solicitação serão analisados antes a codificação de caracteres adequada foi definida e, portanto, usa a codificação padrão do servidor, que geralmente é ISO-8859-1.Isso vai bagunçar tudo.

Soluções

Existem várias maneiras de consertar:

  1. Use um filtro de servlet que define ServletRequest#setCharacterEncoding() com UTF-8.Configurando a codificação de resposta por ServletResponse#setCharacterEncoding() é, aliás, desnecessário, pois não será afetado por esse problema.

    @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);
        }
    
        // ...
    }
    

    Você só precisa levar em conta que HttpServletRequest#setCharacterEncoding() define apenas a codificação para parâmetros de solicitação POST, não para parâmetros de solicitação GET.Para parâmetros de solicitação GET, você ainda precisará configurá-los no nível do servidor.

    Se acontecer de você usar a biblioteca de utilitários JSF OmniFaces, esse filtro já vem pronto para uso, o CharacterEncodingFilter.Basta instalá-lo conforme abaixo em web.xml como primeira entrada de filtro:

    <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. Reconfigure o servidor para usar UTF-8 em vez de ISO-8859-1 como codificação padrão.No caso do Glassfish, seria uma questão de adicionar a seguinte entrada ao <glassfish-web-app> do /WEB-INF/glassfish-web.xml arquivo:

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

    Tomcat não suporta isso.Tem o URIEncoding atributo em <Context> entrada, mas isso se aplica apenas a solicitações GET, não a solicitações POST.


  3. Relate isso como um bug para PrimeFaces.Existe realmente algum motivo legítimo para verificar se a solicitação HTTP é uma solicitação ajax, verificando um parâmetro de solicitação em vez de um cabeçalho de solicitação, como você faria para JSF padrão e, por exemplo, jQuery?Os PrimeFaces' core.js JavaScript está fazendo isso.Seria melhor se ele fosse definido como um cabeçalho de solicitação de XMLHttpRequest.


Soluções que NÃO funcionam

Talvez você encontre as "soluções" abaixo em algum lugar da Internet enquanto investiga esse problema.Essas soluções nunca funcionarão neste caso específico.A explicação segue.

  • Configurando o prólogo XML:

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

    Isso apenas informa ao analisador XML para usar UTF-8 para decodificar a fonte XML antes de construir a árvore XML em torno dela.O analisador XML realmente usado pelo Facelts é SAX durante JSF ver o tempo de construção.Esta parte não tem nada a ver com codificação de solicitação/resposta HTTP.

  • Configurando metatag HTML:

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

    A meta tag HTML é ignorada quando a página é veiculada por HTTP por meio de um http(s):// URI.Só é usado quando a página é salva pelo cliente como um arquivo HTML no sistema de disco local e depois reaberta por um file:// URI no navegador.

  • Configurando o formulário HTML para aceitar o atributo charset:

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

    Os navegadores modernos ignoram isso.Isto só tem efeito no navegador Microsoft Internet Explorer.Mesmo assim, está fazendo isso de maneira errada.Nunca use.Todos os navegadores reais usarão o atributo charset especificado no Content-Type cabeçalho da resposta.Até o MSIE fará isso da maneira certa, desde que você não especifique o accept-charset atributo.

  • Configurando o argumento JVM:

    -Dfile.encoding=UTF-8
    

    Isso é usado apenas pela JVM Oracle(!) para ler e analisar os arquivos de origem Java.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top