文字化けとは?
JSPにおけるデフォルトの出力文字コードは、「ISO-8859-1(Latin 1)」という欧米系言語です。そのため、JSPページ内でマルチバイト文字を利用する場合には @pageディレクティヴのcontentType属性で出力文字コードを指定していないと、下図のようにページが文字化けしてしまう可能性があるので、注意してください。
文字化けするコード
<html>
<body>
ハロー ワールド
</body>
</html>
文字化けを起こさないためには、以下のようにcontentType属性で出力文字コードを指定してあげる必要があります。また JSPが記述されている文字コードによっては、pageEncoding属性も併せて記述します。
文字化けしないコード
<%@ page contentType="text/html;charset=Windows-31J" %>
<html>
<body>
ハロー ワールド
</body>
</html>
J2SE 1.4.1以降のバージョンより文字コードの扱いに変更があったため、従来の「Shift_JIS」を指定すると一部の機種依存文字(「〜」など)が文字化けしてしまう可能性がありますので「Windows-31J」を指定するようにします。
文字コード
JSPやServlet開発者の方は一度は文字化けで悩まされたことがあるでしょう。 Windowsで使用している文字コードが Windows-31Jで Unix では EUC、DBでは別のコード体系を使用していて、さらに Javaでは Unicodeが採用されて、、、と色々な文字コードが登場してくるので文字コードの変換タイミングや記述等を曖昧にしてしまうとハマってしまうことになります。
Javaでは文字列を内部的にはUnicodeで保持しています。そのため、Javaでの文字列の入出力の際は必ず Unicodeと他の文字コード間でのコード変換が行われます。ここで対応するコードが存在しない場合、文字化けの症状として良く見られる「?」が出力されてしまうことになります。
Shift_JISと Windows-31J
Windowsでは Shift_JISが文字コードとして使われていると認識されている方は多いかと思いますが、Windowsでは Microsoft社、及び、MS-DOSのOEMベンダがShift_JISを独自に拡張した Windows-31Jという文字コードが使われています。 Shift_JIS と Windows-31J の違いは以下のようなものが挙げられます。
- Windows-31JはNEC特殊文字やIBM特殊文字を含んでいますが、Shift_JISではこれらの文字を含んでいません。
- 一部の文字での Unicodeに変換する際のコードポイントが異なります(〜 ‖ − ¢ £, ¬ など)。
Javaでは Unicodeを採用していますので、特に Shift_JIS との相違点となる、二番目の項目で挙げている文字( 〜, ‖, −, ¢, £, ¬)には悩まされる事が多々ありますので注意する必要があります。
文字コードの変換タイミング
あまり意識することは無いかもしれませんが、JSPファイルを実行する時は暗黙的に文字コード変換が行われています。文字化けが発生したときは、先ずどの段階で文字化けが発生したのか切り分けをします。今回はどのタイミングで文字コードの変換が行われているのか幾つか挙げてみます。
- 1.JSPファイルは実行する際に Javaファイルへ変換されます。先ず JSPファイルを JSPコンパイラが読み込む段階で文字コードが変換されます。
- 2.次にJSPコンパイラ JSPを解析し Javaファイルを生成しますが、この段階でも Javaファイルを出力の時点でコードが変換されます。
- 3.次は Javaコンパイラ(javac)が Javaファイルを読み込んで classファイルを生成する時です。
- 4.最後に生成された classファイル(サーブレット)がリクエストに対する処理を実行して HTTPレスポンスを出力するときにも文字コード変換が行われます。
contentTypeとpageEncoding
先ずJSPページで文字化けが発生してしまっている場合は「pageディレクティブのpageEncoding属性とcontentType属性を適切に記述する」ことでたいがいのケースは解決します。先ずそれには、これらの属性がどのように使用されてどのような意味を持っているのか見ていきましょう。
pageEncoding
pageEncoding属性は JSPファイルがどの文字コードで記述されているかの設定するための pageディレクティブです。 この属性を誤って指定した場合、JSPファイルを JSPコンパイラが読み込んで Servletファイルを Unicodeで出力する際の変換で文字場が発生します。そのため Javaソースへ変換されたファイルの全角文字が文字化けしています。
例えば Windowsのメモ帳で JSPファイルを作成した場合は Windowsの文字セットである「Windows-31J」を指定します。また、Eclipse等を使い、Unicodeで JSPファイルを作成している場合には「UTF-8」と指定します。
Javaソースに変換されたファイルで文字化けが発生している場合は、実際のJSPの文字コードと、この属性の値に間違いが無いか確認しましょう。 pageEncodingは省略した場合、後述する contentTypeの charset属性が使用されます。ちなみに何も指定しなかった場合のデフォルトは「ISO-8859-1」です。
contentType属性
contentType属性は、 JSPページが応答として出力する文字セットとMIMEタイプを指定します。 このディレクティブで指定された MIMEタイプと文字コードは HTTPのContent-Typeヘッダとしてブラウザへ伝えられ、ブラウザはこのヘッダを参照して文字コードを判断します。
JSPのディレクティブで以下上段のように記述すると、Javaファイル変換時には以下下段のような記述となります。
JSP
<@ page contentType="text/html; charset=windows-31j" >
Servlet
response.setContentType("text/html; charset=windows-31j");
charsetで「Shift_JIS」を指定した場合は、Shift_JISに含まれない「〜」等の全角文字は出力の際に文字化けしてしまいます。
それでも文字化け
charsetとpageEncodingを正しく設定しているのにも拘らず文字化けが発生してしまう場合があります。JSPファイルを Windows-31Jで記述して、出力する charsetも Windows-31Jで指定したのですが、ブラウザへ表示する段階で文字化けが発生しています。
Javaファイルに変換されたファイルを見ても正常に変換されており、レスポンスの文字コードもShift_JIS(Windows-31J)です。HTTPヘッダがおかしいのかと思い見てみても正常(以下参照)
GET /wtomcat/jsp/sample.jsp HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; ja; rv:1.8.0.8)
Gecko/20061025 Firefox/1.5.0.8
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,
text/plain;q=0.8,image/png,*/*;q=0.5
Accept-Language: ja,en-us;q=0.7,en;q=0.3
Accept-Encoding: gzip,deflate
Accept-Charset: Shift_JIS,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Cookie: JSESSIONID=8295C08AD8361CCC72E748606F968E98
Cache-Control: max-age=0
HTTP/1.x 200 OK
Server: Apache-Coyote/1.1
Content-Type: text/html;charset=Windows-31J
Content-Length: 149
Date: Thu, 07 Dec 2006 02:30:34 GMT
この現象はFireFoxでは起こらず、IEでエンコードを「自動選択」にしている場合のみ発生するようです。不本意ながら以下のMETAタグで「Shift_JI」Sを指定することによって解消しました。(Windows-31Jを指定してもダメ) IEのバージョンは 6 sp2
Java内部ではではWindows-31Jを、IEの認識ではShift_JISを指定すると上手くいくようです。
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=Shift_JIS">
インクルードファイルでの文字化け
インクルードディレクティブで複数のJSPファイルをインクルードしている場合、Tomcat4.1.xx系では正常に日本語出力されていたのにも係わらず、Tomcat5.x系では文字化けしてしまう場合があります。
[sample.jsp]
<%@ page contentType="text/html;charset=Windows-31J" pageEncoding="Windows-31J"%>
<html>
<head>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=Shift_JIS">
</head>
<body>
<%@ include file="include_page1.jsp"%>
ハロ〜 ワールド<br>
<jsp:include page="include_page2.jsp" flush="true" />
</body>
</html>
[include_page1.jsp]
はろ〜 わーるど<br>
[include_page2.jsp]
HELLO WORLD<br>
Tomcat4.1.31の出力
Tomcat5.5.20の出力
JSP1.2等の仕様では、JSPファイルのエンコーディング はpageディレクティブで指定したpageEncoding属性またはcontentType属性によって決まりますが、これは変換単位で指定するものではなくページ単位(上記で言えばファイル毎)で指定する必要があるため、include_page1.jspと include_page2.jspはデフォルトエンコーディングであるISO-8859-1と解釈されてしまい、Javaソースへの変換で文字化けが発生してしまいます
そう言う意味では「 Tomcat4.1.xx では上手く動いてしまっていた」と言えるかも知れません。
対策
上記で文字化けが発生している原因が、インクルードされたファイルの pageEncodingが指定されていないためデフォルトエンコーディングで解釈されてしまっているためなので、インクルードされるファイルに 「 <%@ page pageEncoding="Windows-31J"%>」を記述すれば解決します。
注意点として、Tomcat4.1.xxではインクルード元ファイルに pageディレクティブが記述されている場合、インクルードされるファイルに pageディレクティブを記述することは出来ません。そのため上記方法で解決はしても Tomcat4.1.xxでは動作しなくなります。
web.xmlを使用した文字化け対策
JSP2.0から新たに JSPコンフィギュレーション(<jsp-config>要素)機能が追加されました。<jsp-config>要素は、デプロイメント・ディスクリプタ(web.xml)に設定を追加することで、アプリケーション配下のJSPペーのエンコーディングやヘッダ、フッタを集約して定義することが出来るようになりました。
設定できる項目
| 要素 |
概要 |
| taglib |
このアプリケーションで使用する全てのJSPに設定するタグライブラリ群を定義します。 |
| taglib-uri |
タグライブラリのURIを記述します。 |
| taglib-location |
このタグライブラリに対応する設定ファイル(通用は拡張子tld)パスを記述します。 |
| jsp-property-group |
このアプリケーションで使用するJSPに設定するプロパティを定義します。 |
| url-pattern |
このプロパティ群を適用するURLパターンを定義します。ワイルドカード(*)が使用できます。(必須) |
| page-encoding |
JSPファイル自体の文字エンコーディングを定義します。 |
| include-prelude |
デフォルトでページの先頭にincludeするファイルのパスを記述します。複数定義可能。 |
| include-coda |
デフォルトでページの最後にincludeするファイルのパスを記述します。複数定義可能。 |
|
[サンプル]
<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/web-app_2_4.xsd"
version="2.4">
<jsp-config>
<jsp-property-group>
<url-pattern>*.jsp</url-pattern>
<page-encoding>windows-31j</page-encoding>
<include-prelude>/jsp/common/page_charset.jsp</include-prelude>
</jsp-property-group>
</jsp-config>
〜 以下省略 〜
</web-app>
上記のようにすることで JSPページ全てのエンコーディングを「 Windows-31J 」として、また全ての JSPページのヘッダとして page_charset.jsp を実行することが出来ます。
|