1. ホーム
  2. java

[解決済み] デザインパターン Webベースアプリケーション【終了しました

2022-03-15 23:44:18

質問事項

簡単なWebベースのアプリケーションを設計しています。私はこのWebベースのドメインに新しいです。私は、サーブレット間でどのように責任を分配するべきか、新しいサーブレットを作るための基準など、デザインパターンに関するあなたのアドバイスが必要です。

実は、私のホームページにはいくつかのエンティティがあり、それぞれに追加、編集、削除のようなオプションがあります。以前は、Servlet1がentity1の追加、Servlet2がentity1の編集といったように、オプションごとに1つのServletを使っていましたが、この方法では、結局、多数のServletを持つことになりました。

今、私たちはデザインを変えているところです。私の質問は、サーブレットの責任をどのように正確に選択するかということです。エンティティごとに1つのサーブレットを用意して、そのエンティティが持つすべてのオプションを処理し、リクエストをサービスレイヤーに転送するようにすればいいのでしょうか。それとも、ページ全体のリクエストを処理し、対応するサービスレイヤーに転送する、ページ全体に対して1つのサーブレットを持つべきでしょうか?また、リクエストオブジェクトはサービスレイヤーに転送されるべきなのか、そうでないのか。

どのように解決するのですか?

ちょっとまともなWebアプリケーションは、様々なデザインパターンの組み合わせで構成されています。ここでは、最も重要なものだけを紹介します。


Model View Controllerパターン

使いたいコア(アーキテクチャ)なデザインパターンは Model-View-Controller パターン . その コントローラ を直接作成/使用するサーブレットで表現されます。 モデル ビュー をリクエストに基づかせます。は、その モデル は、Javabeanクラスで表現される。これは、多くの場合、さらに ビジネスモデル アクション(振る舞い)を含む データモデル であり、データ(情報)を含む。その ビュー に直接アクセスできるJSPファイルによって表現されます。 データ ) モデル EL (Expression Language)によるものです。

そして、アクションやイベントの処理方法によるバリエーションがあります。ポピュラーなものは

  • リクエスト(アクション)ベースのMVC : これが最もシンプルな実装です。この場合、( 事業内容 ) モデル は直接 HttpServletRequestHttpServletResponse オブジェクトを作成します。リクエストパラメータを収集し、変換し、検証するのは (ほとんど) あなた自身です。そのため 表示 は、プレーンなバニラ HTML/CSS/JS で表現でき、リクエスト間で状態を維持することはない。このため、特に スプリングMVC , Struts ストライプ が動作します。

  • コンポーネントベースのMVC これは実装が難しいですね。しかし、よりシンプルなモデルとビューになり、すべてのquot;raw;Servlet APIが完全に抽象化されます。リクエストパラメータを自分で収集し、変換し、検証する必要はないはずです。そのため コントローラ はこのタスクを行い、収集、変換、検証されたリクエストパラメータを モデル . 必要なのは、モデルのプロパティと直接連携するアクションメソッドを定義することだけです。そのため 表示 は、JSPタグリブやXML要素で構成されるquot;components"で表現され、HTML/CSS/JSを生成します。また ビュー 後続のリクエストのために、セッションで管理されます。これは特にサーバーサイドの変換、検証、値変更イベントにおいて有用です。このようにして、特に JSF , ウィケット および プレイ! が動作します。

余談ですが、趣味で自作のMVCフレームワークを使うのはとてもいい勉強になりますし、個人的な目的であればおすすめです。しかし、プロフェッショナルになるのであれば、自分でフレームワークを作り直すのではなく、既存のフレームワークを選ぶことを強くお勧めします。既存のよく開発されたフレームワークを学ぶことは、自分で堅牢なフレームワークを開発・維持するよりも長期的には時間がかからないからです。

以下の詳細な説明では、実装が簡単なリクエストベースのMVCに限定して説明します。


フロントコントローラーのパターン ( メディエーターパターン )

まず コントローラ の部分を実装する必要があります。 Front Controllerパターン (これは Mediatorパターン ). これは、すべてのリクエストの集中エントリーポイントを提供する単一のサーブレットのみから構成されるべきです。それは モデル は、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-patternweb.xml は、例えば /pages/* , *.do または単に *.html .

プリフィックスパターンの場合、例えば /pages/* のような URL を呼び出すことができます。 http://example.com/pages/register , http://example.com/pages/login などを提供し /WEB-INF/register.jsp , /WEB-INF/login.jsp を適切な GET および POST アクションで指定します。部品 register , login で利用できるようになります。 request.getPathInfo() 上記の例のように

のようなサフィックス・パターンを使用する場合、以下のようになります。 *.do , *.html のようなURLを呼び出すことができます。 http://example.com/register.do , http://example.com/login.do などがあり、この回答のコード例を変更する必要があります(また、この回答の ActionFactory を抽出するようにします。 registerlogin による部品 request.getServletPath() の代わりに


戦略パターン

Action の後に続く必要があります。 戦略パターン . に基づいて作業を行う抽象/インターフェース型として定義される必要があります。 渡された の引数は、抽象的なメソッドの引数です(ここが コマンドパターン で渡された引数に基づいて、抽象/インターフェース型が処理を行います。 作成 実装の)。

public interface Action {
    public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception;
}

を、(1)のように 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 の後に続く必要があります。 ファクトリーメソッドパターン . 基本的には、抽象型/インターフェース型の具体的な実装を返す作成メソッドを提供する必要があります。この場合、このメソッドは Action インターフェイスを提供する。例えば メソッド パスインフォ (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) では


その他のパターン

ここまでが重要なパターンでした。

さらに一歩踏み込むために ファサードパターン を作成し Context このクラスはリクエストとレスポンスオブジェクトをラップし、 リクエストとレスポンスオブジェクトに委譲するいくつかの便利なメソッドを提供し、 そのメソッドを引数として Action#execute() メソッドで代用できます。これにより、生のサーブレット API を隠すための抽象的なレイヤーが追加されます。そうすると、基本的には以下のようになります。 ゼロ import javax.servlet.* の宣言は、すべての Action の実装があります。JSFの用語で言うと、これは FacesContext ExternalContext クラスが行っています。具体的な例は この回答 .

次に 状態パターン リクエストパラメーターの収集、変換、検証、モデル値の更新、アクションの実行といったタスクを分割するために、追加の抽象化レイヤーを追加したい場合です。JSFの用語で言えば、これが LifeCycle が行っています。

次に コンポジットパターン は、モデルにアタッチ可能で、その挙動がリクエストベースのライフサイクルの状態に依存するコンポーネントベースのビューを作成したい場合のためにあります。JSFの用語で言うと、これは UIComponent を表します。

こうすることで、コンポーネントベースのフレームワークへと少しずつ進化させることができるのです。


こちらもご覧ください。