サーブレットとブラウザ間の文字の入出力にはdoGetメソッド、doPostメソッドを使いますが、どのようにこれらを使うか、については多くの情報が検索できますし、書物でも解説されています。
しかし、入出力時の文字コードを適切に設定しないと日本語を扱う場合に文字化けが起こり、情報も少ないため、この解消には苦労をします。
そこで、なぜ文字化けが起こるのかを推測を含め整理します。
まず、HTMLの文字コードは以下の順で処理されます。
1. HTTPヘッダのContent‒Typeのcharsetの値
2. HTML内のMETAタグのContent‒Typeのcharsetの値
しかし、サーブレットコンテナは指定がない限りContent‒Typeのcharsetをデフォルトの文字コードに設定するのでサーブレットの中のmetaタグ指定は無視されます。tomcatの場合デフォルトの文字コードはISO-8859-1(アルファベット)なので日本語は文字が化けることになります。
そこで、文字コードをHTTPヘッダのContent‒Typeで指定する必要があります。
日本語の表示の場合は、データがブラウザに返される前にHttpServletResponseインタフェースのsetContentTypeメソッドで日本語の文字コードを設定します。
public class MySecondServlet extends HttpServlet { public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setContentType("text/html; charset=Windows-31J"); (以下省略)
つぎに日本語の入力の場合は、これとは別にHttpServletRequestインタフェースのsetCharacterEncodingメソッドで指定します。
req.setCharacterEncoding("Windows-31J");
これで入力も正しく処理されるはずなのですが、doPostメソッドは良いのですが、doGetメソッドの場合は文字化けが治りません。
調べたところ、「Tomcat5.xよりFORMのGETメソッドでパラメータを送信した場合、setCharacterEncodingメソッドを無視するようになった。」という情報があり、その解消のためには「(tomcatのconfフォルダー内の)server.xmlファイルの
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" useBodyEncodingForURI="true" />
ところが、これだけではdoGetメソッドの文字化けは解消ぜず、文字コードの指定をUTF-8に変更して日本語を正しく入力できるようになりました。
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // req.setCharacterEncoding("Windows-31J"); // resp.setContentType("text/html; charset=Windows-31J"); req.setCharacterEncoding("UTF-8"); resp.setContentType("text/html; charset=UTF-8");
この原因はdoGetメソッドがURLパラメータで情報を受取るため、内部処理が全てUTF-8のサーブレットが情報をWindows-31Jで受取り文字化けを起こしている、のではないかと推測されます。
一方、doPostメソッドの場合には情報はフォームを使って送られるのでメソッドの中でWindows-31JをUTF-8に変換しているため、指定する文字コードがWindows-31Jでないと文字化けを起こす、と推定されます。
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding("Windows-31J"); resp.setContentType("text/html; charset=Windows-31J"); // req.setCharacterEncoding("UTF-8"); // resp.setContentType("text/html; charset=UTF-8");