на главную обучение сертификация статьи литература ссылки гостевая книга
  Список статей Оглавление Текст статьи  

Java: Русские буквы и не только...

Автор:Астахов Сергей
Создан:03.06.2003


8. Русские буквы в Servlet-ах

   Ну, для чего эти самые Servlet-ы нужны, я думаю, Вы в курсе. Если нет - то лучше сначала прочитать документацию. Здесь же рассказывается только об особенностях работы с русскими буквами.    Так в чём же особенности? Когда Servlet посылает ответ клиенту, есть два способа послать этот ответ - через OutputStream (метод getOutputStream()) или через PrintWriter (метод getWriter()). В первом случае Вы записываете массивы байтов, поэтому применимы вышеописанные методы записи в потоки. В случае же PrintWriter, он использует установленную кодировку. В любом случае необходимо правильно указать используемую кодировку при вызове метода setContentType(), для того, чтобы было правильное преобразование символов на стороне сервера. Это указание должно быть сделано перед вызовом getWriter() или перед первой записью в OutputStream. Пример:
  public void doPost(HttpServletRequest request,
    HttpServletResponse response)throws ServletException,IOException
  {
   //Установка кодировки ответа
   //Учтите, что некоторые engine не допускают
   //наличие пробела между ';' и 'charset'
   response.setContentType("text/html;charset=Windows-1251");

   PrintWriter out = response.getWriter();

   //Отладочный вывод названия кодировки для проверки
   out.println("Encoding: "+response.getCharacterEncoding());
   ...
   out.close();
  }
   Это по поводу отдачи ответов клиенту. Со входными параметрами, к сожалению не так просто. Входные параметры кодируются броузером побайтно в соответствии с MIME-типом "application/x-www-form-urlencoded". Как рассказал Алексей Менделев русские буквы броузеры кодируют, используя текущую установленную кодировку. Ну и, разумеется, ничего о ней не сообщают. Соответственно, например, в JSDK версий от 2.0 до 2.2 это никак не проверяется, а то, что за кодировка будет использована для преобразования - зависит от используемого engine (обычно ISO-8859-1). Начиная со спецификации 2.3 появилась возможность устанавливать кодировку для javax.servlet.ServletRequest - метод setCharacterEncoding(). Эту спецификацию уже поддерживают последние версии Resin и Tomcat.

   Таким образом, если Вам повезло, и у Вас стоит сервер с поддержкой Servlet 2.3, то всё довольно просто:
  public void doPost(HttpServletRequest request,
    HttpServletResponse response)throws ServletException,IOException
  {
   //Кодировка сообщений
   request.setCharacterEncoding("Cp1251");

   String value = request.getParameter("value");
   ...
   В применении метода request.setCharacterEncoding() есть одна существенная тонкость - он должен быть применен до первого обращения к запросу за данными (например request.getParameter()). Если Вы используете фильтры, которые обрабатывают запрос до того как он приходит в сервлет, есть ненулевая вероятность того, что в одном из фильтров может произойти чтение какого-нибудь параметра из запроса (например для авторизации) и request.setCharacterEncoding() в сервлете не сработает.

   Потому идеологически более правильно написать фильтр, устанавливающий кодировку запроса. При этом он должен стоять первым в цепочке фильтров в web.xml.
Пример такого фильтра:
  import java.io.*;
  import java.util.*;
  import javax.servlet.*;
  import javax.servlet.http.*;

  public class CharsetFilter implements Filter{
    //кодировка
    private String encoding;

    public void init(FilterConfig config) throws ServletException{
      //читаем из конфигурации
      encoding=config.getInitParameter("requestEncoding");

      //если не установлена - устанавливаем Cp1251
      if(encoding==null) encoding="Cp1251";
    }

    public void doFilter(ServletRequest request,
	   ServletResponse response, FilterChain next)
         throws IOException, ServletException{
      request.setCharacterEncoding(encoding);
      next.doFilter(request, response);
    }

    public void destroy(){}
  }
И его конфигурации в файле web.xml:
  <!--CharsetFilter start-->
  <filter>
    <filter-name>Charset Filter</filter-name>
    <filter-class>CharsetFilter</filter-class>
      <init-param>
        <param-name>requestEncoding</param-name>
        <param-value>Cp1251</param-value>
      </init-param>
  </filter>

  <filter-mapping>
    <filter-name>Charset Filter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
 <!--CharsetFilter end-->
   Если же Вам не повезло, и у Вас более старая версия контейнера сервлетов - для достижения результата придётся поизвращаться:
  • Оригинальный способ работы с кодировками предлагает Russian Apache.

  • Своё решение проблемы так же предложил Вячеслав Педак.

  • Ну а самый простейший вариант извлечь таки символы - передавать в комплекте параметров имя кодировки (или, если вы уверены в текущей кодировке броузера, использовать предопределённую кодировку) и использовать метод перекодировки символов:
      public void doPost(HttpServletRequest request,
        HttpServletResponse response)
    	  throws ServletException,IOException{
       //Кодировка сообщений, использованная engine
       //Некоторые используют ISO-8859-1, некоторые кодировку
       //по умолчанию - единообразия тут нет
       String requestEnc="ISO-8859-1";
    
       //Кодировка, установленная в броузере
       String clientEnc=request.getParameter("charset");
    
       if(clientEnc==null) clientEnc="Cp1251";
    
       //Получение параметра
       String value=request.getParameter("value");
    
       // 
       if(value!=null)
          value=new String(value.getBytes(requestEnc),clientEnc);
       ...
    


назад оглавление дальше