05.設計2: フレームワークの組み合わせと
エラートラップ
概要
どんなフレームワークを使用するか?
どこでどのようにエラーのトラップをして、処理をするか?を考えてみましょう。
ここでは、本サンプルについての設計を見てみます。
実際にはプログラムを作る前、つまり設計段階でこのような情報をまとめておくべきだと思います。
よくあるアーキテクチャ図のように層(レイヤー)でまとめてみても良いと思います。
組み合わせとエラートラップ
本サンプルでは、フレームワークの組み合わせとエラートラップを以下のようにしてみました。
順番も重要です。
【軽い説明】
まず、文字コード設定フィルタで、リクエストオブジェクトの文字コードをUTF-8に設定しています。
次のログMDC設定では、ログにログインアカウントや、リクエストパスなどを出力できるように
MDCというハッシュに値を設定しています。
Springマルチパートはファイルアップロード時にリクエストパラメタを解釈できるようにしています。
その次のSpringSecurityでは、セキュリティ処理をしています。認証・認可だけでなくCSRF対策も行います。
SpringMVC設定はservletで、SpringMVCの中心人物で、これを設定しないとSpringMVCは使えません。
その後は、自作したControllerが呼ばれることになります。
返りでHTMLが作成されることになります。
図の見方、考え方
さて、図を作ったらそれで終わりではありません。
心に留めておくことは、図を作ることが目的ではなく、「その設計でホントに大丈夫か?」を調査するのが目的だ
ということです。
では早速、作った図を調査していきましょう。
【まず、ログMDC設定フィルタ。】
ここで初めてログインアカウントやリクエストパスをログ出力するための準備ができます。
逆に言うと、その前にログ出力されるとアカウントやパスはNULLが出力されてしまいます。
そこで、その観点で見直すと、このフィルタの前には文字コード設定フィルタしかありません。
文字コード設定が失敗し例外が発生することはめったにありません。
仮にそれでログにアカウントやリクエストパスが出なくてもそれ程、問題ないと思われます。
ログにアカウントやパスを出力するのは、ユーザが閲覧した情報を追跡するという監査ログのためですが
この時点でエラーになった場合はまったく個人情報を閲覧できていないからです。
別の目的の場合は、何か考えないといけないかも知れませんが、目的に応じて大丈夫かを考えればよいと思います。
【次に、マルチパートフィルタ】
ここは、次の記事を読むとここに挿入した意味が分かると思います。
参考: 04.CSRF対策
ただ、MDC設定フィルタの後で良いか?という問題があります。
これですと、もしリクエストパラメタの一部をログに出力したい場合、ファイルアップロード時は
いつでもNULLが出力されてしまいます。
マルチパートのパラメタを解釈する前にMDC設定があるので、パラメタの値が取得ができないからです。
ただ、マルチパートフィルタをMDCの前にすると、マルチパートで例外が発生した時にリクエストパスが
ログ出力されなくなります。
つまりこの2つの順番はトレードオフのような関係になります。
どちらを先にしても問題があり、それ程大きな問題でもないので、
あまりエラーの起こりそうにないものを先に置く方針にしました。
【トランザクションの範囲】
本サンプルでは、ビジネスロジックのメソッド毎にトランザクションの開始と終了する方針にしました。
逆に言うと、基本的にはビジネスロジックのメソッド1つについて、1つのトランザクション単位にする設計です。
そのようにビジネスロジックを作っていく必要があります。
【ちなみにDaoのフレームワークは】
ORマッピングは、図には描いていませんが、MyBatisを使用しました。
このような感じで順番などを決めていきます。
エラートラップについて
上記の図を見ていただくと、例外発生時のエラートラップのタイミングが2つあることが分かります。
エラーをトラップする目的は何でしょうか?
1つはセキュリティのためです。
トラップせずにtomcatに例外処理を任せると、tomcatのバージョンやクラスのパッケージ名など、
攻撃者が攻撃しやすくなる情報がバーゲンセールのように大量放出されます。
もうひとつは、ユーザにエラー時に何をしたらよいかをお知らせしたり、リカバリをするためです。
例外発生時にtomcatが出力する画面ではエラーのトレースなどしか出力されないため、
ユーザはどうしたらよいかわかりません。
そんなときに自作のエラー画面で優しく「こんなミスしたので、こうしてみてください」などのメッセージが
あれば、ユーザも対処方法が分かります。
ですので、エラートラップも重要な設計のひとつです。
エラーの対処方法
Javaでのエラー対処は、エラー内容ごとに別々のExceptionクラスを作成し、例外を発生させ、上部でトラップするのが
おおよその世の中のスタンダードのようです。
トラップした後は、Exceptionクラスごとに別々の対処を実装します。
このとき、存在する例外クラスすべての処理を実装するのは大変なので、親のクラスごとに処理を作ることが多いです。
つまり、例外クラスは親子関係が非常に重要です。
例えばDBのエラーの場合は、DataAccessExceptionの派生クラスかどうかを調べて、派生クラスなら
「DB処理で問題が発生しました」などのメッセージを出力すると思います。
ですが、独自で作成した例外がDB関連なのに、Exceptionをextendsしていた場合、DBエラーとして引っかからなくなります。
親子関係が重要ということがなんとなく理解できましたでしょうか。
Springでのエラートラップ
Springでのエラートラップは、上記の図を見ていただくと分かりますが、Controllerより下のレイヤーのみしかできません。
本サンプルでは、ExceptionHadlerResolverで行う方針にしました。
他にも、@ControllerAdviceを利用する方法や、@ExceptionHandlerを利用する方法、自作の例外に@ResponseStatusを
つける方法などいくつかあるようです。
どれが良いかを検討して使用していくのがよさそうです。
ただ、用意された方法をすべてまばらに使用してしまうと、プログラマーなどが使い分けが分からなくなって、コードの書き方に
統一性がなくなるなどの弊害があります。
ですので、なるべく少ない種類を使用するようにした方がよいのではないかと個人的には思っています。
ちなみに今回、ExceptionHadlerResolverを使用したのは、まとめて1か所で例外をハンドリングできるからです。
他の方法ですと、各Controller作成者がハンドリングしたりします。
通常の開発では、共通部分や基盤の設計やプログラミングを上級者が行い、各Controllerなどの作成をその他の人が
行うかと思います。
Controller作成者に任せる部分が多くなると、人によって例外処理を入れたり、入れなかったりが出る可能性があります。
ですのでまとめてすべて扱えるExceptionHadlerResolverを使用してみました。
Tomcatでのエラートラップ
図を見るとSpringでエラートラップできない部分があることに気づきます。
レンダリング(HTML作成)より上のレイヤーで、例外が発生した場合です。
つまり、JSP内にエラーがあればtomcatのバージョンやトレースがそのまま画面に出力されて、
セキュリティ上、よくありません。
そこで、tomcatのエラー捕捉を使用する設計にしました。
ソースの「web.xml」の下の方を参照してみてください。
Created Date: 2015/03/28