日本語パラメータの対応(getBytes)

広告

前のページでフォームから送られ来るリクエストパラメータの処理方法について確認しました。実はその時のプログラムでは日本語のデータを送付すると文字化けします。

例えばフォームの入力画面で日本語を含む文字を入力して送信します。

日本語の対応

すると次のように日本語を入力した部分は文字化けして表示されます。

日本語の対応

文字化けしてしまう理由は次の通りです。

フォームで入力された値などがサーバに送信される際にURLエンコードが行われバイト列としてサーバに送信されます。サーブレット側では送られてきたバイト列を元の文字列に戻そうとするのですが、その時にデータの文字コードを「ISO-8859-1(Latin1)」だと判断して戻してしまいます。ここで文字化けが発生します。

そこで正しい文字コードを使ってバイト列から文字列を取り出すように変更します。1つ目は事前に文字コードを指定する方法、2つ目は一度誤って処理された文字列をバイト列に戻してから改めて正しい文字コードで文字列に戻す方法です。

1つ目の方法は次のページで確認しますので、ここでは2つ目の方法を試してみます。

文字列をバイト列に戻す

「getParameter」メソッドなどで取得した文字列の値は、先ほど書いたとおりクライアントから送られてきたバイト列を文字コード「ISO-8859-1」で文字列に変換したものです。そこで文字列をまず元のバイト列に戻します。それには「String」クラスで用意されている「getBytes」メソッドを使います。

指定された文字セットを使用してこの String をバイトシーケンスに符号化し、
結果を新規バイト配列に格納します。

指定された文字セットでこの文字列を符号化できない場合、このメソッドの動作
は指定されません。符号化処理をより強力に制御する必要がある場合、
CharsetEncoder クラスを使用する必要があります。

パラメータ:
  charsetName - サポートする charset の名前 
戻り値:
  結果のバイト配列 
例外: 
  UnsupportedEncodingException - 指定された文字セットがサポートされて
    いない場合

文字コード「ISO_8859_1」を使って文字列にしたものを元に戻したいので引数には「ISO_8859_1」を指定して文字列をバイト列に変換します。例えば次のように使います。

public class Sample extends HttpServlet {
  public void doGet(HttpServletRequest request, HttpServletResponse response)
    throws IOException, ServletException{

    String val = request.getParameter("name");

    try {
      byte[] byteData = val.getBytes("ISO_8859_1");
    }catch(UnsupportedEncodingException e){
      System.out.println(e);
    }
  }
}

バイト列から文字列を作成する

次にバイト列を文字列に変換します。今度は正しい文字コードを使って変換します。Stringクラスのコンストラクタの1つに、バイト列と文字コードから文字列を作成するコンストラクタが用意されているためそれを利用します。

指定された文字セットを使用して、指定されたバイト配列を復号化することによっ
て、新しい String を構築します。新しい String の長さは文字セットによって
変化するため、バイト配列長と一致しないことがあります。

指定された文字セットで指定されたバイトが無効な場合、このコンストラクタの
動作は指定されません。復号化処理をより強力に制御する必要がある場合、
CharsetDecoder クラスを使用する必要があります。

パラメータ:
  bytes - 文字列に復号化されるバイト
  charsetName - サポートする charset の名前 
例外: 
  UnsupportedEncodingException - 指定された文字セットがサポートされ
    ていない場合

ここで指定する文字コードは、元々のデータを送ってきたフォームがURLエンコードに使った文字コードです。基本的にブラウザはフォームが含まれるHTMLページの文字コードを使ってエンコードを行います。例えば文字コードとして「Shift_JIS」を指定する場合には次のように記述します。

public class Sample extends HttpServlet {
  public void doGet(HttpServletRequest request, HttpServletResponse response)
    throws IOException, ServletException{

    String val = request.getParameter("name");

    try {
      byte[] byteData = val.getBytes("ISO_8859_1");
      val = new String(byteData, "Shift_JIS");
    }catch(UnsupportedEncodingException e){
      System.out.println(e);
    }
  }
}

文字コードとして「JISAutoDetect」を指定すれば自動的に元の文字コードを判別してくれることになっていますが、あまりこの判別があてになりませんのでクライアント側のHTMLページの文字コードを決めておき、サーブレット側でも特定の文字コードを指定したほうが無難です。

サンプルプログラム

では簡単なサンプルで試して見ます。

フォームが含まれるHTMLページはフルーツの種類を選択した時に送付する値を日本語にしたものを使います。

