ベストプラクティス
このセクションではClickアプリケーションのデザインと構築に関するベストプラクティスについてお話します。以下のトピックがカバーされています:
- セキュリティ - J2EEのロールベースのセキュリティ
- ページの自動マッピング - Convention over Configurationの利用
- ナビゲーション - フォワード、リダイレクトにページクラスを使用する
- テンプレーティング - Webアプリケーションの標準化
- メニュー - 画面遷移の集約
- ロギング - 基底クラスでLog4jを使用する
- エラーハンドリング - カスタムエラーページの利用法
- パフォーマンス - ページのパフォーマンスを向上します
セキュリティ
アプリケーションのセキュリティのためにJ2EEサーブレットパスロールベースのセキュリティモデルを使用することを強く推奨します。Clickページは独自のセキュリティモデルを実現するためにonSecurityCheck()メソッドを提供しますが、J2EEのモデルのほうが多くの利点があります。
これらの利点には以下のようなものがあります:
- 業界標準のパターンであるため開発とメンテナンスがより簡単になります。
- 一般的にアプリケーションサーバはLDAPディレクトリ、リレーショナルデータベースを含む多くのセキュリティインフラとの統合手段を提供します。
- サーブレットセキュリティモデルはページをブックマークしているユーザもサポートします。ユーザがあとでこれらのページにアクセスすると、コンテナはリソースへのアクセスを許可する前に自動的に認証処理を行うでしょう。
- このセキュリティモデルを使用することで、ページにセキュリティに関するコードを含める必要がなくなります。これはコードの再利用性の促進につながりますし、少なくともより書きやすいコードになります。
もし、あなたのアプリケーションにきめ細かい、もしくは複雑なセキュリティ要件が求められる場合、JEE宣言型セキュリティモデルとプログラム型セキュリティモデルを必要に応じて組み合わせる必要があります。この場合、宣言型セキュリティを荒い粒度のアクセスコントロールで使用し、プログラム型セキュリティをきめ細かいアクセスコントロールで使用することを推奨します。
宣言型セキュリティ
J2EEサーブレットセキュリティモデルは、ユーザが保護されたリソースにアクセスする前に正しいロールで認証されている必要があります。J2EEの仕様の多くと比較すると、サーブレットセキュリティモデルは驚くほど簡単です。
例えば管理者用のページを保護するためにセキュリティ制約をweb.xmlに追加します。これによってユーザはadminディレクトリ配下のリソースにアクセスするためにadminロールが必要になります。
ユーザのロールはweb.xmlのsecurity-role要素で定義します。
サーブレットのセキュリティモデルは3つの異なる認証方法をサポートしています。
- BASIC - セキュリティがそれほど重要でない内部向けのアプリケーションにおいてのみ推奨されます。これは最も簡単な認証方法で、保護されたリソースにアクセスする前にシンプルなダイアログを表示します。BASIC認証はユーザ名とパスワードをBase64エンコードされた文字列としてサーバに送信するため、それほど安全ではありません。
- DIGEST - 適度なセキュリティレベルが必要な内部向けのアプリケーションで推奨されます。BASIC認証と同じく保護されたりソースにアクセスする前に認証のためのダイアログを表示します。すべてのアプリケーションサーバがDIGEST認証をサポートしているというわけではなく、Apache Tomcatの比較的最近のバージョンだけがこの方法をサポートしています。
- FORM - カスタムログインページが必要なアプリケーションにおいて推奨されます。高いレベルのセキュリティを必要とするアプリケーションにおいてHTTP上でFORM認証を用いることが推奨されます。
認証方法は<login-method>要素で指定します。例えばBASIC認証を使用する場合は以下のように指定します:
FORM認証を使用するためにはログインページのパスとエラーページのパスも指定する必要があります:
Clickのlogin.htmページでは、j_usernameとj_passwordというフィールドを含むj_security_checkという特別なフォームが必要です:
FORM認証を使用する場合、Clickのログインページクラスの役割は単にログインフォームを表示することだけであるため、アプリケーションロジックを入れないようにしてください。もし、ログインページクラスにナビゲーションロジックを実装しようとするなら、J2EEコンテナは単にそれを無視するか、またはエラーを投げるかもしれません。
以下はadminパスとuserパス配下のページにセキュリティ制約を実現するweb.xmlの一部です。この設定は認証にFORM認証を使用し、認証されていないリクエスト(403)を/not-authorized.htmページにリダイレクトします。
代替のセキュリティソリューション
JEEでは利用できないRememberMe機能やより良いリソースマッピングとPostログインページサポートなどのように拡張された特徴を持つ代替のセキュリティソリューションも提供されます。(Postログインページサポートはユーザがログイン成功後に転送される1つのデフォルトURLの指定を許可します。この機能はすべての非セキュアページへのログインフォームの埋め込みとユーザ認証成功後のホームページへの転送を許可します。)
以下にいくつかの代替のセキュリティソリューションがあります:
その他のリソース
セキュリティに関するより多くの情報を得るために以下のリソースを参照してください:
- Form Based Authentication by Louis E. Mauget
- Servlet Specification by Sun Microsystems
- Basic authentication scheme
- Digest authentication scheme
- Https URI scheme
ページの自動マッピング
あなたはClickのページ自動マッピング機能を使用すべきです。詳しくはページの自動マッピングのトピックを参照してください。
自動マッピングを利用するとclick.xmlにURLのパスとページクラスのマッピングを手動で設定する必要がなくなります。あなたがこの規約に従えば、アプリケーションのメンテナンスはとても容易になり、対応するページクラスとHTMLテンプレートを迅速に決定することができます。
以下はclick.xmlの自動マッピングの設定例です:
ページテンプレートがどのようにページクラスにマッピングされるかを見るために、アプリケーションモードをdebugに設定すると、起動時にマッピングがリストアップされます。この例の場合、以下のようなリストが出力されます:
[Click] [debug] automapped pages: [Click] [debug] /category-tree.htm -> com.mycorp.dashboard.page.CategoryTree [Click] [debug] /process-list.htm -> com.mycorp.dashboard.page.ProcessList [Click] [debug] /user-list.htm -> com.mycorp.dashboard.page.UserList
ナビゲーション
フォワードやリダイレクトを使用してページ間の遷移を行う際、パスよりもみむしろページクラスを使用することでターゲットとなるページを示すべきです。これはコンパイル時のチェックを提供します。そしてもしページの移動があった場合にはJavaコード中のパス文字列を書き換える必要がなくなります。
ページクラスを使用してフォワードするには以下のようにします:
ページクラスを使用して別のページにリダイレクトするために、Contextからページのパスを得ることができます。以下の例ではxリクエストパラメータとして顧客IDをターゲットページに送信しています:
別ページへリダイレクトする迅速な方法は、単にターゲットクラスを参照することです。以下の例ではセッションを無効にすることでユーザをログアウトさせ、アプリケーションのホームページにリダイレクトしています:
テンプレーティング
ページのテンプレーティングの利用は強く推奨されます。ページテンプレートは以下を含む多くの利点を提供します:
- メンテナンスする必要のあるHTMLmp量を大幅に減少させます
- アプリケーション全体で統一されたルック&フィールを確約します
- アプリケーションのグローバルな変更を非常に簡単にします
テンプレートの利用方法についてはページ・テンプレーティングのトピックを参照してください。また、Clickのサンプルがページ・テンプレーティングを使用していますので、そちらも参考にしてください。
メニュー
多くのアプリケーションにとって、アプリケーションの画面遷移を集約するためにMenuコントロールはとても有用です。メニューはWEB-INF/menu.xmlで定義されており、変更はとても容易です。
メニューは通常、ページボーダーテンプレートで定義されるので、アプリケーション全体で使用可能です。MenuコントロールはHTMLレンダリングをサポートしないので、あなたはプログラム的にメニューをレンダリングするためにVelocityマクロを記述する必要があります。あなたはボーダーテンプレートで以下のようにマクロを呼び出すでしょう:
メニューをレンダリングするためにマクロを使用することの利点は、コードを異なるアプリケーションで再利用することができるという点です。そして、メニューを変更するには単にWEB-INF/menu.xmlを修正するだけでよいのです。マクロを定義するのに最もよい場所はWebアプリケーションルートの/macro.vmです。このファイルはClickによって自動的にインクルードされます。
マクロを使用することで、isUSerInRoles()でアクセスが許可されているユーザが認証されている場合のみ項目を表示するような動的なメニューを作成することも可能です。
また、JavaScriptを使用してドロップダウンメニューなどの動的な振る舞いを実現することもできます。例としてClickのサンプルのMenuのページを参照してください。
ロギング
ページでのロギングのためにあなたはLog4jを使用するべきです。代替ライブラリはCommons Loggingです。もしCommons Loggingを使用している場合、このライブラリにはいくつかのアプリケーションサーバにおいてクラスローダに関する問題があったことに注意してください。Commons Loggingを使用する場合は必ず最新版を使うようにしてください。
ロガーを定義するのに最も良い場所は共通の基底ページです。例えば:
このパターンでは、すべてのページクラスはBasePageを継承することでgetLogger()メソッドを使用できます。
非常に重いデバッグステートメントがある場合、isDebugEnabledスイッチを使用すべきかもしれません。それによってデバッグが必要でなければ呼び出されないようになります。
Clickのロギングファシリティはアプリケーションのためでなく、Click内部での利用のためにデザインされていることに注意してください。Clickがプロダクションモードで実行されている場合、全くログは出力されません。
エラーハンドリング
Clickでは、ハンドルされないエラーは表示するためにErrorPageに向けられます。もしアプリケーション独自のエラーハンドリングが必要な場合、カスタムエラーページをWEB-INF/click.xmlに登録することができます。
例を以下に示します:
一般にアプリケーションは、サービス層のコードもしくはサーブレットフィルタを使用することでトランザクションエラーを処理するため、エラーページにエラーハンドリング用のロジックを含む必要はないでしょう。
カスタムエラーページの潜在的な用途としては、独自のロギングも含まれています。
例えばアプリケーションがハンドルされないエラーを標準出力ではなくアプリケーションのログに出力する必要がある場合、カスタムエラーページを使うべきかもしれません。エラーのロギングを提供するAppErrorPageの例を示します:
パフォーマンス
Yahooは、Web アプリケーションのパフォーマンスを改善するベストプラクティスのリストを公開しました。
Click Frameworkには、 これらのルールのうちのいくつかを提供する PerformanceFilterがあります。
ここでは、PerformanceFilterでは対応していないルール -ルールその1: ファイルを連結することによってHTTPリクエストを最小化する と ルールその10: JavascriptとCSSを小さくする- を採用する方法についての要点を述べます。
ルールその1に関して元記事の中ではCSSスプライトについての言及がありますが、ここではCSSスプライトについての話題はに触れません。
指摘したいのは、Webアプリケーション中の個々のページをやみくもに最適化する必要はないということです。その代わりにWebサイトのいわゆるホームページのような良く参照されるであろうページをを候補に絞ることになるでしょう。
このルールその1とその10を適用するのに有用ないくつかのツールが世の中には存在します。
- YUICompressor - JavaScriptとCSSファイルを縮小化および圧縮し、通信量を小さくします
- Ant Task for YUICompressor - YUICompressorを使用するAnt のタスクです
- JSMin - YUICompressorと同様のツールですが、縮小化のみで圧縮は行いません。このJSMinがYUICompressorよりまさる部分は実行速度が速いことと、YUICompressorはおおよそビルド時に使われるのに対してJSMinは実行時にもJavaScriptを縮小化するために利用することができる点です。
以下の記事は、YUICompressorとAntを使ってJavaScriptとCSSファイルを連結、圧縮する方法の概要です。
- Article explaining how to use Ant and YUICompressor for compression.
- Article outlining how to use a special YUICompressor Ant Task for compression.
上記のアプローチをとると、ClickでもPageで使用する全てのJavaScriptとCSSは2つのファイルに集約されます。ここでは仮にその2つのファイル名をhome-page.cssとhome-page.jsとして話を進めます。もちろんこの2つのファイルにはPageとControlを利用したときに生成される全てのJavaScriptとCSSが含まれていなければなりません。その上でClickに対して、これら圧縮された2つのファイル(home-page.cssとhome-page.js)"だけ"をincludeするよう指定します。
Clickは、ユーティリティクラスであるPageImportsを利用して、CSSとJavaScriptをincludeしています。PageImports はsetInitialized(boolean)メソッドを公開しており、これによりPageImportsがいつ完全に初期化されるかを制御できます。一旦PageImportsの初期化が完了すると、CSSもJavaScriptもincludeされることがなくなります。
Page.GetPageImports()をオーバーライドできることをふまえて、必要なJavaScriptとCSSファイルをimportし、PageImportsを初期化された状態にセットし、PageImportsが他のCSSやJavaScriptファイルをスキップするよう強制します。
以下がサンプルになります。
以下のborder-template.htmを使います。
出力されるHTMLは、ひとつのCSSファイルとひとつのJavaScriptファイルをimportします。
実際に動作するデモがこちらにあります。