少しまともなWebアプリケーションは、さまざまなデザインパターンで構成されています。最も重要なものだけを取り上げます。
使用するコア(アーキテクチャー)設計パターンは、Model-View-Controllerパターンです。コントローラは、直接特定の用途/作成(IN)サーブレットで表されるべきであるモデルとビューの要求に基づい。モデルのJavaBeanクラスで表現されます。これは多くの場合、アクション(動作)を含むビジネスモデルとデータ(情報)を含むデータモデルでさらに分割できます。ビューは、(に直接アクセスしていJSPファイルで表現されるデータ)モデル EL(式言語)によると。
次に、アクションとイベントの処理方法に基づいてバリエーションがあります。人気のあるものは次のとおりです。
リクエスト(アクション)ベースのMVC:これは実装が最も簡単です。(ビジネス)モデルはオブジェクトHttpServletRequest
と直接連携しHttpServletResponse
ます。リクエストパラメータを収集し、変換し、検証する必要があります(ほとんどの場合)。ビューは、プレーンバニラのHTML / CSS / JSで表すことができ、それはリクエスト間で状態を維持しません。これが、Spring MVC、Struts、およびStripesの動作方法です。
コンポーネントベースのMVC:これは実装が困難です。しかし、最終的には、すべての「生の」サーブレットAPIが完全に抽象化された、より単純なモデルとビューになります。リクエストパラメータを自分で収集、変換、検証する必要はありません。コントローラは、このタスクとセットで集められ、変換され、検証リクエストパラメータんモデル。必要なのは、モデルプロパティを直接操作するアクションメソッドを定義することだけです。のビュー今度はHTML / CSS / JSを生成するJSPタグライブラリまたはXML要素の風味で「コンポーネント」で表されます。の状態ビュー後続のリクエストはセッションで維持されます。これは、サーバー側の変換、検証、および値変更イベントに特に役立ちます。これがJSF、Wicket、Playなどの方法です。動作します。
補足として、自家製のMVCフレームワークを趣味で使うことは非常に素晴らしい学習課題であり、個人的またはプライベートな目的でそれを維持する限り、私はそれをお勧めします。しかし、いったんプロになったら、独自のフレームワークを作り直すのではなく、既存のフレームワークを選択することを強くお勧めします。既存の十分に開発されたフレームワークを学ぶことは、堅牢なフレームワークを自分で開発して維持するよりも、より短い時間で済みます。
以下の詳細な説明では、実装が簡単なので、リクエストベースのMVCに制限します。
最初に、コントローラーパーツはフロントコントローラーパターン(特殊な種類のメディエーターパターン)を実装する必要があります。これは、すべての要求の中央エントリーポイントを提供する単一のサーブレットのみで構成する必要があります。pathinfoやservletpath、メソッド、特定のパラメーターなど、リクエストによって利用可能な情報に基づいてモデルを作成する必要があります。ビジネスモデルが呼ばれるAction
以下にHttpServlet
例。
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
Action action = ActionFactory.getAction(request);
String view = action.execute(request, response);
if (view.equals(request.getPathInfo().substring(1)) {
request.getRequestDispatcher("/WEB-INF/" + view + ".jsp").forward(request, response);
}
else {
response.sendRedirect(view); // We'd like to fire redirect in case of a view change as result of the action (PRG pattern).
}
}
catch (Exception e) {
throw new ServletException("Executing action failed.", e);
}
}
アクションを実行すると、ビューを見つけるための識別子が返されます。最も簡単な方法は、JSPのファイル名として使用することです。具体的には、このサーブレットの地図url-pattern
ではweb.xml
、例えば/pages/*
、*.do
あるいは単に*.html
。
たとえば、プレフィックスパターンの場合、http://example.com/pages/registerなどの/pages/*
URLを呼び出すことができます。 http://example.com/pages/login、などと提供し/WEB-INF/register.jsp
、/WEB-INF/login.jsp
適切なGETとPOSTアクションで。部品register
、login
などはrequest.getPathInfo()
、上記の例のようにして使用できます。
あなたが使用している場合は、サフィックス・パターンが好き*.do
、*.html
など、あなたでしその後、URLのinvokeのようにhttp://example.com/register.do、 http://example.com/login.do、など、あなたが変更する必要がありますこの回答のコード例(もActionFactory
)を抽出するregister
とlogin
によって部品をrequest.getServletPath()
代わりに。
Action
従うべきであるStrategyパターンを。これは、抽象メソッドの渡された引数に基づいて作業を行う抽象/インターフェース型として定義する必要があります(これは、コマンドパターン抽象/インターフェースタイプは、実装の作成中に渡される引数)。
public interface Action {
public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception;
}
のException
ようなカスタム例外を使用して、より具体的にすることができActionException
ます。これは基本的なキックオフの例に過ぎず、残りはすべてあなた次第です。
LoginAction
これは(名前が示すように)ユーザーにログインするの例です。User
自身のターンであるデータモデル。ビューはの存在を認識していますUser
。
public class LoginAction implements Action {
public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
String username = request.getParameter("username");
String password = request.getParameter("password");
User user = userDAO.find(username, password);
if (user != null) {
request.getSession().setAttribute("user", user); // Login user.
return "home"; // Redirect to home page.
}
else {
request.setAttribute("error", "Unknown username/password. Please retry."); // Store error message in request scope.
return "login"; // Go back to redisplay login form with error.
}
}
}
ActionFactory
従うべきFactory Methodパターンを。基本的に、抽象/インターフェース型の具体的な実装を返す作成メソッドを提供する必要があります。この場合、Action
リクエストによって提供された情報に基づいて、インターフェースの実装を返す必要があります。たとえば、メソッドとpathinfo(pathinfoは、クエリ文字列を除く、リクエストURLのコンテキストとサーブレットパスの後の部分です)。
public static Action getAction(HttpServletRequest request) {
return actions.get(request.getMethod() + request.getPathInfo());
}
actions
順番にいくつかの静的/アプリケーションにわたるでなければなりませんMap<String, Action>
すべての既知のアクションを保持する全体である。この地図を埋める方法はあなた次第です。ハードコーディング:
actions.put("POST/register", new RegisterAction());
actions.put("POST/login", new LoginAction());
actions.put("GET/logout", new LogoutAction());
// ...
または、クラスパスのプロパティ/ XML構成ファイルに基づいて構成可能:(疑似)
for (Entry entry : configuration) {
actions.put(entry.getKey(), Class.forName(entry.getValue()).newInstance());
}
または、特定のインターフェースやアノテーションを実装するクラスのクラスパスのスキャンに基づいて動的に:(疑似)
for (ClassFile classFile : classpath) {
if (classFile.isInstanceOf(Action.class)) {
actions.put(classFile.getAnnotation("mapping"), classFile.newInstance());
}
}
Action
マッピングがない場合のために「何もしない」を作成することを覚えておいてください。たとえば、request.getPathInfo().substring(1)
そのときに直接返すようにします。
その他のパターン
これらはこれまでのところ重要なパターンでした。
さらに一歩進んだ方法として、Facadeパターンを使用してContext
クラスを作成し、クラスを作成して要求オブジェクトと応答オブジェクトをラップし、要求オブジェクトと応答オブジェクトに委譲し、Action#execute()
代わりにメソッドに引数として渡すいくつかの便利なメソッドを提供できます。これにより、抽象サーブレット層が追加され、未加工のサーブレットAPIが非表示になります。その後、基本的にすべての実装で宣言がゼロになる はずです。JSF用語では、これはおよびクラスが行っていることです。あなたはこの答えで具体的な例を見つけることができますimport javax.servlet.*
Action
FacesContext
ExternalContext
。
次に、リクエストパラメータの収集、変換、検証、モデル値の更新、アクションの実行などのタスクを分割するために、追加の抽象化レイヤーを追加する場合の状態パターンがあります。JSF用語では、これはLifeCycle
が行っていることです。
次に、モデルにアタッチできるコンポーネントベースのビューを作成する場合の複合パターンがあり、その動作はリクエストベースのライフサイクルの状態に依存します。JSF用語では、これはUIComponent
代表的なものです。
このようにして、コンポーネントベースのフレームワークに向かって少しずつ進化させることができます。
以下も参照してください。