ログインしてさらにmixiを楽しもう

コメントを投稿して情報交換!
更新通知を受け取って、最新情報をゲット!

Javaの課題丸投げコミュの文字コードの問題なんですが

  • mixiチェック
  • このエントリーをはてなブックマークに追加
はじめまして、JSP+JAVA+Tomcatで開発中の者です。

困ったことはWEBフォームから「〜」等の特定文字がDBに登録出来ない事です。
そこで文字コードの問題を解決したいのですが。

問題点)
 JSPファイル中の
 <% page contentType="text/html; charset=ISO-2022-JP" %>
 これを
 <% page contentType="text/html; charset=EUC-JP" %>
 に変更してみようかと思うのですが、この結果

 org.apache.jasper.JasperException: JSPのクラスをコンパイルできません

 という事になってしまいます。

EUCにさえしてしまえば、サーブレット側のgetParameterで取得した際に「〜」が文字化けせずに受け取れるかなと思っているのですが肝心のJSP側がこの状態で困っています。

コメント(43)

System.outではなく、res.getWriter()の方に出力してみていただけますか?
System.outではシステムのデフォルトエンコーディングやターミナルのエンコーディングの問題の可能性もあるので、判断が付きがたいです。
ご指摘の通りやってみましたが取得できてました。

res.setContentType("text/html; charset=Windows-31J");
req.setCharacterEncoding("Windows-31J");
String strData = req.getParameter("name").toString();
java.io.PrintWriter out = response.getWriter();
out.println("strData=" + strData);

結果
strData=〜

ところが取得出来た筈の〜をStringに入れてSQLを生成実行すると文字化けてしまいます。
SQL文が文字化けたそのままに、ポストグレスにも保存される模様です。

SQL文
 '$B!A(B'

