java基礎：java文字化けと解決のまとめ

最近、たまに仕事に文字化けの現象が発生しましたので、javaの文字化けを整理してみます。

# コンパイル不備の文字化け
## 例１：
単純なjavaサンプルですが、保存時の文字コードの設定を出力結果への影響を試します。
```java
public class helloTokyo{
	public static void main(String[] args){
		System.out.println("hello tokyo");
		System.out.println("hello東京");
	}
}
```
まず、MS932で保存してコンパイルしてテストします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476221/b2f98fc1-ea78-5bcb-dbf8-4d43f347b785.png)
文字化けなし。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476221/dce56cc5-4a33-bb7a-c742-2761e39c7645.png)
次は、UTF-8で保存してコンパイルしてテストします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476221/0e68d5fe-e0fe-e5d5-2830-e728de4fa1ec.png)
見事に文字化けしています！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476221/1e88b104-fa55-d631-80be-a13d41cca328.png)
javacのコンパイルする際、デフォルト文字コードはOSにより変わります。日本語windowsの場合MS932です。ソースはjavacのデフォルト文字コードと一致する場合、出力は正しいです。
ただし、UTF-8でプログラムするなということではないです。以下のようにjavacのencodingパラメータを指定すれば、文字化けがなくなります！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476221/0d1ed28a-1856-1853-e7e9-2d79a21f99ca.png)
## 例２：
次はjspサンプルで試験をやります。１行目のpageEncodingはコンパイル時jspファイルをどう読み込むかかの設定と理解すればよいです。contentTypeはサーバからブラウザーへ送信時の文字コードです。
```jsp
<%@ page language="java" contentType="text/html; charset=MS932"
 pageEncoding="MS932"%>
<!DOCTYPE HTML>
<HTML>
<BODY>
hello Tokyo<br>
hello 東京<br>
</BODY>
</HTML>
```
MS932のままで保存して実行します。文字化けなし。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476221/9db34b31-d924-0ca3-3c95-642ac268d2c2.png)
次はUTF-8で保存して実行します。文字化け発見！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476221/6fcafc00-28a6-7c50-8f5d-c619e5b23816.png)

ソースの１行目を以下のように、pageEncodingをUTF-8に修正したら、文字化けが解消です。
```jsp
<%@ page language="java" contentType="text/html; charset=MS932"
 pageEncoding="UTF-8"%>
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476221/70454a9f-0ad2-3a84-6d46-714ce4bc5f56.png)

# POST送信の文字化け
WEB送信はよくPOST方法でやります。送信内容をサーバ側から受け取るとき文字化けだったら困ります。
## 例３：
前述の例を改修してPOST送信と送信内容表示機能を付けます。
```jsp
<%@ 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>
```
送信ボタンを押します。文字化け発見！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476221/6d53fe36-089c-f67b-e672-643b008b5926.png)
開発者ツールで送信内容を取得してオンラインDecodeしてみましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476221/d51fcabf-6e02-bc9f-9e43-1ab92a6d5349.png)
MS932（ShiftJISの拡張）の文字はURLエンコードディングされているとわかりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476221/c6cee668-481c-930e-81f5-22f664943d72.png)
そしてrequestの文字コードをMS932で指定すれば問題解決です。
```jsp
<%@ 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>
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476221/60e7335e-805a-3141-3497-ff87c935cb60.png)

自分から自分へPOST送信するときjspのcontentTypeとrequestの文字コード指定を統一すれば問題なしと結論しやすいですね。正しいかどうか次の段落をみてください。

## 例４：
もしPOST送信先は別システムのもので向こうのrequest文字コードを編集できない場合どうすればいいですか。この場合、自分のformの文字コードaccept-charsetを指定しましょう。前述の例と区別するため、今回は、formとrequestの文字コードを全部UTF-8にします。
```jsp
<%@ 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>
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476221/c5d5a10f-0dde-58f8-0802-84cda7972546.png)
結論：<b>POSTの場合、<font color=red>送信文字コード指定</font>と<font color=red>request setCharacterEncoding</font>この２箇所が同じであれば文字化けなしです。別々だったら文字化けです。</b>
formのaccept-charsetがあれば、それは送信の文字コード指定になります。formのaccept-charsetがなければ、jsp画面ロード時のcontentTypeの文字コードはデフォルトの送信文字コードになります。

# GET送信の文字化け
GETは送信内容をURL経由でサーバに渡します。基本的に英数字のコードの送信を推奨されますが、たまに名称とかメッセージとかを送信してみたら、大抵ひどい目になりますね。
## 例５：
以下のようになもにしないままで、get方法の送信内容を取得してみます。
```jsp
<%@ 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>
```
文字化け発見！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476221/ea3f5840-75ce-6a0a-8d5d-25c9df2f2899.png)
POSTと違って送信後のURLは長くなります。
```
http://localhost:8080/helloworld/helloTokyo.jsp?txt=%93%8C%8B%9E
```
また開発者ツールで閲覧する場合、MS932のエンコードとわかります。つまりcontentTypeと同じMS932です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476221/af47a199-146e-de2e-d2c2-4ca33483f0d8.png)

GET方法は、setCharacterEncodingが効かないです。話によるとtomcatの設定を変更すればsetCharacterEncodingを有効にさせることですが、好みではありません。参考までやり方を貼り付けます。
```xml
<Connector port="8080" maxHttpHeaderSize="8192"
           maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
           enableLookups="false" redirectPort="8443" acceptCount="100"
           connectionTimeout="20000" disableUploadTimeout="true" 
 useBodyEncodingForURI="true"/>
```
プログラムの対応方法は以下です。
```jsp
<%@ 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");//Tomcat7
		txt=new String(txt.getBytes("UTF-8"),"MS932");//Tomcat8～  
	}
%>
hello Tokyo<br>
hello <%=txt%><br>
<form method="get">
<input name="txt" value="東京">
<input type=submit value="送信">
</form>
</BODY>
</HTML>
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476221/4ad97512-eba4-3101-0e93-63de4d717f9f.png)
結論：<B>ISO-8859-1はjavaの内部文字コードです。tomcat7のrequestからのGET送信内容を<font color=red>ISO-8859-1</font>でバイト配列を作成して、<font color=red>送信時文字コード</font>で文字列を再作成するということです。tomcat8以降このGET送信内容はUTF-8文字コードになっています。</B>

# tomcatコンソールの文字化け
zip版のtomcatを実行する場合、コンソール画面が文字化けです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476221/d3162f32-9df1-c97a-8b49-a93025355f38.png)
これは、logging.propertiesの設定による現象です。tomcatの各種設定はデフォルトとしてlinux向けです。そして、logging.propertiesに設定される文字コードもlinux向けでUTF-8にされています。windowsのデフォルト文字コードはMS932なので合わないから文字化けです。対応方法は以下のように、コンソールに出力する文字コードをMS932にすることです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476221/e790eb2b-27c9-01df-0ada-66c09404be40.png)
これで文字化け解決。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476221/1bedac88-e3f0-bdc5-3dfb-bfe854c5e2c0.png)