買い物かごを再表示するためのRefreshBasketServletクラスを作成
Servletの作成の仕方は既に説明しているため割愛します。作成の仕方が分からない方は当連載第2回目の3ページ以降で説明しています。
買い物かごのへの削除・追加のためのServletを作成します。まずは本数を増減させた場合に金額が正確に表示されるよう実装します。図2のように内容は第5回で作成したBasketServletクラスをほぼ同じです。
001: protected void processRequest(HttpServletRequest request, HttpServletResponse response)
002: throws ServletException, IOException {
003:
004: ArrayList basketItems = new ArrayList();
005:
006: String[] basketItemIds = request.getParameterValues("id");
007: String[] allQuantity = request.getParameterValues("quantity");
008:
009: int basketId = 0;
010:
011: BasketHelper basketHelper = new BasketHelper();
012: // ログインしたユーザidをもとにデータベースからbasket情報を
013: // 取得する。第5回は固定で「tomoharu」とする
014: basketId = basketHelper.getBasketId("tomoharu");
015:
016: basketHelper.updateBasketItems(basketItemIds, allQuantity);
017:
018: basketItems = basketHelper.getBasketItems(basketId);
019: request.getSession().setAttribute("basket", basketItems);
020:
021: // ImoshochuShop.jspに遷移する
022: RequestDispatcher rd = request.getRequestDispatcher("/ImoshochuShop.jsp");
023: rd.forward(request, response);
024:
025: }
BasketServletクラスと違うところは、JSPから受け取るパラメタの違い(6、7行目)と銘柄の挿入ではなく更新を行っている箇所(16行目)です。ただし、本数が0本の銘柄を削除することが仕様であるため、厳密にはupdateBasketItemsという名称ですが、削除処理も行っています。BasketHelperクラスのupdateBasketItemsはそのままDAOクラスのupdateItemsメソッドを呼び出しているだけであるため割愛します。サンプルコードでご確認ください。
BasketDAOImplクラスの変更
まずは図3のように定数として定義しているSQLに追加、変更します。
001: private static final String SQL_INSERT_BASKET = "insert into basket values(0, ?)"; 002: private static final String SQL_GET_BASKETID = "select * from basket where user_id = ?"; 003: private static final String SQL_INSERT_BASKET_ITEM = "insert into basket_item values(0, ?, ?, 1)"; 004: private static final String SQL_UPDATE_BASKET_ITEM = "update basket_item set quantity = ? where id = ?"; // 第6回で追加 005: private static final String SQL_DELETE_BASKET_ITEM = "delete from basket_item where id = ?"; // 第6回で追加 006: // 第6回でbasket_itemのidを返すよう変更 007: private static final String SQL_GET_ALL_BASKET_ITEMS = "select b.id as basket_item_id, m.id, m.name, m.price, b.meigara_id, b.quantity" 008: + " from (basket_item as b inner join meigara as m on b.meigara_id = m.id)" 009: + " where basket_id = ?";
4行目と5行目が追加したSQL文です。7行目がbasket_itemのidを取得するよう変更しています。説明が遅れましたが、SQL文の中にある「?」がプレースフォルダと呼ばれるもので、後で値を設定できるように用意されたものです。プレースフォルダを使用する場合はStatementではなくPreparedStatementを使用します。具体的にはupdateItemsメソッドで説明します。
次にupdateItemsメソッドを追加します。図4がupdateItemsメソッドの抜粋です。
001: Connection conn = null;
002: PreparedStatement updatePreparedStatement = null;
003: PreparedStatement deletePreparedStatement = null;
004: ArrayList updatedBasketItemIds = new ArrayList(Arrays.asList(basketItemIds));
005: ArrayList updatedAllQuantity = new ArrayList(Arrays.asList(allQuantity));
006: try {
007: conn = getConnection();
008: updatePreparedStatement = conn.prepareStatement(SQL_UPDATE_BASKET_ITEM);
009: deletePreparedStatement = conn.prepareStatement(SQL_DELETE_BASKET_ITEM);
010: for (int i = 0; i < updatedBasketItemIds.size(); i++) {
011: int basketItemId = Integer.parseInt(updatedBasketItemIds.get(i));
012: int quantity = Integer.parseInt(updatedAllQuantity.get(i));
013: if (quantity == 0) {
014: deletePreparedStatement.setInt(1, basketItemId);
015: deletePreparedStatement.executeUpdate();
016: } else {
017: updatePreparedStatement.setInt(1, quantity);
018: updatePreparedStatement.setInt(2, basketItemId);
019:
020: updatePreparedStatement.executeUpdate();
021: }
022:
023: }
024: } catch(SQLException se) {
少しトリッキーなコーディングになっていますが、可読性を高めるということでご勘弁ください。3、4行目で2つのPreparedStatementを定義しています。3行目が更新用、4行目が削除用となっています。
このように2つ定義したのは本数(quantity)が0の場合、削除。0以外の場合、更新する必要があるためです。13行目から21行目が削除と更新処理のコードです。13行目で先述のSQL_DELETE_BASKET_ITEMの?に画面から取得したbasket_itemのidを設定しています。このようにプレースフォルダは異なった値を入れるためのもので、プログラミング言語の変数に相当します。ただし、SQLに出現する?の順番に従って1から番号を指定する必要があります。
14行目で不完全であったSQL文が実行できるようになりました。15行目でSQL文を実行しています。これで本数が0の銘柄は買い物かごから削除されます。17、18、20行目が更新の場合の処理です。一点だけ注意しないといけないのは、データベースに接続し、処理を行い、終了したらリソースを解放するような処理は、ほとんどの場合一から作ることはなく、別のプロジェクトのプログラムからコピーして作成するが故にリソースの解放を忘れてしまいがちになることです。この例で言うと、PreparedStatementを2つ生成しているので、2つともfinallyブロックでcloseメソッドを使ってリソースを解放しなくてはなりません。
ここまでで、冒頭で説明した仕様の2と3を実装したことになります。
