2010-03-28 6 views
5

Certains pseudo-code:encodage de caractères dans le application web typique Java

String a = "A bunch of text"; //UTF-16 
saveTextInDb(a); //Write to Oracle VARCHAR(15) column 
String b = readTextFromDb(); //UTF-16 
out.write(b); //Write to http response 

Lorsque vous enregistrez Java String (UTF-16) à Oracle VARCHAR (15) ne Oracle stocke aussi ce que UTF-16? La longueur d'un Oracle VARCHAR se réfère-t-elle au nombre de caractères Unicode (et non au nombre d'octets)?

Lorsque nous écrivons b au ServletResponse cela est-il écrit en UTF-16 ou sommes-nous en train de convertir par défaut en un autre encodage comme UTF-8?

Répondre

4

Au lieu de UTF-16, pensez à la «représentation interne» de votre chaîne. Une chaîne en Java est une sorte de caractères, peu importe le codage utilisé en interne. L'encodage devient pertinent si vous interagissez avec l'extérieur du programme. Dans votre exemple saveTextInDb, readTextFromDb et write font cela. Chaque fois que vous échangez des chaînes avec l'extérieur, un encodage pour la conversion est utilisé. saveTextInDb (et read) ressemble à des méthodes self-made, au moins je ne les connais pas. Vous devriez donc rechercher quel encodage est utilisé pour cette méthode. La méthode write d'un Writer crée toujours des octets, qui représentent un encodage associé à l'écrivain. Si vous obtenez votre Writer d'une réponse HttpServletResponse, le codage associé est celui utilisé pour la sortie de la réponse (qui sera envoyée dans les en-têtes).

response.setEncoding("UTF-8"); 
Writer out = response.getWriter(); 

Ce code retourne sans un Writer, qui traduit les chaînes en codage UTF-8. Même si vous écrivez un fichier:

Writer fileout = new OutputStreamWriter(new FileOutputStream(myfile), "ISO8859-1"); 

Si vous accédez à un DB, le cadre que vous utilisez devrait assurer un échange constant de chaînes avec la base de données.

3

Le ServletResponse utilisera ISO 8859-1 (Latin 1) par défaut. UTF-8 est l'encodage le plus commun utilisé pour les réponses HTTP qui nécessitent Unicode, mais vous devez définir ce codage spécifiquement.

Selon this document Oracle peut prendre en charge UTF-8 ou UTF-16 dans la base de données. Vos méthodes qui lisent/écrivent Oracle devront utiliser le codage approprié qui correspond à la façon dont la base de données est configurée, et la traduire vers/depuis la représentation interne de Java.

4

La capacité d'Oracle à stocker (et extraire ultérieurement) du texte Unicode à partir de la base de données repose uniquement sur le jeu de caractères de la base de données (généralement spécifié lors de la création de la base de données). Choisir AL32UTF8 comme jeu de caractères est recommandé pour stocker le texte Unicode dans les types de données CHAR (y compris VARCHAR/VARCHAR2), car il vous permettra d'accéder à tous les points de code Unicode sans consommer beaucoup d'espace de stockage par rapport aux autres encodages comme AL16UTF16/AL32UTF32. En supposant que cela soit fait, c'est le pilote Oracle JDBC qui est responsable de la conversion des données encodées en UTF-16 en AL32UTF8. Cette conversion "automatique" entre codages se produit également lorsque des données sont lues dans la base de données. Pour répondre à la requête sur la longueur en octets de VARCHAR, la définition d'une colonne VARCHAR2 dans Oracle implique une sémantique des octets - VARCHAR2 (n) est utilisé pour définir une colonne pouvant stocker n octets (comportement par défaut, spécifié par le paramètre NLS_LENGTH_SEMANTICS de la base de données); Si vous avez besoin de définir la taille en fonction des caractères, VARCHAR2 (n CHAR) doit être utilisé.

Le codage des données écrites dans l'objet ServletResponse dépend du codage de caractères par défaut, sauf si cela est spécifié via les appels d'API ServletResponse.setCharacterEncoding() ou ServletResponse.setContentType().Dans l'ensemble, pour une solution Unicode complète impliquant une base de données Oracle, il faut avoir une connaissance de

  1. Le codage des données entrantes (à savoir le codage des données lues via l'objet ServletRequest). Cela peut être fait en spécifiant l'encodage accepté dans les formulaires HTML via le accept-charset attribute. Si le codage est inconnu, l'application pourrait tenter de le définir à une valeur connue via la méthode ServletRequest.setCharacterEncoding(). Cette méthode ne modifie pas le codage existant des caractères dans le flux. Si le flux d'entrée est en ISO-Latin1, la spécification d'un codage différent entraînera très probablement une exception. Il est important de connaître le codage, car les bibliothèques d'exécution Java nécessitent une connaissance du codage d'origine du flux, si le contenu du flux doit être traité en tant que primitives de caractères ou chaînes. Apparemment, cela est requis lorsque vous appelez ServletRequest.getParameter ou des méthodes similaires qui traitent le flux et retournent des objets String. Le processus de décodage se traduira par la création de caractères dans le codage de la plate-forme (c'est UTF-16).
  2. Codage des données lues dans les flux, par opposition aux données créées avec la JVM. Ceci est très important, car le codage des données lues à partir des flux ne peut pas être modifié. Il existe cependant un processus de décodage qui convertira les caractères des caractères codés pris en charge en caractères UTF-16, chaque fois que ces données sont accédées en tant que primitives de caractères ou en tant que chaîne. De nouveaux objets String peuvent être créés avec un encodage défini. Cela est important lorsque vous écrivez le contenu du flux sur un autre flux (le flux de sortie de l'objet HttpServletResponse par exemple). Si le contenu du flux d'entrée est traité comme une séquence d'octets, et non comme des caractères ou des chaînes, aucune opération de décodage ne sera entreprise par la JVM. Cela impliquerait que les octets écrits dans le flux de sortie ne doivent pas être modifiés si des caractères intermédiaires ou des objets String ne sont pas créés. Sinon, il est tout à fait possible que le contenu du flux de sortie soit malformé et analysé de manière incorrecte par un décodeur correspondant. En termes simples,

    • Si vous écrivez des objets String ou des caractères dans le flux de sortie de la servlet, vous devez spécifier le codage que le navigateur doit utiliser pour décoder la réponse. Des codeurs appropriés peuvent être utilisés pour coder la séquence de caractères spécifiée dans la réponse souhaitée.
    • Si vous écrivez une séquence d'octets qui seront interprétés comme des caractères, alors le codage à spécifier dans l'en-tête HTTP doit être connu avant
    • si vous écrivez une séquence d'octets qui sera analysée comme un séquence d'octets (pour les images et autres données binaires), alors le concept d'encodage est immatériel.
  3. Le jeu de caractères de la base de données de l'instance Oracle. Comme indiqué précédemment, les données seront stockées dans la base de données Oracle, dans le jeu de caractères défini (pour les types de données CHAR). Le pilote Oracle JDBC prend en charge la conversion des données entre UTF-16 et AL32UTF8 (le jeu de caractères de base de données dans ce cas) pour les types de données CHAR et NCHAR. Lorsque vous appelez resultSet.getString(), une chaîne avec des caractères UTF-16 est renvoyée par le pilote JDBC. L'inverse est vrai, lorsque vous envoyez des données à la base de données aussi. Si un autre jeu de caractères de base de données est utilisé, un niveau de conversion supplémentaire (de l'UTF-16 à l'UTF-8 au jeu de caractères de la base de données) est exécuté de manière transparente par le pilote JDBC.