Como fazer o UTF-8 funcionar em aplicativos da Web Java?

367

Eu preciso que o UTF-8 funcione no meu aplicativo da web Java (servlets + JSP, sem estrutura usada) para suportar äöåetc. para texto finlandês regular e alfabetos cirílico como ЦжФem casos especiais.

Minha configuração é a seguinte:

  • Ambiente de desenvolvimento: Windows XP
  • Ambiente de produção: Debian

Banco de dados usado: MySQL 5.x

Os usuários usam principalmente o Firefox2, mas também o Opera 9.x, FF3, IE7 e Google Chrome são usados ​​para acessar o site.

Como conseguir isso?

kosoant
fonte

Respostas:

552

Responder a mim mesmo como o FAQ deste site o encoraja. Isso funciona para mim:

Principalmente os caracteres äåö não são problemáticos, pois o conjunto de caracteres padrão usado pelos navegadores e o tomcat / java para webapps é latin1, ie. ISO-8859-1, que "entende" esses caracteres.

Para que o UTF-8 funcione em Java + Tomcat + Linux / Windows + Mysql, é necessário o seguinte:

Configurando o server.xml do Tomcat

É necessário configurar que o conector use UTF-8 para codificar os parâmetros de URL (solicitação GET):

<Connector port="8080" maxHttpHeaderSize="8192"
 maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
 enableLookups="false" redirectPort="8443" acceptCount="100"
 connectionTimeout="20000" disableUploadTimeout="true" 
 compression="on" 
 compressionMinSize="128" 
 noCompressionUserAgents="gozilla, traviata" 
 compressableMimeType="text/html,text/xml,text/plain,text/css,text/ javascript,application/x-javascript,application/javascript"
 URIEncoding="UTF-8"
/>

A parte principal sendo URIEncoding = "UTF-8" no exemplo acima. Isso garante que o Tomcat lide com todos os parâmetros GET recebidos como codificados em UTF-8. Como resultado, quando o usuário grava o seguinte na barra de endereços do navegador:

 https://localhost:8443/ID/Users?action=search&name=*ж*

o caractere ж é tratado como UTF-8 e é codificado para (geralmente pelo navegador antes mesmo de chegar ao servidor) como % D0% B6 .

A solicitação POST não é afetada por isso.

CharsetFilter

Chegou a hora de forçar o java webapp a lidar com todos os pedidos e respostas conforme codificado em UTF-8. Isso requer que definamos um filtro de conjunto de caracteres como o seguinte:

package fi.foo.filters;

import javax.servlet.*;
import java.io.IOException;

public class CharsetFilter implements Filter {

    private String encoding;

    public void init(FilterConfig config) throws ServletException {
        encoding = config.getInitParameter("requestEncoding");
        if (encoding == null) encoding = "UTF-8";
    }

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain next)
            throws IOException, ServletException {
        // Respect the client-specified character encoding
        // (see HTTP specification section 3.4.1)
        if (null == request.getCharacterEncoding()) {
            request.setCharacterEncoding(encoding);
        }

        // Set the default response content type and encoding
        response.setContentType("text/html; charset=UTF-8");
        response.setCharacterEncoding("UTF-8");

        next.doFilter(request, response);
    }

    public void destroy() {
    }
}

Esse filtro garante que, se o navegador não tiver definido a codificação usada na solicitação, esteja definido como UTF-8.

A outra coisa feita por esse filtro é definir a codificação de resposta padrão, ou seja. a codificação na qual o html retornado / o que quer que seja. A alternativa é definir a codificação da resposta etc. em cada controlador do aplicativo.

Esse filtro deve ser adicionado ao web.xml ou ao descritor de implementação do aplicativo da web:

 <!--CharsetFilter start--> 

  <filter>
    <filter-name>CharsetFilter</filter-name>
    <filter-class>fi.foo.filters.CharsetFilter</filter-class>
      <init-param>
        <param-name>requestEncoding</param-name>
        <param-value>UTF-8</param-value>
      </init-param>
  </filter>

  <filter-mapping>
    <filter-name>CharsetFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