formsample2.html

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">

<html lang="ja">
<head>
<meta http-equiv="Content-Type" Content="text/html;charset=Shift_JIS">
<title>フォームサンプル</title>
</head>
<body>

<p>アンケート調査です</p>

<form action="/sample/RequestSample2" method="get">

<table>
<tr>
<td>氏名</td>
<td><input type="text" size="20" value="" name="name"></td>
</tr>
<tr>
<td>年齢</td>
<td><input type="text" size="5" value="" name="old"></td>
</tr>
<tr>
<td>好きな果物</td>
<td>
<select name="food" size="3" multiple>
<option value="りんご">りんご</option>
<option value="メロン">メロン</option>
<option value="ぶどう">ぶどう</option>
</select>
</td>
</tr>
</table>
<input type="submit" name="button1" value="送信">
</form>

</body>
</html>

次にフォームから送られてくるリクエストパラメータを処理するサーブレットを作成します。

RequestSample2.java

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

public class RequestSample2 extends HttpServlet {
  public void doGet(HttpServletRequest request, HttpServletResponse response)
    throws IOException, ServletException{

    response.setContentType("text/html;charset=Shift_JIS");
    PrintWriter out = response.getWriter();

    String tmp;

    String name = "";
    tmp = request.getParameter("name");
    if (tmp == null || tmp.length() == 0){
      name = "未設定です";
    }else{
      name = decodeString(tmp);
    }

    int old;
    tmp = request.getParameter("old");
    if (tmp == null || tmp.length() == 0){
      old = -1;
    }else{
      try{
        old = Integer.parseInt(tmp);
      }catch (NumberFormatException e){
        old = -1;
      }
    }

    String tmps[] = request.getParameterValues("food");
    String food = "";
    if (tmps != null){
      for (int i = 0 ; i < tmps.length ; i++){
        food += decodeString(tmps[i]);
        food += " ";
      }
    }else{
      food = "ありません";
    }

    StringBuffer sb = new StringBuffer();

    sb.append("<html>");
    sb.append("<head>");
    sb.append("<title>サンプル</title>");
    sb.append("</head>");
    sb.append("<body>");

    sb.append("<p>お名前は ");
    sb.append(name);
    sb.append(" です</p>");

    sb.append("<p>年齢は ");
    if (old == -1){
      sb.append("未設定です</p>");
    }else{
      sb.append(old);
      sb.append(" です</p>");
    }

    sb.append("<p>好きな果物は ");
    sb.append(food);
    sb.append("です</p>");

    sb.append("</body>");
    sb.append("</html>");

    out.println(new String(sb));

    out.close();
  }

  protected String decodeString(String str){
    try {
      byte[] byteData = str.getBytes("ISO_8859_1");
      str = new String(byteData, "Shift_JIS");
    }catch(UnsupportedEncodingException e){
      return null;
    }

    return str;
  }
}

サンプルプログラムをコンパイルして作成した「RequestSample2.class」ファイルを別途作成した「web.xml」ファイルを次のように配置します。

D:¥ -- servlet-sample
        |
        +-- (formsample2.html)
        |
        +-- WEB-INF
             |
             +-- (web.xml)
             |
             +-- classes
                  |
                  +-- (RequestSample2.class)

web.xmlファイルは次のようになります。

<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app 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"
  version="2.4">

  <servlet>
    <servlet-name>RequestSample2</servlet-name>
    <servlet-class>RequestSample2</servlet-class>
  </servlet>

  <servlet-mapping>
    <servlet-name>RequestSample2</servlet-name>
    <url-pattern>/RequestSample2</url-pattern>
  </servlet-mapping>
</web-app>

コンテキストファイルを作成し「(Tomcatをインストールしたディレクトリ)¥Tomcat 5.5¥conf¥Catalina¥localhost¥」ディレクトリに「sample.xml」ファイルとして保存します。内容は以下の通りです。

<Context path="/sample"
docBase="d:/servlet-sample/sample">
</Context>

準備は以上です。ではTomcatを再起動してから「http://localhost:8080/sample/formsample2.html」へブラウザでアクセスして下さい。

日本語対応

フォームが表示されますので、適当に値を入力してから送信ボタンをクリックして下さい。すると次のようにリクエストパラメータの値を取得して表示します。

日本語対応

今回は日本語を使った場合でも文字化けせずに処理が出来ました。

( Written by Tatsuo Ikura )

関連記事 (一部広告含む)