タイガー!タイガー!じれったいぞー!(SE編)

AS400, Java, JavaEE, JSF等の開発、習慣など。日々の気づきをまとめたブログ(備忘録)

文字化け対策(Java AP Server → AS400)

AS400内のアプリは、5250エミュレータで接続することで操作可能になりますが、AS400の外にApplication Server(Web, Java)を立て、AS400DB2 for i)をDB Serverで運用する場合、JDBCドライバーを使って、Web・DB間のやり取りを行うようになります。

この場合、役割が分離されて管理はしやすくなるのですが、Webアプリ側できちんとバリデーション対応をしていないと、文字化けで悩むことになります。

最近、文字化けではまったケースが2回あったので、備忘録としてまとめておきます。

文字化けとなった文字

DB側で文字化けとなってしまった対象の文字は、次の2つ。

水平TABなんかは、WEB画面へ直接入力することはできないはずなんです。

しかし、操作をした方に聴いてみると、どちらの場合も「お取引先様からいただいたファイル」から情報をカット&ペーストしたという話でした。
その結果、バリデーション・チェックされずに、DBに格納されてしまったというわけです。

AS400側での文字化けの表示

  • AS400のCCSIDは、5026。
  • 文字化けが含まれているレコードをUPDDTAコマンドで直接中身を確認してみました。

水平TAB

「検索されたレコードに正しくないデータが入っている。」とエラーになり、レコードを開くことができませんでした。

f:id:no14141:20190830122428p:plain

ではなぜ、文字化け対象文字が、水平TABであるかがわかったのか? SQLのHEX関数でEBCDIC文字コードを確認できたからです。

SELECT MODEL, HEX(MODEL)   
 FROM LIB_NAME.TABLE_NAME
 WHERE KEY = 'XXXXXXXXXX'    

-- MODEL         HEX ( MODEL )                     
-- 123               F1F2F30540404040404040404040404040404040

せっかくなので、各サイトを頼りに今回の文字コードを調べました。

文字 EBCDIC Unicode UTF-8 MS932
水平TAB 0x05 0x09 0x09 0x09
ラテン文字の中点 0xD64D 0xB7 0xC2 0xB7 0x8145(※注: 全角の中点と同じコード)

ラテン文字の中点

UPDDTAコマンドでレコードは表示されましたが、該当文字の部分が「・」になっていました。 これは、ラテン文字中点としての中点ではなく、5250アプリでも、①などの機種依存文字を入力した場合に「・」と表示されていたので、同様に文字化けとして「・」という文字に置換されていると考えてよさそうです。

ACSの表示設定の中には、文字化けの場合、変換して表示する機能があることを発見したので、こちらの設定が適用されて「・」と表示されているのでしょう。

ちなみに、ACSの文字化け置換の確認・設定は、「編集 > 設定 > 外観 > 表示」の画面内で操作可能でした。

f:id:no14141:20190830122450j:plain

AS400側での文字化けの影響

  • ODBCで接続しているサブシステム側で問題がありました。

SQLツール(ODBCドライバー連携)やPHPアプリでは、文字化け箇所が「?」に置換されて表示されたのですが、VBアプリでは文字化けフィールドをSQLで取得しただけで例外扱いになり、正常の処理ができなくなってしまいました。

ODBCドライバーとVBの相性が悪いのでしょうか?
それとも最新のODBCドライバーでは置換されるのか不明ですが、VBアプリで今回の文字化けの影響があることがわかりました。

解決策

  • やはり、DBにエントリーするWebアプリできちんとバリデーションを行えばよいでしょう。
  • もともと自作したStringUtilsクラス内で、AS400へ書き込み可能な文字列かのメソッドを用意していたので、その中に水平TABとラテン文字の中点を追加しました。
  • 2つの文字だけをバリデーションエラーとする場合のサンプルソースは、下記の通りです。JavaEEであれば、このメソッドとBeanValidationを結びつければ、シンプルな実装が可能になります。
    public static boolean canSetDB400(String target) {

        // Unicodeでの判別
        for (char c : target.toCharArray()) {
            //ラテン文字の中点(0xb7)、水平TAB(0x9)は除外
            String s = Integer.toHexString(c);
            if (s.equals("b7") || s.equals("9")) {
                return false;
            }
        }
        return true;
    }

まとめ

  • 今回は、文字化け調査で、かなりの時間を割いてしまいましたが、文字コードについて勉強になって良かったと思っています。
  • それにしても、AS400に文字化けせずに書き込めるかどうかのユーティリティ・プログラムは、無いものでしょうか。もしかしたら、自分は車輪の開発をしてしまっているのかもしれませんね。