JSPのインクルードに関連する文字化けを解消Javaの文字化け対策FAQ(4)

JSP/サーブレット・プログラミングで誰もが一度は遭遇するトラブルが文字化けだ。予期せぬ文字化け発生に、デバックに苦労した経験を持つ読者も多いだろう。本連載では、JSP/サーブレットにおける文字列の扱いの基礎を復習した上で、文字化けの解決策を要点よく解説してきた。今回が最終回。(編集部)

» 2005年03月12日 00時00分 公開
[吉川和巳スティルハウス]

本記事は2005年に執筆されたものです。Javaの文字化け全般の最新情報は@IT Java Solution全記事一覧のカテゴリ「トラブル・問題解決/ノウハウ/文字化け」をご参照ください。


質問1:JSPのインクルードで文字化けを防ぐには?

解答:親ページではcontentType属性を、子ページではpageEncoding属性を指定しましょう

 JSPのインクルード機能は文字化けが起こりやすいポイントの1つである。その原因を明らかにする前に、まずは同機能について簡単におさらいしておこう。JSPでは、外部のJSPページやHTMLページをインクルードする手段として、以下の2種類を提供している。

  • includeディレクティブ:<%@ include file="ファイル名" %>
  • includeアクション:<jsp:include page="ファイル名" />

 includeディレクティブの場合、インクルードする側のJSPページ(以下、親ページ)のコンパイル時に、インクルードされる側のJSPページやHTMLページ(以下、子ページ)が親ページの一部として挿入される。いわば「静的なインクルード機能」だ。これに対しincludeアクションの場合、Webブラウザが親ページをリクエストするたびに、子ページのコンテンツがレスポンスに挿入される。すなわち「動的なインクルード機能」である。

 このいずれの手段を用いる場合でも、文字化けを防ぐ基本ルールは「pageディレクティブのcontentType属性とpageEncoding属性を適切に記述する」ことである。本連載の第1回「Webブラウザが文字コードを判定する基準は?」でも説明したとおり、これら2つの属性はそれぞれ以下の役割を担っている。

  • contentType属性:JSPページ出力時の文字コード、およびContent-Typeヘッダに指定する文字コード名を指定する
  • pageEncoding属性:JSPページ読み込み時の文字コードを指定する(省略時はcontentType属性の値が使用される)

 周知のとおり、一般的なJSPページではcontentType属性に正しい文字コード名を記述しておけば文字化けは発生しない。なぜならpageEncoding属性は省略可能であり、その場合はContentType属性で指定した文字コードがJSPページの読み込み時にも使用されるからだ。

 しかしインクルードされるJSPページでは事情が異なる。上述したとおり、contentType属性の本来の目的は「HTTPレスポンスに用いる文字コードの指定」であるため、親ページ側で1回だけセットすればよく、子ページ側でも重複して記述するのは無意味である(二重指定時の振る舞いは実装依存であるが、Tomcatでは単に無視される)。

 とはいえ、子ページからcontentType属性を取り去ってしまうと、今度はサーブレット・コンテナが子ページの文字コードを判別する手立てがなくなり、子ページ部分の文字化けが発生してしまう。そこで子ページには、読み込み時の文字コードを伝える手段としてpageEncoding属性だけを記述しておく。

 インクルード時の文字化けを防ぐためのルールをまとめると、以下のようになる。

  • 親ページ:contentType属性で文字コードを指定する
  • 子ページ:pageEncoding属性で文字コードを指定する

 例えば、それぞれ以下のような内容でpageディレクティブを記述すればよい。

親ページ:parent.jsp

<%@ page language="java" contentType="text/html; charset=Windows-31J" %>
<html>
  <head><title>インクルードのテスト</title></head>
    <body>
      これ読めますか:<%@ include file="child.jsp" %><BR>
      これ読めますか:<jsp:include page="child.jsp" /><BR>
    </body>
</html>

子ページ:child.jsp

<%@ page pageEncoding="Windows-31J" %>
こんにちは

 図1は、上記コードをTomcat 5.0.28で表示した例である(Tomcat 4.1.31でも動作確認済み)。

図1 インクルードの表示例 図1 インクルードの表示例

質問2:includeディレクティブを使うとエラーが発生します

解答:属性指定の重複を避けるか、includeアクションを使いましょう

 Tomcat 4では、includeディレクティブに限って、「pageディレクティブの各属性を1回しかセットできない」という制限がある。例えばcontentType属性やpageEncoding属性を親ページと子ページの両方に指定し、includeディレクティブで子ページを挿入すると、図2のようなエラーが発生する。

図2 contentType属性の二重指定時のエラー(Tomcat 4.1.31) 図2 contentType属性の二重指定時のエラー(Tomcat 4.1.31)

 このエラーを回避する方法はいくつかある。

  • Tomcat 5にアップグレードする
  • includeアクションを代わりに使う
  • 親ページではcontentType属性だけ、子ページではpageEncoding属性だけを使う
  • 子ページから文字コード指定を外す

 例えば、同じTomcat 4でもincludeアクションを使ったり、includeディレクティブのままでもTomcat 5にアップグレードしたりすることで、この問題を解消できる。もしくは上述したコード例のように、親ページと子ページでそれぞれ異なる属性を使う方法もある。

 また最後の「子ページから文字コード指定を外す方法」について補足しておこう。Tomcat 4のincludeディレクティブには「デフォルト・エンコーティングで子ページを読み込む」という固有の振る舞いがある。よって、子ページから文字コード指定をすべて削除し、デフォルト・エンコーティングで読み込ませれば上記エラーを回避できる。ただし、この方法はincludeアクションやTomcat 5では逆に文字化けを引き起こすので注意が必要だ。

質問3:HTMLページをインクルードすると文字化けします

解答:HTMLページをデフォルト・エンコーティングで作成するか、JSP化しましょう

 インクルードする子ページがJSPではなくHTMLページであると、その文字コードをサーブレット・コンテナに伝える手段がなくなる。そこでTomcat 4およびTomcat 5では、非JSPの子ページをデフォルト・エンコーティングで読み込む仕様になっている。HTMLページをJVMのデフォルト・エンコーティングで作成しておけば、文字化けは起きないはずだ。

 もっとも、前回も説明したとおり、デフォルト・エンコーティングへの依存はバグのもとである。例えばWindows環境では問題なく動作していたインクルードが、Linuxサーバ上にデプロイした途端に文字化けする、といったトラブルが起きやすくなる。子ページのデフォルト・エンコーティング依存を避けたいときは、子ページもJSPページで統一し、pageEncoding属性で文字コードを明示すればよい。

 またTomcat 5では、includeディレクティブに限って「非JSPの子ページを常にISO-8859-1として読み込む」という制限がある。このケースでは子ページをデフォルト・エンコーティングで作成したとしても文字化けを防げない。よって代わりにincludeアクションを用いるか、子ページをJSP化するなどの対策が必要となる。

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。