As instruções para criar esse filtro são encontradas no wiki do tomcat ( http://wiki.apache.org/tomcat/Tomcat/UTF-8 )

Codificação de página JSP

No seu web.xml , adicione o seguinte:

<jsp-config>
    <jsp-property-group>
        <url-pattern>*.jsp</url-pattern>
        <page-encoding>UTF-8</page-encoding>
    </jsp-property-group>
</jsp-config>

Como alternativa, todas as páginas JSP do aplicativo da web precisariam ter o seguinte na parte superior:

 <%@page pageEncoding="UTF-8" contentType="text/html; charset=UTF-8"%>

Se algum tipo de layout com fragmentos JSP diferentes for usado, isso será necessário em todos eles.

Meta tags HTML

A codificação de página JSP informa à JVM para manipular os caracteres na página JSP na codificação correta. Chegou a hora de informar ao navegador em que codificação a página html está:

Isso é feito com o seguinte na parte superior de cada página xhtml produzida pelo aplicativo da web:

   <?xml version="1.0" encoding="UTF-8"?>
   <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
   <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fi">
   <head>
   <meta http-equiv='Content-Type' content='text/html; charset=UTF-8' />
   ...

Conexão JDBC

Ao usar um banco de dados, é necessário definir que a conexão use a codificação UTF-8. Isso é feito no context.xml ou onde quer que a conexão JDBC seja desativada da seguinte maneira:

      <Resource name="jdbc/AppDB" 
        auth="Container"
        type="javax.sql.DataSource"
        maxActive="20" maxIdle="10" maxWait="10000"
        username="foo"
        password="bar"
        driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/      ID_development?useEncoding=true&amp;characterEncoding=UTF-8"
    />

Banco de dados MySQL e tabelas

O banco de dados usado deve usar a codificação UTF-8. Isso é alcançado criando o banco de dados com o seguinte:

   CREATE DATABASE `ID_development` 
   /*!40100 DEFAULT CHARACTER SET utf8 COLLATE utf8_swedish_ci */;

Em seguida, todas as tabelas também precisam estar em UTF-8:

   CREATE TABLE  `Users` (
    `id` int(10) unsigned NOT NULL auto_increment,
    `name` varchar(30) collate utf8_swedish_ci default NULL
    PRIMARY KEY  (`id`)
   ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_swedish_ci ROW_FORMAT=DYNAMIC;

A parte principal sendo CHARSET = utf8 .

Configuração do servidor MySQL

O servidor MySQL também deve ser configurado. Normalmente, isso é feito no Windows, modificando o arquivo my.ini e no Linux, configurando o arquivo my.cnf . Nesses arquivos, deve-se definir que todos os clientes conectados ao servidor usem utf8 como o conjunto de caracteres padrão e que o conjunto de caracteres padrão usado pelo servidor também seja utf8.

   [client]
   port=3306
   default-character-set=utf8

   [mysql]
   default-character-set=utf8

Procedimentos e funções Mysql

Eles também precisam ter o conjunto de caracteres definido. Por exemplo:

   DELIMITER $$

   DROP FUNCTION IF EXISTS `pathToNode` $$
   CREATE FUNCTION `pathToNode` (ryhma_id INT) RETURNS TEXT CHARACTER SET utf8
   READS SQL DATA
   BEGIN

    DECLARE path VARCHAR(255) CHARACTER SET utf8;

   SET path = NULL;

   ...

   RETURN path;

   END $$

   DELIMITER ;

Solicitações GET: latin1 e UTF-8

Se e quando for definido no server.xml do tomcat que os parâmetros de solicitação GET sejam codificados em UTF-8, as seguintes solicitações GET serão tratadas adequadamente:

   https://localhost:8443/ID/Users?action=search&name=Petteri
   https://localhost:8443/ID/Users?action=search&name=ж

Como os caracteres ASCII são codificados da mesma maneira com latin1 e UTF-8, a sequência "Petteri" é manipulada corretamente.

O caráter cirílico ж não é totalmente compreendido em latim1. Como o Tomcat é instruído a manipular parâmetros de solicitação como UTF-8, ele codifica esse caractere corretamente como % D0% B6 .

Se e quando os navegadores forem instruídos a ler as páginas na codificação UTF-8 (com cabeçalhos de solicitação e metatag html), pelo menos o Firefox 2/3 e outros navegadores desse período codificarão o caractere como % D0% B6 .

O resultado final é que todos os usuários com o nome "Petteri" são encontrados e também todos os usuários com o nome "ж".

Mas e quanto a äåö?

A especificação HTTP define que, por padrão, os URLs são codificados como latin1. Isso resulta no firefox2, firefox3 etc., codificando os seguintes

    https://localhost:8443/ID/Users?action=search&name=*Päivi*

para a versão codificada

    https://localhost:8443/ID/Users?action=search&name=*P%E4ivi*

Em latin1, o caractere ä é codificado como % E4 . Mesmo que a página / solicitação / tudo esteja definido para usar UTF-8 . A versão codificada em UTF-8 de ä é % C3% A4

O resultado disso é que é praticamente impossível para o aplicativo da web manipular corretamente os parâmetros de solicitação GET, pois alguns caracteres são codificados em latin1 e outros em UTF-8. Aviso: solicitações POST funcionam como navegadores codificam todos os parâmetros de solicitação de formulários completamente em UTF-8 se a página for definida como sendo UTF-8

Coisas para ler

Muito obrigado pelos escritores a seguir por dar as respostas para o meu problema:

  • http://tagunov.tripod.com/i18n/i18n.html
  • http://wiki.apache.org/tomcat/Tomcat/UTF-8
  • http://java.sun.com/developer/technicalArticles/Intl/HTTPCharset/
  • http://dev.mysql.com/doc/refman/5.0/en/charset-syntax.html
  • http://cagan327.blogspot.com/2006/05/utf-8-encoding-fix-tomcat-jsp-etc.html
  • http://cagan327.blogspot.com/2006/05/utf-8-encoding-fix-for-mysql-tomcat.html
  • http://jeppesn.dk/utf-8.html
  • http://www.nabble.com/request-parameters-mishandle-utf-8-encoding-td18720039.html
  • http://www.utoronto.ca/webdocs/HTMLdocs/NewHTML/iso_table.html
  • http://www.utf8-chartable.de/

Nota importante

suporta o plano multilíngue básico usando caracteres UTF-8 de 3 bytes. Se você precisar ir além disso (determinados alfabetos requerem mais de 3 bytes de UTF-8), será necessário usar um VARBINARYtipo de coluna ou usar o utf8mb4conjunto de caracteres (que requer o MySQL 5.5.3 ou posterior). Lembre-se de que o uso do utf8conjunto de caracteres no MySQL não funcionará 100% do tempo.

Tomcat com Apache

Mais uma coisa Se você estiver usando o conector Apache + Tomcat + mod_JK, também precisará fazer as seguintes alterações:

  1. Inclua URIEncoding = "UTF-8" no arquivo tomcat server.xml para o conector 8009, que é usado pelo conector mod_JK. <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" URIEncoding="UTF-8"/>
  2. Vá para a pasta apache, ou seja, /etc/httpd/confadicione AddDefaultCharset utf-8-a httpd.conf file. Nota: Primeiro verifique se existe ou não. Se existir, você pode atualizá-lo com esta linha. Você pode adicionar esta linha na parte inferior também.
kosoant
fonte
Essas etapas também funcionam com Struts / tiles e um banco de dados postgres.
kosoant 26/09/08
17
Dois comentários: 1) nas metatags HMTL você incluiu uma declaração xml. Remova-o, isso ativaria apenas os navegadores no modo quirks, você não quer ter isso. Além disso, as metatags HTML já são feitas de forma implícita pelo JSP pageEncoding, para que você possa deixá-lo de fora. 2) no banco de dados MySQL e nas tabelas que você usou utf8_swedish_si, deveria ter sido utf8_unicode_ci. Você pode até deixar o agrupamento de lado, basta CHARACTER SET utf8.
BalusC 04/12/2009
Nenhum dos documentos que consultei sobre metatags HTML e modo quirks (por exemplo , ericmeyeroncss.com/bonus/render-mode.html , en.wikipedia.org/wiki/Quirks_mode ) indicam que a presença de <meta http-equiv = 'Content -Type 'tem algum impacto no modo de renderização.
Marcel Stör
Como uma observação interessante, você também pode estar ciente de que, se você tiver um ouvinte que acesse um parâmetro de solicitação, precisará adicionar um ouvinte que defina o conjunto de caracteres em vez de um filtro, porque os ouvintes são executados antes dos filtros. Eu segui todas as etapas e ainda não funcionou por causa disso. Apenas pensei em transmitir essas informações, caso alguém tenha um problema semelhante.
usar o seguinte
3
## Tomcat with Apache ## Mais uma coisa Se você estiver usando o conector Apache + Tomcat + mod_JK, também precisará fazer as seguintes alterações: 1. Adicione URIEncoding = "UTF-8" no arquivo tomcat server.xml para o conector 8009, é usado pelo conector mod_JK. <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" URIEncoding="UTF-8"/> 2. Vá para a pasta apache, ou seja, /etc/httpd/confadicione AddDefaultCharset utf-8o arquivo 'httpd.conf'. Nota: primeiro verifique se existe ou não. Se existir, você pode atualizá-lo com esta linha. Você pode adicionar esta linha na parte inferior também.
Vijay Shegokar
14

