Ввод Unicode, полученный через компоненты ввода PrimeFaces, поврежден - PullRequest
13 голосов
/ 09 марта 2012

Когда я все еще использовал PrimeFaces v2.2.1, я мог набирать ввод Unicode, например китайский, с компонентом ввода PrimeFaces, таким как <p:inputText> и <p:editor>, и извлекать ввод в хорошей форме в методе управляемого компонента.

Однако после того, как я обновился до PrimeFaces v3.1.1, все эти символы стали моджибаке или вопросительными знаками.Хорошо вводится только латинский ввод, это искаженные символы китайского, арабского, иврита, кириллицы и т. Д.

Как это вызвано и как я могу это решить?

1 Ответ

23 голосов
/ 23 марта 2012

Введение

Обычно JSF / Facelets устанавливает кодировку символов параметра запроса в UTF-8 по умолчанию уже при создании / восстановлении представления.Но если какой-либо параметр запроса был запрошен за до , представление было создано / восстановлено, тогда уже слишком поздно устанавливать правильную кодировку символов.А именно параметры запроса будут проанализированы только один раз.

Ошибка кодирования PrimeFaces

Ошибка в PrimeFaces 3.x после обновления с 2.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.Это все испортит.

Решения

Есть несколько способов исправить это:

  1. Использовать фильтр сервлетов , которыйустанавливает 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 , такой фильтр уже имеется в наличии 1049 *.Просто установите его, как показано ниже в 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>
    

  2. Переконфигурируйте сервер для использования 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.


  3. Сообщите об этом как об ошибке в PrimeFaces.Есть ли на самом деле какая-либо законная причина для проверки того, что HTTP-запрос является ajax-запросом, проверяя параметр запроса вместо заголовка запроса, как, например, для стандартного JSF и, например, jQuery?JavaScript-код PrimeFaces core.js делает это.Было бы лучше, если бы он установил его в качестве заголовка запроса XMLHttpRequest.


Решения, которые НЕ работают

Возможно, вы наткнетесь наниже «решения» где-то в интернете, пока исследуем эту проблему.Эти решения никогда не будут работать в этом конкретном случае.Объяснение приведено ниже.

  • Настройка пролога XML:

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

    Это только говорит синтаксическому анализатору XML использовать UTF-8 для декодирования источника XML перед построением дерева XML вокругЭто.Анализатор XML, фактически используемый Facelts, является SAX во время JSF просмотра времени сборки .Эта часть не имеет ничего общего с HTTP-запросом / ответной кодировкой.

  • Настройка метатега HTML:

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

    Метатег HTML игнорируется, когда страницаобслуживается по HTTP через http(s):// URI.Он используется только в том случае, когда клиент сохраняет страницу в виде файла HTML на локальной дисковой системе, а затем повторно открывает URI file:// в браузере.

  • Настройка HTML-формы принимает атрибут charset:

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

    Современные браузеры игнорируют это.Это действует только в браузере Microsoft Internet Explorer.Даже тогда он делает это неправильно.Никогда не используйте это.Вместо этого все настоящие веб-браузеры будут использовать атрибут charset, указанный в заголовке Content-Type ответа.Даже MSIE будет делать это правильно, если вы не укажете атрибут accept-charset.

  • Установка аргумента JVM:

    -Dfile.encoding=UTF-8
    

    Это используется толькоOracle (!) JVM для чтения и анализа исходных файлов Java.

...