DB
 $B!A(B

取得は出来ているのだから、あとはこれをポストグレスが使えるEUC−JPに変更してあげれば良いのでしょうか?
となると

String(request.getParameter("name").getBytes("Windows-31J"), "EUC-JP")

みたいな操作が必要なんでしょうか?
ひょっとするとPostgreSQLのJDBCドライバがかなり古くないでしょうか?新しいドライバならデータベースのエンコーディングがEUC-JPでも普通に格納できます。
いまJDBCドライバのバージョンの調べ方を探していたのですが、その課程でちょっと気になる事が。

--------------------------------原文ママ----------------
Connection conn = DriverManager.getConnection(
"jdbc:postgresql://localhost/testdb?charSet=UTF-8", "postgres", "");
Statement stmt = conn.createStatement();
stmt.executeUpdate("set client_encoding to 'UTF-8'");

PostgreSQLでは、WindowsでのUDF(機種依存文字とか呼ばれるNEC特殊文字とかIBM拡張文字を含む)もEUC-JPや UNICODEにマッピングしてくれるが、Javaではそれをやってくれないので、データベースエンコーディングにEUC-JPを使いたい場合はこのような設定をすることでいくつかの問題を回避できる。

データベースエンコーディングがUNICODEであればこんなことをする必要は無い。
--------------------------------ここまで----------------

とあるのですが、他の人が作成したDBアクセスクラスで上記の

Connection conn = DriverManager.getConnection(
"jdbc:postgresql://localhost/testdb?charSet=UTF-8", "postgres", "");

これが未定義なのです。

lookup("java:/comp/env/jdbc/PostgreSQL")

これしか書いてない。
これが原因なのでは?とも思いましたけどどうでしょう?

lookup("java:/comp/env/jdbc/PostgreSQL://localhost/testdb?charSet=UTF-8")

ただこのtestdbの所の記述が環境によって変わる?DB名?という謎が残ってますが。
やっとらしきファイル見つけました

postgresql-8.1-404.jdbc2.jar
postgresql-8.1-404.jdbc2ee.jar
postgresql-8.1-404.jdbc3.jar

この辺でしょうか。
8.1対応の物なのでそこまで古くないのかなとも思うのですが、どうでしょうか?
あとJAVAソース上のSQLに直接〜を埋め込んで実行したのですが、〜は正常にDBに保存されます。
これだとJDBCとConnection時点での問題じゃなさそうですね。
もうちょっと考えてみます。

やっぱり受け渡し時に化けてるのが問題かなぁ?
8.1は私は使ったことがないですね...
文字列を渡すときに、PreparedStatementでパラメータ付きクエリを使っているでしょうか?それとも、文字列を直接結合してますか?
Stringをただ結合しているだけです。
それが問題でしょうか?
まずはそこから追いかけてみます。
文字コード以前に、Stringを結合してSQLを作るのはあまりお勧めできません。ウェブアプリケーションではセキュリティホールになりますからね...

ただ、文字列を結合しているだけなら、SQL上に直接文字を書くのと変わらないはずです。その部分のソースも見せてもらえますか?
文字化けが発生している箇所を特定しないと、解決は難しいと思うので、まずどこで化けているのかを特定しましょう。

以下が参考になると思います。
http://www.ingrid.org/java/jserv/i18n/corruptedchar.html
>鳥取ループさん
SQL編集の所をPreparedStatementで書き換えてみましたけどダメでした。
うーん、やっぱりFORMから取得してる段階で文字化けしてるんじゃないでしょうか?

sql = "";
sql += "INSERT INTO table ";
sql += "(a,b,c) ";
sql += " VALUES (";
sql += "'" + strA + "', ";
sql += "'" + strB + "', ";
sql += "'" + strC + "', ";
sql += ") ";
dao.execute(con,sql);

以前はこの状態で実行してました。


>なかのさん
そうですねえ、そのページもう一回見直してみようかなあ。
あと一点不可解な事が起きてるんですが、JSPファイルを実行する際に

エラー発生
<%@ page contentType="text/html; charset=Windows-31J;"%>

エラー無し
<%@ page contentType="text/html; charset=Windows-31J;" pageEncoding="ISO-2022-JP"%>
ないし
<%@ page contentType="text/html; charset=ISO-2022-JP"%>

何故かページのエンコードがISO-2022-JPじゃないとエラーが出るんですよね。
Windows上とはいえちょっと変じゃないかと思うんですが、何分これ系の開発は今年始めたばかりで詳しくないので?なのです。
とりあえず今日はこれくらいで、また明日再チャレンジします。

なかのさん、そして長い間おつきあい下さった鳥取ループさんどうもありがとうございます。
もなじらさんの問題が解決するかどうかはわかりませんが、
ここの説明は詳しかったです。

http://www.atmarkit.co.jp/fjava/rensai3/mojibake01/mojibake01.html
http://www.atmarkit.co.jp/fjava/rensai3/mojibake02/mojibake02.html
あれ?そもそも「〜」って表記出来ました?

これって、バックスラッシュと同じで、出来ないんじゃなかったかなf^_^;

チルド問題で調べていただければ「〜」は出くると思います。
>17
例えばそのstrAをres.getWriter()へ送り返して化けるならフォームからの取得時に化けているということです。

>18
それはJSPファイルがISO-2022-JPなので、
<%@ page contentType="text/html; charset=Windows-31J;"%>
としてしまうとISO-2022-JPをシフトJISで解釈してしまってコンパイルエラーになっているのだと思います。

>R_Kloverさん
charset=Windows-31Jという設定なら「〜」は化けないですよ。
ひょっとするとですが、送信元のフォームのエンコーディングがISO-2022-JPになっていませんか?フォームがあるHTMLページのエンコーディングもシフトJISにすればなおりそうな予感がします。
>鳥取ループさん
res.getWriter()で送り返すと「〜」で表示されてましたから、少なくともブラウザの世界では正常なんだと思います、でもサーブレット上で文字が、それも内部的に「のみ」化ける(文字コードが限定される?)なんて事あるんでしょうかね???

<%@ page contentType="text/html; charset=Windows-31J;"%>
なるほどファイルそのものを同じ文字コードで保存しなきゃ意味無いんですね、これはうかつでした。

<%@ page contentType="text/html; charset=Windows-31J;" pageEncoding="ISO-2022-JP"%>
ページエンコーディングのみで、キャラクターセットはWindows-31Jなんです。



>時雨さん
それが何か調べてみます。
ヒントどうもありがとう。
>もなじらさん
状況からするとこれでほぼ間違いないと思うのは、
ブラウザでパラメータを送るページ(HTML)のエンコーディングが
ISO-2022-JPになっていませんでしょうか。
ブラウザでフォームを表示したときにエンコーディングがどうなっているか
ブラウザのメニューで調べてみてください。
ブラウザは、フォームが含まれるHTMLのエンコーディングでパラメータを送ります。
ISO-2022-JPで送られたパラメータをシフトJISで解釈してDBに格納しようとすると文字化けするが、
シフトJISで解釈してブラウザに送り返しても、ブラウザはISO-2022-JPと認識してくれている(UTF-8やEUCではこうはいきませんが、ISO-2022-JPでは符号化の性質上あり得ます)
...ということが起こっているとすればこの現象の説明がつきます。
>鳥取ループさん

>ブラウザでパラメータを送るページ(HTML)のエンコーディングが
>ISO-2022-JPになっていませんでしょうか。

それはpageEncodingの事じゃなくてですか?
pageEncodingならISO-2022-JPですが。

>ブラウザのメニューで調べてみてください。
エンコードは自動選択でシフトJISでした。
という事はビンゴ?
つまりres.getWriter()で書き戻すと、もう一度元に戻してくれるから正常に見えると。



対策としては?
・ページエンコーディング(並びにJSPファイルの文字コードをWindows-31Jにする)

困ったな、JSPファイル作成するにもテラパッドが対応しているのが
shift-jis
jis ←現在はこれです
euc
unicode
utf-8
です。
pageEncodingではなくて、contentTypeの方です。
フォームもJSPなのか、制的なHTMLなのかは分かりませんが。
JSPはISO-2022-JPでも構いません。

おそらくですが...
req.setCharacterEncoding("ISO-2022-JP");
とすれば直りませんか?
うーん、JSPファイルを
・JIS
・<%@ page contentType="text/html; charset=ISO-2022-JP;" pageEncoding="ISO-2022-JP"%>

JAVA
・response.setContentType("text/html; charset=ISO-2022-JP");
・request.setCharacterEncoding("ISO-2022-JP");

これでやってみましたけど

「日本語〜」 → 「$BF|K\8l!A!A(B」

でした
ちなみに、
「日本語〜」 → 「$BF|K\8l!A!A(B」
となったときに「$BF|K\8l!A!A(B」 は
どうやって表示していますか?
DBの登録内容をコピペで出しています。
次のどこで化けてますか?
1.ブラウザ→Java
2.Java→DB
3.DB→Java
4.Java→ブラウザ

化けてる文字は?
1.全ての文字
2.全ての日本語
2.「〜」
症状を見る限り、ブラウザ→Javaの時点で化けていると思います。
ISO-2022-JPでブラウザから送られているパラメータをシフトJISとして解釈してしまっているようです。
フォームを表示しているのはJSP、パラメータを受け取っているのはサーブレットという状況ですよね?
サーブレットのソースをすべてコピペしていただけますか?
条件によるんですが

処理A)
<%@ page contentType="text/html; charset=Windows-31J;" pageEncoding="ISO-2022-JP"%>

response.setContentType("text/html; charset=Windows-31J");
request.setCharacterEncoding("Windows-31J");

この条件で行った際に以下の場所で文字化けします。

1.System.out.println
2.DB(ポストグレス)上

1と2が同じ結果になるので、おそらく

>次のどこで化けてますか?
>1.ブラウザ→Java
で
>化けてる文字は?
>2.「〜」

という結論になるかと思っています。

元データ:日本語〜

1.DB上
 $BF|K\8l!A(B

2.System.out.println
$BF|K\8l!A(B


ここで以下の処理を加えた場合、以下のようになります

処理B)
strData3 = new String(request.getParameter(strName).getBytes("Windows-31J"), "iso-2022-jp");

1.System.out.println
日本語?





ですので

処理A)
次のどこで化けてますか?
1.ブラウザ→Java

化けてる文字は?
2.全ての日本語


処理A+処理B)
次のどこで化けてますか?
1.ブラウザ→Java

化けてる文字は?
3.「〜」

になるかと思います。
>鳥取ループさん

うーん、全てというのは先方が嫌がると思うんですよ。

なので改変して一部分だけしかお出し出来ないという感じなんです。

public void service(HttpServletRequest request, HttpServletResponse response)での処理

HttpSession hs = request.getSession();
response.setContentType("text/html; charset=Windows-31J");
request.setCharacterEncoding("Windows-31J");

String ss = this.getData(request);



public String getData(HttpServletRequest request)での処理

String ss = request.getParameter("name").toString();
//String ss = new String(request.getParameter("name").getBytes("Windows-31J"), "iso-2022-jp");
return ss;
Tomcat5.0.28ではGETにより受信したパラメータに対して、setCharacterEncodingメソッドの文字コードを「適用しない」のですが、これは当てはまりませんか?

http://www.atmarkit.co.jp/fjava/rensai3/mojibake03/mojibake03.html
>なかのさん
そういった問題がありましたか...

ということは、ISO-2022-JPではなくて、UTF-8を使うようにしないといけないのかも知れません。

「〜」が化ける問題ですが、
String ss = new String(request.getParameter("name").getBytes("Windows-31J"), "iso-2022-jp");
の部分を
String ss = new String(request.getParameter("name").getBytes("Shift_JIS"), "iso-2022-jp");
とすれば、おそらく直ると思います。
ただ、Javaでiso-2022-jpを使うと、いずれにしてもNEC文字が化けるので、フォームのエンコーディングにはWindows-31JやUTF-8を使ったほうがいいです。JDK1.5ならx-eucJP-Openという手もありますが。
解決しました!


問題点
1.JSPへのエンコード指定
<%@ page contentType="text/html; charset=Windows-31J;" pageEncoding="ISO-2022-JP"%>
ここでWindows−31Jを指定する事

2.JSPのMETA指定をしない
<!-- meta http-equiv="Content-Type" content="text/html; charset=iso-2022-jp" -->
※ここをコメント化したら直りました
META指定すると文字化けの原因となるからしない事。

META要素より
http://www.ingrid.org/java/jserv/i18n/corruptedchar.html

3.サーブレットでエンコード指定する
setContentTypeとsetCharacterEncodingでWindows−31Jを指定する
response.setContentType("text/html; charset=Windows-31J");
request.setCharacterEncoding("Windows-31J");



以上のことを実施してようやく保存出来るようになりました。
結局いくらJSPやサーブレットで文字コード指定しても、META指定が勝ってるのか、こっちが優先されてて文字化け起こしてたんですね。
なんてこった・・・。
他の人が作成した資源なんで、どこをどうしたら良いのか五里霧中でしたがこんなトラップが仕掛かっていたとは・・・。

ここまで二日間にわたって色々ご指導下さった皆様に感謝申し上げます。

鳥取ループさん
なかのさん
しまあじさん
R_Kloverさん
時雨さん
本当にありがとうございました。

特に鳥取ループさんには大変お世話になりました。
もう何か送らせて下さい千葉名産とか(笑)

最後になりますが、METAタグをこのJSPファイルに書いた人に今度あったら、たっぷり文句言ってきます(笑)

本当にありがとうございました。
全く環境は異なりますが、情報までに記載します

一度、〜で文字化けが起こった環境が
DBサーバがoracleの場合で、サーバの言語設定がSJIS_TILDE(正式名称ではありません Windowsの場合、レジストリにあったと思います)
クライアントが、SJISの時に〜は文字化けしてました
(登録時の状態で)

参考までです

追伸;解決してなによりですw
>時雨さん
ありがとうございますw
すごい時間に書き込みしてますねw

ログインすると、残り7件のコメントが見れるよ

mixiユーザー
ログインしてコメントしよう!

Javaの課題丸投げ 更新情報

Javaの課題丸投げのメンバーはこんなコミュニティにも参加しています

星印の数は、共通して参加しているメンバーが多いほど増えます。

人気コミュニティランキング