はしくれエンジニアもどきのメモ

情報系技術・哲学・デザインなどの勉強メモ・備忘録です。

Java MVCフレームワークでショッピング風サイトを作る(Controller 編)

Java MVCフレームワークでショッピング風サイトを作る(Controller 編)

Java MVCフレームワークでショッピング風サイトを作って見たのでメモ。 今回はラストのController 編。前回Model 編の続き。

cartman0.hatenablog.com

環境

仕様・構成

  1. 「ログイン画面(index.jsp)」からあらかじめDBに保存しているユーザIDをパスワードを使ってログインする。

  2. 「商品一覧画面(itemList.jsp)」へ遷移するので、 商品一覧の中から購入数(あらかじめ決めた在庫数まで)を選択して、購入ボタンを選択。

  3. すると、 「購入確認画面(confirm_result.jsp)」へ遷移し、 購入ボタンをまた選択する。

  4. 商品が購入され、「購入結果画面(result.jsp)」へ遷移し、

  5. 一覧へ戻るを選択して、「商品一覧画面(itemList.jsp)」へ戻ってくる(在庫数は再計算されている)

また、購入履歴を選択した場合は、 過去に何を買ったかを「購入履歴画面(history.jsp)」へ遷移する。

Controller(Servlet)ファイルの確認

今回使うServlet は4種類。

クラス名説明
LoginServlet.java ログイン・ログアウトなどの処理を受け付け
ShoppingServlet.java 商品一覧・購入履歴などの処理を受け付け
BuyItemServlet.java 商品購入処理を受け付け
ResultServlet.java 商品購入結果処理を受け付け

商品を買う場合のActivity図

商品を買う場合のActivity図は、以下のようになる。

LoginServlet が、ログイン画面からform(POST) でユーザIDとパスワードを受け取り、ログイン処理を行う。 ログインに成功した場合ShoppingServlet へforward する。

ログインに成功した場合、ShoppingServlet がDBからShoppingDaoを使って、商品一覧情報を取得して、商品一覧画面 へ遷移する。 また、購入履歴リンクが選択された場合は、GETパラメータで判断して、購入履歴画面へ遷移する。

商品一覧画面から「購入」ボタンが選択された場合はBuyItemServlet が受け付け、購入確認画面へ遷移する。

購入確認画面からさらに「購入する」ボタンを選択すると、ResultServletが受け付け、購入結果画面へ遷移する。

商品を買う場合のActivity図ログイン商品一覧購入確認購入結果購入履歴ログイン画面LoginServletLoginDBLoginDaoLoinUserBeanShoppingServletShoppingShoppingDaoItemBeanHistoryBean商品一覧画面BuyItemServlet購入確認画面ResultServlet購入結果画面購入履歴画面

状態(画面)遷移図

状態遷移図で表すと以下のようになる。

画面(View)の状態遷移図 ログイン画面index.jspログイン前 商品一覧画面itemList.jsp ログイン画面index.jspログイン後 ログインエラー画面loginFailed.jsp 購入履歴画面history.jsp 購入確認画面purchase_confirm.jsp 購入結果画面result.jsp ユーザID, パスワードを入力 ログアウト ログアウト ログイン 戻る ログイン失敗 ログイン失敗 購入履歴 数量と購入を選択 一覧に戻る ログアウト 購入履歴 購入する ログアウト 購入履歴 一覧に戻る

Controller(Servlet)の作成

LoginServlet.java

LoginServlet が、ログイン画面からform(POST) でユーザIDとパスワードを受け取り、DBのuserテーブルからLoginDaoを使ってユーザ情報を取ってきて、 ログイン処理を行う。

ログインに失敗した場合、ログインエラー画面(loginFailed.jsp)へforwardする。

ログインに成功した場合、セッションにユーザ情報(login_user_bean)とログイン状態(login_state) を付加(setAttribute) し、 ShoppingServlet へforward する。

ログアウトのリンクが選択された場合、 セッションに付加されていたユーザ情報(login_user_bean)とログイン状態(login_state) を削除する。


package login;

import java.io.IOException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

