Java HttpServlet 初心忘れるべからず!
前回は、 XA の使い方について執筆しました。今回は、基本に立ち戻って、今更ながら HttpServlet で扱うリクエストパラメータのエンコーディングの話を執筆したいと思います。
GlassFish をこれから使おうと言う人の中にも、 Servlet 初心者と言う方がいらっしゃると思われるので、この辺のことはきちっと理解しておいた方が良いかな? と思い執筆することにいたしました。
(商用のアプリケーションサーバーの中には、このエンコードに関して何も意識せずに、クライアントから送信されたロケールをそのまま受け取るものもあるようなので、結構この辺のことがないがしろにされてしまうケースが多々あるような気がします・・・)
今回も検証環境に以下を使用します。
※検証環境
| ・機種名 | :iMac7,1 |
| ・CPU | :Intel Core 2 Duo 2GHz |
| ・メモリー | :2G Bytes |
| ・OS | :Mac OS X 10.4.11 Tiger |
| ・カーネル | :Darwin 8.11.1 |
| ・Java | :java version “1.5.0_13″ |
| ・GlassFish | :v2-ur2-b04 |
さてそれでは早速実装してみましょう。以下のようなページを表示し、送信ボタンを押すと入力した内容をテキストボックスの横に表示する簡単なサーブレットを作成し、 GlassFish に配備して実行します。

画面が表示されたらテキストボックスに、"あいうえお12345"と入力して送信ボタンをクリックしてみます。すると、以下のように、マルチバイトキャラクタのみ文字化けして表示されます。

これは、開発者であれば、かなり多くの人が経験したのではないかと思います。サーブレットのコード上で、 "response.setContentType("text/html;charset=UTF-8");" と宣言したのに、なんで?と思われるかも知れませんね。この宣言は、 html body 部分に対する宣言で、 http リクエストパラメータはこの対象外となるからです。
そしてこの文字化けの理由ですが、 javax.servlet.http.HttpServletRequest の標準仕様として、リクエストに対して何もエンコード指定しない場合は、デフォルトのエンコードである iso-8859-1 as LATIN 1 として受信してしまうからです。
ではどうやったらこの文字化け問題を解決できるのか? 方法は3通りあります。
1つ目は、リクエストパラメータを iso-8859-1 として byte コードを取得し、サーバー側で処理したいエンコードを設定し直して String オブジェクトを生成する方法で、以下のようなコードとなります。
String input = new String(request.getParameter("input").getBytes("iso-8859-1"), "UTF-8");2つ目は、 http リクエストに対して、サーバー側で処理したいエンコードを指定してからリクエストパラメータを取得すると言う方法です。コードは以下の通りです。
request.setCharacterEncoding("UTF-8");3つ目の方法としては、サーブレットフィルターを透過させてサーブレットにリクエストが渡る前に、サーバーで処理したいエンコードに変換してからサーブレットへリクエストを渡すと言うやり方になります。
サーブレットフィルタークラスのコードは以下の通りです。
public class CharacterSetFilter implements Filter {
protected static final String ENCODING_KEY = "encoding";
protected String encoding = null;
protected FilterConfig filterConfig = null;
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
this.encoding = this.filterConfig.getInitParameter(ENCODING_KEY);
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
if(this.encoding != null) {
request.setCharacterEncoding(this.encoding);
}
chain.doFilter(request, response);
}
public void destroy() {
this.encoding = null;
this.filterConfig = null;
}
}そして、そのアプリケーションで使いたいエンコードと、フィルタークラスをアプリケーションに登録するため、 web.xml に以下を記述します。
※フィルターの定義
<filter>
<description>キャラクタセットフィルター</description>
<filter-name>Character Set Encoding</filter-name>
<filter-class>jp.glassfish.jacksparrow.encoding.filter.CharacterSetFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>Character Set Encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>以上の方法で解決できるようになります。以上3つの方法それぞれの利点と欠点を以下に纏めてみました。
| 実装方法 | 実装漏れ | 再利用 | コード量 |
| iso-8859-1 で getBytes() してコンバート | 有り | 共通の変換クラス化すれば可 | 中 |
| setCharacterEncoding() を利用して文字エンコードを指定 | 有り | 不可 | 少 |
| サーブレットフィルターを利用して文字エンコードを指定 | 無し | 可 | やや多 |
とまぁ簡単に纏めてみましたが、私が良く利用する方法としては、3つ目の方法を必ずと言って良いほど使っています。
理由としては、
1、Struts などのフレームワークを利用した場合、サーブレットの外側かえら文字エンコードの指定をする必要がある。
2、システム要件などにより、途中で文字エンコードを変更する必要が発生した場合、 web.xml の設定を変更するだけで容易に変えられる。
3、なによりも、再利用が簡単で、サーブレットを作成しなければならない局面が発生した場合でも、サーブレット開発者は特に文字エンコードに対する実装を意識しなくて済む。
と言ったところになります。
そして先ほどのフィルターをアプリケーションに追加し実行した結果が以下になります。

さて如何でしたでしょうか? ご理解いただけたら幸いです。因に今回検証に使用したサンプルアプリケーションはこちらから取得できます。ご活用ください。
本投稿もシリーズ化してまいりましたので、次回は、せっかく JavaEE 参照実装しているアプリケーションサーバーを使っているのだからと言うこともあり、エンタープライズアプリケーションへと、歩を進めて行きたいと思います。
と言う訳で次回は、「 GlassFish v2 で WebService 」と題しまして、投稿を執筆して行こうと思います。
Comments
Pingback from jacksparrow » GlassFish v3-Prelude 正式リリース!!!
Date: 2008 年 11 月 20 日, 11:38 PM
[...] さて以前執筆しましたJava HttpServlet 初心忘れるべからず!にて、「 GlassFish v2 で WebService [...]



Write a comment