Java e il problema dell'encoding dei caratteri

document_java Java e il problema dell'encoding dei caratteri
Oggi voglio trattare un problema abbastanza vasto sull'encoding (encode e decode) dei programmi in java. In generale la codifica (encode) più utilizzata è la UTF-8 che comprende un range vastissimo di caratteri che non dovrebbe creare problemi per nessuna lingua (e invece ne crea). Utilizzare però questa codifica crea un po' di problemi agli sviluppatori.
Vediamo alcuni utilissimi consigli.

Attualmente l'encoding più diffuso nel web è l'UTF-8.
Vediamo come scrivere un programma java - servlet based che utilizzi tale encoding.
Vedremo anche come gestire al meglio la scrittura su socket per supportare tale codifica.

1) I file XML del nostro programma java
Tutti i file XML devono contenere la seguente intestazione
<?xml version="1.0" encoding="UTF-8"?>
che indica l'uso della codifica UTF-8 per i file.

2) Le pagine JSP del nostro programma java
Tutte le pagine JSP devono contenere la seguente intestazione
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
che indica l'uso della codifica UTF-8 per i file.

3) Le pagine JSP / HTML del nostro programma java
Sia le pagine JSP che le pagine HTML devono contenere la seguente intestazione
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
che indica l'uso della codifica UTF-8 per i file.

4) I file delle traduzioni / label del nostro programma java
In questi file, i classici file *.properties che contengono le label, consiglio di non usare i caratteri accentati per le vocali ma di usare al loro posto le codifiche unicode:

 

carattere 'e' accentato: \u00E8
carattere 'a' accentato: \u00E0
carattere 'o' accentato: \u00F2
carattere 'u' accentato: \u00F9
carattere 'i' accentato: \u00EC

Così facendo non si avrà nessun problema di codifica dei caratteri.

In questa maniera si indica al sistema che le varie parti sono tutte scritte in UTF-8.

Come trattare però anche la request in UTF-8?

Lo si può fare mediante un filtro nella seguente maniera.

1) Si dichiara una classe per la gestione del filtro, ad es.
package my.filter;

import java.io.IOException;
import java.io.UnsupportedEncodingException;

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{

public CharsetFilter() {
//Costruttore
}

public void init(FilterConfig config) {
//Metodo per l'inizializzazione del filtro
}

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
//Applicazione del filtro
if(request.getCharacterEncoding() == null)
{
try {
request.setCharacterEncoding("UTF-8");
} catch (UnsupportedEncodingException e) {               
}
}

//Si passa il tutto alla sottostante catena di filtri
try {
chain.doFilter(request,response);
} catch (IOException e) {
} catch (ServletException e) {
}
}

public void destroy() {
//Metodo per la distruzione del filtro
}
}


2) Dichiarazione del filtro nel file web.xml
Per poter essere usato correttamente il filtro deve essere dichiarato nel file web.xml dell'applicazione
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<filter>
<filter-name>CharsetFilter</filter-name>
<filter-class>my.filter.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>


Con il filter-mapping si dice al sistema quando il filtro deve essere usato. Nel nostro caso sempre.
Così facendo, se si scrive in un campo di testo di una form un carattere UTF-8, il filtro imposterà correttamente la request in UTF-8 e tutto funzionerà correttamente.

Se tutte queste accortezze non dovessero essere sufficienti l'ultima cosa che si può fare, sia sotto Tomcat che sotto JBOSS, è di settare direttamente l'encoding in questi applicativi in maniera da trattare tutto il flusso con codifica UTF-8.

Se si usa Eclipse per lo sviluppo di programmi Java vi consiglio di leggere la mia guida su come impostare Eclipse per l'uso dell'UTF-8. La guida la trovate qui.

Java, i Socket e la scrittura UTF-8
Vediamo ora come ci si deve comportare se si ha a che fare con i socket. Il problema lo si ha in fase di scrittura e non in fase di lettura.
Utilizzando i socket una maniera che si può usare per scrivere nel socket è:
ServerSocket serverSocket = new ServerSocket(miaPorta);
Socket socket = serverSocket.accept();
socket.setKeepAlive(true);
DataOutputStream os = new DataOutputStream(socket.getOutputStream());
os.writeBytes("MIO TESTO UTF-8");
os.close();
socket.close();

In questa maniera però non si è UTF-8 compatibili.
Dovremmo usare invece il seguente codice
ServerSocket serverSocket = new ServerSocket(miaPorta);
Socket socket = serverSocket.accept();
socket.setKeepAlive(true);
Writer os = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), "UTF-8"));
os.write("MIO TESTO UTF-8");
os.close();
socket.close();


Ovvero, usare un Writer, specificando la codifica UTF-8, al posto del DataOutputStream e usare il metodo write().
Il DataOutputStream ha un metodo writeUTF() che però non consiglio di usare.

RIFERIMENTI
Un riferimento utilissimo lo trovate nell'articolo "Character entity references for ISO 8859-1 characters" qua.

We use cookies

Utilizziamo i cookie sul nostro sito Web. Alcuni di essi sono essenziali per il funzionamento del sito, mentre altri ci aiutano a migliorare questo sito e l'esperienza dell'utente (cookie di tracciamento). Puoi decidere tu stesso se consentire o meno i cookie. Ti preghiamo di notare che se li rifiuti, potresti non essere in grado di utilizzare tutte le funzionalità del sito.