Acho que você resumiu bastante bem em sua própria resposta.

No processo de UTF-8-ing (?) De ponta a ponta, você também pode querer garantir que o próprio java esteja usando UTF-8. Use -Dfile.encoding = utf-8 como parâmetro para a JVM (pode ser configurado em catalina.bat).

stian
fonte
Isso me ajudou, fiz tudo o que foi mencionado, mas a codificação JVM era windows-1250 assim que mudei para UTF-8 e funcionou perfeitamente.
Coding_idiot
2
Onde você adiciona isso no arquivo Catalina.bat, por favor?
Noah
11

Para adicionar à resposta do kosoant , se você estiver usando o Spring, em vez de escrever seu próprio filtro Servlet, poderá usar a classe que org.springframework.web.filter.CharacterEncodingFiltereles fornecem, configurando-a da seguinte forma em seu web.xml:

 <filter>
    <filter-name>encoding-filter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
       <param-name>encoding</param-name>
       <param-value>UTF-8</param-value>
    </init-param>
    <init-param>
       <param-name>forceEncoding</param-name>
       <param-value>FALSE</param-value>
    </init-param>
 </filter>
 <filter-mapping>
    <filter-name>encoding-filter</filter-name>
    <url-pattern>/*</url-pattern>
 </filter-mapping>
Raedwald
fonte
11
Esse filtro deve ser o primeiro filtro em web.xml
olyanren 5/05
2

Também quero adicionar daqui que esta parte resolveu meu problema de utf:

runtime.encoding=<encoding>
John
fonte
1

Isto é para codificação grega nas tabelas MySql quando queremos acessá-las usando Java:

Use a seguinte configuração de conexão no seu pool de conexões JBoss (mysql-ds.xml)

<connection-url>jdbc:mysql://192.168.10.123:3308/mydatabase</connection-url>
<driver-class>com.mysql.jdbc.Driver</driver-class>
<user-name>nts</user-name>
<password>xaxaxa!</password>
<connection-property name="useUnicode">true</connection-property>
<connection-property name="characterEncoding">greek</connection-property>

Se você não quiser colocar isso em um conjunto de conexões JNDI, poderá configurá-lo como um JDBC-url, como a próxima linha ilustra:

jdbc:mysql://192.168.10.123:3308/mydatabase?characterEncoding=greek

Para mim e Nick, para nunca mais esquecermos e perdermos tempo ...

Mike Mountrakis
fonte
5
Eu ainda preferiria o UTF-8 acima do grego (e converter seus dados gregos atuais em UTF-8) para que seu aplicativo esteja pronto para o domínio mundial.
BalusC 04/12/2009
1

Boa resposta detalhada. só queria adicionar mais uma coisa que definitivamente ajudará outras pessoas a ver a codificação UTF-8 nos URLs em ação.

Siga as etapas abaixo para ativar a codificação UTF-8 em URLs no firefox.

  1. digite "about: config" na barra de endereços.

  2. Use o tipo de entrada de filtro para procurar a propriedade "network.standard-url.encode-query-utf8".

  3. a propriedade acima será falsa por padrão, coloque-a em TRUE.
  4. reinicie o navegador.

A codificação UTF-8 nos URLs funciona por padrão no IE6 / 7/8 e no chrome.

Jay
fonte
1

Respostas anteriores não funcionaram com o meu problema. Foi apenas em produção, com tomcat e apache mod_proxy_ajp. Post corpo perdeu chars não ascii por? Finalmente, o problema foi com o JVM defaultCharset (US-ASCII em uma instalação padrão: Charset dfset = Charset.defaultCharset ();); portanto, a solução foi executada no servidor tomcat com um modificador para executar a JVM com UTF-8 como charset padrão:

JAVA_OPTS="$JAVA_OPTS -Dfile.encoding=UTF-8" 

(inclua esta linha em catalina.sh e reinicie o tomcat de serviço)

Talvez você também precise alterar a variável de sistema linux (edite ~ / .bashrc e ~ / .profile para alterações permanentes, consulte https://perlgeek.de/en/article/set-up-a-clean-utf8-environment )

exportar LC_ALL = en_US.UTF-8
exportar LANG = en_US.UTF-8

exportar LANGUAGE = pt_BR.UTF-8

Rogelio Triviño
fonte
0

Estou com um problema semelhante, mas, nos nomes de arquivos de um arquivo, estou compactando com o apache commons. Então, eu resolvi com este comando:

convmv --notest -f cp1252 -t utf8 * -r

Funciona muito bem para mim. Espero que ajude alguém;)

caarlos0
fonte
0

No meu caso de exibição de caracteres Unicode em pacotes de mensagens, não preciso aplicar a seção "JSP page codification" para exibir Unicode na minha página jsp. Tudo o que preciso é da seção "CharsetFilter".

bnguyen82
fonte
0

Outro ponto que não foi mencionado diz respeito aos Servlets Java que trabalham com o Ajax. Tenho situações em que uma página da Web está captando texto utf-8 do usuário que está enviando para um arquivo JavaScript que o inclui em um URI enviado ao Servlet. O Servlet consulta um banco de dados, captura o resultado e o retorna como XML para o arquivo JavaScript que o formata e insere a resposta formatada na página da web original.

Em um aplicativo Web, eu estava seguindo as instruções de um livro do Ajax para encerrar o JavaScript na construção do URI. O exemplo no livro usou o método escape (), que eu descobri (da maneira mais difícil) que está errado. Para utf-8, você deve usar encodeURIComponent ().

Hoje em dia, poucas pessoas lançam seu próprio Ajax, mas pensei em acrescentar isso.

David
fonte
0

Sobre CharsetFiltermencionado na resposta @kosoant ....

Existe uma compilação Filterno tomcat web.xml(localizada em conf/web.xml). O filtro é nomeado setCharacterEncodingFiltere é comentado por padrão. Você pode descomentar isso (lembre-se de descomentar filter-mappingtambém)

Também não há necessidade de configurar o jsp-configseu web.xml(eu testei para o Tomcat 7+)

Alireza Fattahi
fonte
0

Algum tempo você pode resolver o problema através do assistente MySQL Administrator. No

Variáveis ​​de inicialização> Avançado>

e defina Def. conjunto de caracteres: utf8

Talvez essa configuração precise reiniciar o MySQL.

user3600935
fonte
0

Enfrentou o mesmo problema no Spring MVC 5 + Tomcat 9 + JSP.
Após a longa pesquisa, chegou a uma solução elegante ( sem necessidade de filtros e necessidade mudanças no Tomcat server.xml (a partir da versão 8.0.0-RC3))

  1. Na implementação do WebMvcConfigurer, defina a codificação padrão para messageSource (para ler dados de arquivos de origem de mensagens na codificação UTF-8.

    @Configuration
    @EnableWebMvc
    @ComponentScan("{package.with.components}")
    public class WebApplicationContextConfig implements WebMvcConfigurer {
    
        @Bean
        public MessageSource messageSource() {
            final ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
    
            messageSource.setBasenames("messages");
            messageSource.setDefaultEncoding("UTF-8");
    
            return messageSource;
        }
    
        /* other beans and methods */
    
    }
  2. Na implementação DispatcherServletInitializer, substitua o método onStartup e defina a codificação de solicitação e de caractere de recurso.

    public class DispatcherServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
    
        @Override
        public void onStartup(final ServletContext servletContext) throws ServletException {
    
            // https://wiki.apache.org/tomcat/FAQ/CharacterEncoding
            servletContext.setRequestCharacterEncoding("UTF-8");
            servletContext.setResponseCharacterEncoding("UTF-8");
    
            super.onStartup(servletContext);
        }
    
        /* servlet mappings, root and web application configs, other methods */
    
    }
  3. Salve todas as fontes de mensagens e visualize os arquivos na codificação UTF-8.

  4. Adicione <% @ page contentType = "text / html; charset = UTF-8"%> ou <% @ page pageEncoding = "UTF-8"%> em cada arquivo * .jsp ou adicione o descritor jsp-config ao web.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"
     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
     id="WebApp_ID" version="3.0">
        <display-name>AppName</display-name>
    
        <jsp-config>
            <jsp-property-group>
                <url-pattern>*.jsp</url-pattern>
                <page-encoding>UTF-8</page-encoding>
            </jsp-property-group>
        </jsp-config>
    </web-app>
Andrei Veshtard
fonte
-1

Caso você tenha especificado no conjunto de conexões (mysql-ds.xml), no seu código Java, você pode abrir a conexão da seguinte maneira:

DriverManager.registerDriver(new com.mysql.jdbc.Driver());
Connection conn = DriverManager.getConnection(
    "jdbc:mysql://192.168.1.12:3308/mydb?characterEncoding=greek",
    "Myuser", "mypass");
Mike Mountrakis
fonte