@WebServlet(name = "LoginServlet", urlPatterns = {"/LoginServlet"})
public class LoginServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;

    /**
     * コンストラクタ.
     */
    public LoginServlet() {
        super();
    }

    /**
     * Handles the HTTP GET method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");

        String para = request.getParameter("submit");

        HttpSession session = request.getSession();

        if (para.equals("logout")) {
            // ④ クリックされたボタンが「logout」の場合はログアウト処理(セッションの破棄)を実施
            session.removeAttribute("login_state");
            session.removeAttribute("login_user_bean");
            response.sendRedirect("./");
        }

    }

    /**
     * Handles the HTTP POST method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");

        String btn = request.getParameter("submit");

        HttpSession session = request.getSession();
        RequestDispatcher rd;

        if (btn.equals("ログイン")) {
            // ③-1-1 ログイン画面で入力されたIDとパスワードを取得
            String id = request.getParameter("id");
            String pass = request.getParameter("pass");

            // ③-1-2 ユーザ情報をモデルに格納するために指示
            // ③-1-3 ログイン処理クラスをインスタンス化
            LoginDB login = new LoginDB();

            // ③-1-4 ID処理クラスに②-1-1で取得したIDを渡してユーザ情報をモデルに格納
            LoginUserBean bean = login.getUserData(id, pass);

            // ③-2 モデルの情報を判定
            if (bean != null) {
                // ③-2-1 モデルの情報が存在する場合はsetAttributeメソッドを使ってセッションに情報をセット
                // モデル(ユーザ情報)
                session.setAttribute("login_user_bean", bean);
                // ログイン状態
                session.setAttribute("login_state", "login");

                // ③-2-2 つぎに表示させる画面(ビュー)を指定
                rd = request.getRequestDispatcher("./ShoppingServlet");
            } else {
                // ③-3 モデルの情報が存在しない(IDに紐づくユーザ情報がない)場合
                // ③-3-1 つぎに表示させる画面(ビュー)を指定
                rd = request.getRequestDispatcher("./jsp/loginFailed.jsp");
            }

            rd.forward(request, response);

        } else if (btn.equals("ログアウト")) {
            // ④ クリックされたボタンが「logout」の場合はログアウト処理(セッションの破棄)を実施
            session.removeAttribute("login_state");
            session.removeAttribute("login_user_bean");
            response.sendRedirect("./");
        }

    }
}

ShoppingServlet.java

doPost では、 ログインに成功した場合、ShoppingServlet がDB からShoppingDao を使って、商品一覧情報を取得して、商品一覧画面(itemList.jsp) へforward する。

doGet では、 購入履歴リンクが選択された場合は、GETパラメータ(ShoppingServlet?submit=history)で判断して、購入履歴画面(history.jsp) へ遷移する。


package shopping;

import java.io.IOException;
import java.util.ArrayList;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import login.LoginUserBean;

@WebServlet(name = "ShoppingServlet", urlPatterns = {"/ShoppingServlet"})
public class ShoppingServlet extends HttpServlet {

    /**
     * Handles the HTTP GET method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");

        HttpSession session = request.getSession();
        RequestDispatcher rd;

        /*
         * 履歴を表示する処理
         */
        if (session.getAttribute("login_state").equals("login")) {
            String para = request.getParameter("submit");

            if (para.equals("history")) {
                Shopping shopping = new Shopping();

                // session からユーザID を取得
                String user_id = *1.getId();

                //  購入履歴を取得
                ArrayList<HistoryBean> history_beans = shopping.getHistory(user_id);

                // リクエストスコープにセットして画面移動
                request.setAttribute("history", history_beans);
                rd = request.getRequestDispatcher("./jsp/history.jsp");
                rd.forward(request, response);
            }
        }
    }

    /**
     * Handles the HTTP POST method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");

        // 商品一覧を取得
        Shopping shopping = new Shopping();
        ArrayList<ItemBean> item_list = shopping.getItem();
        System.out.println("item_list" + item_list);

        // 商品一覧をリクエストスコープの属性にセット
        request.setAttribute("itemList", item_list);

        // 商品一覧画面に移動
        RequestDispatcher rd = request.getRequestDispatcher("./jsp/itemList.jsp");
        rd.forward(request, response);
    }

    /**
     * Returns a short description of the servlet.
     *
     * @return a String containing servlet description
     */
    @Override
    public String getServletInfo() {
        return "Short description";
    }
  }

BuyItemServlet.java

商品一覧画面から「購入」ボタンが選択された場合は、 doGet()では、商品IDと購入数をGETパラメータでBuyItemServlet が受け付け、 購入確認画面(purchase_confirm.jsp) へ遷移する。

今回、doPost()は使ってない。


