segunda-feira, 7 de fevereiro de 2011

JSF Acentuação IE

Olá, eu estava tendo problemas com caracteres especiais.. nos meus cadastros as palavras que tinham acento ou cedilha chegavam no java desconfiguradas (São Paulo virava São Paulo).

Fiz algumas tentativas frustradas:

<f:view contentType="text/html; charset=UTF-8" encoding="UTF-8">
<f:view contentType="text/html; charset=ISO-8859-1" encoding="ISO-8859-1">
<meta http-equiv='Content-Type' content='text/html; charset=UTF-8' />
<meta http-equiv='Content-Type' content='text/html; charset=ISO-8859-1' />
<h:form acceptcharset="UTF-8">
<h:form acceptcharset="ISO-8859-1"> (essa funcionou em todos os browsers, menos no ie)

Alterei o web.xml:
<locale-encoding-mapping-list>
<locale-encoding-mapping>
<locale>pt< <encoding>ISO-8859-1</encoding> (tentei com UTF-8 tmb)
</locale-encoding-mapping>
</locale-encoding-mapping-list>

Mas nada funcionou...

Pra resolver fiz o seguinte:

Coloquei a seguinte linha no início de todos os .xhtml
<?xml version="1.0" encoding="UTF-8"?>

No web.xml eu adicionei o seguinte:
<filter>
<filter-name>CharsetFilter</filter-name>
<filter-class>br.com.localhost8080.infrastructure.CharsetFilter</filter-class>
<init-param>
<param-name>requestEncoding</param-name>
<param-value>ISO-8859-1</param-value>
</init-param>
</filter>

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

E criei uma classe chamada CharsetFilter no pacote br.com.localhost8080.infrastructure:

package br.com.localhost8080.infrastructure;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public class CharsetFilter implements Filter {

private String encoding;

public void init(FilterConfig config) throws ServletException {
this.encoding = config.getInitParameter("requestEncoding");

if (this.encoding == null) {
this.encoding = "ISO-8859-1";
}
}

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

response.setContentType("text/html; charset=ISO-8859-1");
response.setCharacterEncoding("ISO-8859-1");

next.doFilter(request, response);
}

public void destroy() {
}
}

Isso resolveu o problema de acentuação no submit dos formulários em todos os browsers (Para essa resolução foi de grande ajuda o site stackoverflow.com)

Porém... eu ainda tava com problemas no internet explorer em alguns campos que eram atualizados via ajax ou via rerenderização da tela no retorno de forms.

Para resolver isso criei dois converters, um eu uso para campos atualizados via ajax (ConverterCharset) e outro eu uso para campos atualizados via rerenderização da tela nos retornos dos forms (ConverterString).

Para campos atualizados via ajax é necessário adicionar converter="converterCharset"
<h:inputText value="#{myBean.myObject.name}" converter="converterCharset"/>

ConverterCharset.java:
package br.com.localhost8080.infrastructure;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.ConverterException;
import javax.faces.convert.FacesConverter;

import br.com.localhost8080.infrastructure.StringUtils;

@FacesConverter(value = "converterCharset")
public class ConverterCharset implements Converter {

public Object getAsObject(FacesContext arg0, UIComponent arg1, String value) throws ConverterException {
return value;
}

public String getAsString(FacesContext arg0, UIComponent arg1, Object value) throws ConverterException {
String convertedString = StringUtils.convertUtf8ToIso88591(value);
return convertedString;
}
}

ConverterString.java:

package br.com.localhost8080.infrastructure;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.ConverterException;
import javax.faces.convert.FacesConverter;

import br.com.localhost8080.infrastructure.StringUtils;

@FacesConverter(forClass = String.class, value="Test")
public class ConverterString implements Converter {

//vem da tela / request
public Object getAsObject(FacesContext arg0, UIComponent arg1, String value) throws ConverterException {
if ("".equals(value.toString().trim())) {
return null;
}

String convertedString = StringUtils.convertUtf8ToIso88591(value);
return convertedString;
}

//vai para tela / response
public String getAsString(FacesContext arg0, UIComponent arg1, Object value) throws ConverterException {
String convertedString = StringUtils.convertUtf8ToIso88591(value);
return convertedString;
}
}

Ambos os converters tinham um código de conversão de UTF-8 para ISO-8859-1 que foi externalizado para a classe StringUtils.
package br.com.localhost8080.infrastructure;

public class StringUtils {
/**
* Verifica se valor string do objeto passado como parametro e UTF-8 e entao converte para ISO-8859-1
*/
public static String convertUtf8ToIso88591(Object value) {
if (value instanceof String == false) {
return value.toString();
}

String originalValue = (String) value;

// verifica se e UTF-8 (se tem caracteres especiais)
if (originalValue.contains("Ã") || originalValue.contains("Â")) {
java.nio.charset.Charset utf8charset = java.nio.charset.Charset.forName("UTF-8");
java.nio.charset.Charset iso88591charset = java.nio.charset.Charset.forName("ISO-8859-1");
java.nio.ByteBuffer inputBuffer = java.nio.ByteBuffer.wrap(originalValue.getBytes());
// decode UTF-8
java.nio.CharBuffer data = utf8charset.decode(inputBuffer);
// encode ISO-8559-1
java.nio.ByteBuffer outputBuffer = iso88591charset.encode(data);
byte[] outputData = outputBuffer.array();

String convertedString = new String(outputData);

// se a conversao deu errado retorna o valor original
if (convertedString.contains("?")) {
return originalValue;
}

// retorna o valor convertido
return convertedString;
}

return originalValue;
}
}


É isso.. sem mais problemas de acentuação.

Abraço,
Adriano Schmidt

4 comentários:

  1. Cara, muito obrigado. Aproveitei parte do seu código, mais especificamente o método que faz a conversão da String de UTF-8 para ISO-8859-1.

    Salvou meu dia!

    ResponderExcluir
  2. opa cara muito bom e resolveu meu problema era EXATAMENTE o que eu precisava vlw

    ResponderExcluir
  3. Adriano,

    Enfrentei o mesmo problema porém solucionei de forma diferente. Como uso Facelets, apenas coloquei encoding="ISO-8859-1" na tag f:view, ficando assim:



    Abs

    ResponderExcluir
  4. Bom dia, Adriano. Desculpe voltar nesse tópico antigo mas estou passando pelo mesmo problema, ainda sem solução. Minha dúvid é: qual o charset e collation utiizado num banco mysql?

    ResponderExcluir