最近、たまに仕事に文字化けの現象が発生しましたので、javaの文字化けを整理してみます。
コンパイル不備の文字化け
例1:
単純なjavaサンプルですが、保存時の文字コードの設定を出力結果への影響を試します。
public class helloTokyo{
public static void main(String[] args){
System.out.println("hello tokyo");
System.out.println("hello東京");
}
}
まず、MS932で保存してコンパイルしてテストします。
文字化けなし。
次は、UTF-8で保存してコンパイルしてテストします。
見事に文字化けしています!
javacのコンパイルする際、デフォルト文字コードはOSにより変わります。日本語windowsの場合MS932です。ソースはjavacのデフォルト文字コードと一致する場合、出力は正しいです。
ただし、UTF-8でプログラムするなということではないです。以下のようにjavacのencodingパラメータを指定すれば、文字化けがなくなります!
例2:
次はjspサンプルで試験をやります。1行目のpageEncodingはコンパイル時jspファイルをどう読み込むかかの設定と理解すればよいです。contentTypeはサーバからブラウザーへ送信時の文字コードです。
<%@ page language="java" contentType="text/html; charset=MS932"
pageEncoding="MS932"%>
<!DOCTYPE HTML>
<HTML>
<BODY>
hello Tokyo<br>
hello 東京<br>
</BODY>
</HTML>
MS932のままで保存して実行します。文字化けなし。
次はUTF-8で保存して実行します。文字化け発見!
ソースの1行目を以下のように、pageEncodingをUTF-8に修正したら、文字化けが解消です。
<%@ page language="java" contentType="text/html; charset=MS932"
pageEncoding="UTF-8"%>
POST送信の文字化け
WEB送信はよくPOST方法でやります。送信内容をサーバ側から受け取るとき文字化けだったら困ります。
例3:
前述の例を改修してPOST送信と送信内容表示機能を付けます。
<%@ page language="java" contentType="text/html; charset=MS932"
pageEncoding="UTF-8"%>
<!DOCTYPE HTML>
<HTML>
<BODY>
hello Tokyo<br>
hello <%=request.getParameter("txt")%><br>
<form method="post">
<input name="txt" value="東京">
<input type=submit value="送信">
</form>
</BODY>
</HTML>
送信ボタンを押します。文字化け発見!
開発者ツールで送信内容を取得してオンラインDecodeしてみましょう。
MS932(ShiftJISの拡張)の文字はURLエンコードディングされているとわかりました。
そしてrequestの文字コードをMS932で指定すれば問題解決です。
<%@ page language="java" contentType="text/html; charset=MS932"
pageEncoding="UTF-8"%>
<!DOCTYPE HTML>
<HTML>
<BODY>
<%
request.setCharacterEncoding("MS932");
%>
hello Tokyo<br>
hello <%=request.getParameter("txt")%><br>
<form method="post">
<input name="txt" value="東京">
<input type=submit value="送信">
</form>
</BODY>
</HTML>
自分から自分へPOST送信するときjspのcontentTypeとrequestの文字コード指定を統一すれば問題なしと結論しやすいですね。正しいかどうか次の段落をみてください。
例4:
もしPOST送信先は別システムのもので向こうのrequest文字コードを編集できない場合どうすればいいですか。この場合、自分のformの文字コードaccept-charsetを指定しましょう。前述の例と区別するため、今回は、formとrequestの文字コードを全部UTF-8にします。
<%@ page language="java" contentType="text/html; charset=MS932"
pageEncoding="UTF-8"%>
<!DOCTYPE HTML>
<HTML>
<BODY>
<%
request.setCharacterEncoding("UTF-8");
%>
hello Tokyo<br>
hello <%=request.getParameter("txt")%><br>
<form method="post" accept-charset="UTF-8">
<input name="txt" value="東京">
<input type=submit value="送信">
</form>
</BODY>
</HTML>
結論:POSTの場合、送信文字コード指定とrequest setCharacterEncodingこの2箇所が同じであれば文字化けなしです。別々だったら文字化けです。
formのaccept-charsetがあれば、それは送信の文字コード指定になります。formのaccept-charsetがなければ、jsp画面ロード時のcontentTypeの文字コードはデフォルトの送信文字コードになります。
GET送信の文字化け
GETは送信内容をURL経由でサーバに渡します。基本的に英数字のコードの送信を推奨されますが、たまに名称とかメッセージとかを送信してみたら、大抵ひどい目になりますね。
例5:
以下のようになもにしないままで、get方法の送信内容を取得してみます。
<%@ page language="java" contentType="text/html; charset=MS932"
pageEncoding="UTF-8"%>
<!DOCTYPE HTML>
<HTML>
<BODY>
<%
String txt=request.getParameter("txt");
%>
hello Tokyo<br>
hello <%=txt%><br>
<form method="get">
<input name="txt" value="東京">
<input type=submit value="送信">
</form>
</BODY>
</HTML>
文字化け発見!
POSTと違って送信後のURLは長くなります。
http://localhost:8080/helloworld/helloTokyo.jsp?txt=%93%8C%8B%9E
また開発者ツールで閲覧する場合、MS932のエンコードとわかります。つまりcontentTypeと同じMS932です。
GET方法は、setCharacterEncodingが効かないです。話によるとtomcatの設定を変更すればsetCharacterEncodingを有効にさせることですが、好みではありません。参考までやり方を貼り付けます。
<Connector port="8080" maxHttpHeaderSize="8192"
maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
enableLookups="false" redirectPort="8443" acceptCount="100"
connectionTimeout="20000" disableUploadTimeout="true"
useBodyEncodingForURI="true"/>
プログラムの対応方法は以下です。
<%@ page language="java" contentType="text/html; charset=MS932"
pageEncoding="UTF-8"%>
<!DOCTYPE HTML>
<HTML>
<BODY>
<%
String txt=request.getParameter("txt");
if (txt!=null){
txt=new String(txt.getBytes("ISO-8859-1"),"MS932");
}
%>
hello Tokyo<br>
hello <%=txt%><br>
<form method="get">
<input name="txt" value="東京">
<input type=submit value="送信">
</form>
</BODY>
</HTML>
結論:ISO-8859-1はjavaの内部文字コードです。requestからのGET送信内容をISO-8859-1でバイト配列を作成して、送信時文字コードで文字列を再作成するということです。
tomcatコンソールの文字化け
zip版のtomcatを実行する場合、コンソール画面が文字化けです。
これは、logging.propertiesの設定による現象です。tomcatの各種設定はデフォルトとしてlinux向けです。そして、logging.propertiesに設定される文字コードもlinux向けでUTF-8にされています。windowsのデフォルト文字コードはMS932なので合わないから文字化けです。対応方法は以下のように、コンソールに出力する文字コードをMS932にすることです。
これで文字化け解決。