package shopping;

import java.io.IOException;
import java.util.Enumeration;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 商品購入ページ処理クラス.
 */
@WebServlet("/BuyItemServlet")
public class BuyItemServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;

    /**
     * コンストラクタ.
     */
    public BuyItemServlet() {
        super();
    }

    /**
     * GETメソッドで呼び出された場合の処理
     *
     * @param request
     * @param response
     * @throws javax.servlet.ServletException
     * @throws java.io.IOException
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        // GETメソッドのパラメータ名を取得
        Enumeration<String> names = request.getParameterNames();

        String name;        // 現在のパラメータ名
        String item_id = "";        // 商品ID
        String purchased_num;   // 購入数

        // 購入ボタンがクリックされた場所を特定
        // 今回のサンプルプログラムの場合、クリックされた購入ボタンの値(value)と、リストボックスの値が取得できる
        // 購入ボタンをクリックした後のURLにパラメータが記載されています
        while (names.hasMoreElements()) {
            // 渡ってきたパラメータを順番に処理
            // パラメータ名を取得
            name = names.nextElement();

            // 購入ボタンがクリックされている場合は「購入」のパラメータが取得できる
            if ("購入".equals(request.getParameter(name))) {
                // 購入ボタンに付属している値(value)が商品IDになる
                item_id = name;
            }
        }

        // ドロップダウンリストから購入数を取得
        purchased_num = request.getParameter(item_id + "list");

        // 商品情報を取得
        Shopping shopping = new Shopping();
        System.out.println("item_id: " + item_id);
        ItemBean item_bean = shopping.getItem(item_id);
        System.out.println("item_bean: " + item_bean);

        // 商品一覧をリクエストスコープの属性にセット
        request.setAttribute("item_bean", item_bean);
        request.setAttribute("purchased_num", purchased_num);

        // 購入確認画面に移動
        RequestDispatcher rd = request.getRequestDispatcher("./jsp/purchase_confirm.jsp");
        rd.forward(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    }
}

ResultServlet.java

購入確認画面からさらに「購入する」ボタンを選択すると、 doPost()で、 購入確認画面(purchase_confirm.jsp)にセットしていた値hiddenパラメータ)を ResultServlet が受け付け、購入結果画面(result.jsp)へforward する。

ShoppingDao を使って、在庫(stock)テーブルにアクセスして、 購入数分引いて更新する。 また、ユーザIDを使って、購入履歴(history)テーブルを更新する。

今回は、doGet() は使ってない。


package shopping;

import java.io.IOException;
import java.sql.SQLException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import login.LoginUserBean;

@WebServlet(urlPatterns = {"/ResultServlet"})
public class ResultServlet extends HttpServlet {

  private static final long serialVersionUID = 1L;

  /**
  * Handles the HTTP GET method.
  *
  * @param request servlet request
  * @param response servlet response
  * @throws ServletException if a servlet-specific error occurs
  * @throws IOException if an I/O error occurs
  */
  @Override
  protected void doGet(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
  }

  /**
  * Handles the HTTP POST method.
  *
  * @param request servlet request
  * @param response servlet response
  * @throws ServletException if a servlet-specific error occurs
  * @throws IOException if an I/O error occurs
  */
  @Override
  protected void doPost(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
  request.setCharacterEncoding("UTF-8");

  // ログインid取得
  String user_id = *2.getId();

  // 購入確認画面(purchase_confirm.jsp)にセットしていた値を取得(hiddenパラメータ)
  String item_id = request.getParameter("item_id");
  int purchased_num = Integer.parseInt(request.getParameter("item_quantity"));

  ShoppingDao dao = null;
  try {
      /*
       * 商品ID と購入数を元にDBを更新
       * 対象の商品在庫をマイナスにする
       */
      dao = new ShoppingDao();
      dao.updateItem(item_id, purchased_num);
      dao.updateHistory(user_id, item_id, purchased_num);
  } catch (SQLException sqle) {
      sqle.printStackTrace();
  } finally {
      if (dao != null) {
          dao.close();
      }
  }
  // 商品結果画面に移動
  RequestDispatcher rd = request.getRequestDispatcher("./jsp/result.jsp");
  rd.forward(request, response);

  }
}

コード

github.com

*1:LoginUserBean) session.getAttribute("login_user_bean"

*2:LoginUserBean) request.getSession().getAttribute("login_user_bean"