iT邦幫忙

0

【左京淳的JAVA WEB學習筆記】第十三章 購物車

購物車採用session儲存,結構為Map<String,Integer>。Key為isbn號,值為購入數。
Map中不儲存Book物件,只儲存isbn以節省空間。

查看購物車

已登入的用戶可以查看購物車,網址前綴一樣使用/user/*
localhost:8080/BookShop/user/ShopCarSvl

新建ShopCarSvl

@WebServlet("/user/ShopCarSvl")
public class ShopCarSvl extends HttpServlet {
  public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    Object obj = request.getSession().getAttribute("ShopCar");
    Map<String,Integer> isbns = (Map<String,Integer>)obj;
    BookBiz biz = new BookBiz();
    try {
      //從ShopCar把所有的isbn都交給getBook()去找書。
      List<TBook> books = biz.getBooks(isbns.keySet());
      request.setAttribute("books", books);
      request.getRequestDispatcher("/WEB-INF/main/ShopCar.jsp").forward(request, response);
    }catch(Exception e) {
      Log.logger.error(e.getMessage());
      request.setAttribute("msg", "系統忙碌中,請稍後再試");
      request.getRequestDispatcher("/error.jsp").forward(request, response);
    }
  }

在BookBiz中新增getBooks()

  public List<TBook> getBooks(Set<String> isbns) {
    List<TBook> books = null;
    IBookDao dao = new BookDaoMysql();
    try {
      if(isbns.size() > 0) {
        books = dao.getBooks(isbns);
      }
    }finally {
      dao.closeConnection();
    }
  }

在BookDaoMysql中新增getBooks()

  public List<TBook> getBooks(Set<String> isbns)  throws Exception{
    List<TBook> books = null;
    String strIsbns = "";
    int ii = 0;
    for(String isbn:isbns) {
      if(ii == 0) {
        strIsbns = "'" + isbn + "'";
      }else {
        strIsbns = strIsbns + "," + "'" + isbn + "'";
      }
      ii++;
    }
    String sql = "select isbn,bname,press,price,pdate from tbook where isbn in (" + strIsbns + ")";
    this.openConnection(); 
    PreparedStatement ps = this.connection.prepareStatement(sql);
    ps.setString(1, strIsbns);
    ResultSet rs = ps.executeQuery();
    if(rs != null) {
      books = new ArrayList<TBook>();
      while(rs.next()) {
        TBook book = new TBook();
        book.setBname(rs.getString("bname"));
        book.setIsbn(rs.getString("isbn"));
        book.setPdate(rs.getString("Pdate"));
        book.setPress(rs.getString("press"));
        book.setPrice(rs.getString("price"));
        books.add(book);
      }
    }
    rs.close();
    ps.close();
    return books;
  }

記憶重點

  • isbns是set物件,使用for迴圈將其取出並組合成文字列後加入sql文中。

新建ShopCar.jsp

"  <form action=""<%=basePath%>user/ShopCarSvl"" method=""post"">
    <table align=""center"" width=90%>
      <tr><td align=""right""><jsp:include page=""mhead.jsp""></jsp:include></td></tr>
      <tr>
        <td>
          <table border=""1"" width=100%>
            <tr><td>書名</td><td>商品價格</td><td width=""5%"">數量</td><td>操作</td></tr>
            <c:forEach var=""bk"" items=""${books }"">
              <tr>
                <td>${bk.bname }</td>
                <td>${bk.price }</td>
                <td><input type=""text"" name=""${bk.isbn }"" value=""1""></td>
                <td><a href=""<%=basePath%>user/ShopCarRemoveSvl?isbn=${bk.isbn }"">移除</a></td>
              </tr>
            </c:forEach>
          </table>
        </td>
      </tr>
      <tr>
        <td align=""center"">
          <c:if test=""${books.size()>0 }"">
            <input type=""submit"" value=""結帳"">
          </c:if>
          &nbsp;
          <a href=""<%=basePath%>MainSvl>"">返回</a>
        </td>
      </tr>
    </table>
  </form>"

記憶重點

  • 使用jsp:include標籤添加導覽行
  • 數量欄位使用可修改的標籤,name指定為該書的isbn,供結帳處理使用。

商品加入購物車

在商品明細頁,可以添加商品至購物車。若用戶未登入則由過濾器導向登入頁面。
新增"加入購物車"按鈕

<a href="<%=basePath%>user/ShopCarAddSvl?isbn=${bk.isbn }">加入購物車</a>

新建ShopCarAddSvl

@WebServlet("/user/ShopCarAddSvl")
public class ShopCarAddSvl extends HttpServlet {
  public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    String isbn = request.getParameter("isbn");
    if(isbn == null) {
      throw new ServletException("未找到isbn");
    }
    Object obj = request.getSession().getAttribute("ShopCar");
    Map<String,Integer> shopCar = (Map<String,Integer>)obj;
    shopCar.put(isbn, 1);
    request.getRequestDispatcher("/user/ShopCarSvl").forward(request, response);
  }

從購物車移除商品

<a href="<%=basePath%>user/ShopCarRemoveSvl?isbn=${bk.isbn }">移除</a>

新增ShopCarRemoveSvl

@WebServlet("/user/ShopCarRemoveSvl")
public class ShopCarRemoveSvl extends HttpServlet {
  public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    String isbn = request.getParameter("isbn");
    Object obj = request.getSession().getAttribute("ShopCar");
    Map<String,Integer> isbns = (Map<String,Integer>)obj;
    isbns.remove(isbn);
    request.getRequestDispatcher("/user/ShopCarSvl").forward(request, response);
  }

記憶重點

  • 使用購物車相關功能時,從session取得Map<String,Integer>ShopCar。
  • 顯示購物車內商品列表時,把isbns交給BookBiz去取得列表。(此時把ShopCar命名為isbns,是因為處理標的為isbns)
  • 追加商品時,使用Map<>.put()
  • 刪除商品時,使用Map<>.remove()

結算

在購物車的商品一覽頁面有結算按鈕,點擊前往CheckoutSvl,並攜帶商品列表中的isbns作為參數。
isbns是由<c:forEach>動態產生如下:

<c:forEachvar="bk"items="${books}">
<tr><td><inputtype="text"name="${bk.isbn}"value="1"></td></tr>
</c:forEach>

新建CheckoutSvl

@WebServlet("/user/CheckoutSvl")
public class CheckoutSvl extends HttpServlet {
  public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    Object obj = request.getSession().getAttribute("ShopCar");
    Map<String,Integer> isbns = (Map<String,Integer>)obj;
    BookBiz biz = new BookBiz();
    try {
      //利用ShopCar內的isbns取得DB內的books列表
      List<TBook> books = biz.getBooks(isbns.keySet());
      //遍歷books,利用isbn當key,取得購買數量(value)
      for(TBook book:books) {
        String value = request.getParameter(book.getIsbn());
        int bookCount = 1;
        try {
          //若用戶輸入數量不為空
          if(value != null && !value.trim().equals("")) {
            bookCount = Integer.parseInt(value);
            //將購買數量設定到book物件內
            book.setBuyCount(bookCount);
            isbns.put(book.getIsbn(), bookCount);
          }
        }catch(Exception e){
          //無法判斷的數量當作1處理
          Log.logger.error("購買數量應為整數:" + e.getMessage());
          book.setBuyCount(1);
          isbns.put(book.getIsbn(), 1);
        }
        //計算總額
        double allMoney = 0;
        for(TBook bk:books) {
          allMoney = allMoney + bk.getPrice()*bk.getBuyCount();
        }
        request.setAttribute("books", books);
        request.setAttribute("allMoney", allMoney);
        request.getRequestDispatcher("/WEB-INF/main/Checkout.jsp").forward(request, response);
      }      
    }catch(Exception e) {
      request.setAttribute("msg", "系統忙碌中,請稍後再試");
      request.getRequestDispatcher("/error.jsp").forward(request, response);
    }
  }

記憶重點

  • 由於訂購數量是由用戶輸入,需要先進行整理:
  • 利用request從頁面取得訂購數量
  • 確認非空且能轉為整數,若非整數則預設當作1處理
  • 取得數量後利用setBuyCount(bookCount)方法,將數量設定到book物件中
  • 更新購物車:用新物件取代舊物件isbns.put(book.getIsbn(), bookCount);

整理完後計算金額

  • 重新遍歷一次books,依照商品價格*數量計算總額。
  • 把商品列表和總額設定給request,帶回頁面給用戶。

新建Checkout.jsp

<%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%> 
(中略..)
  <form action="<%=basePath%>user/PayMoneySvl" method="post">
    <table align="center" width=90%>
      <tr><td align="right"><jsp:include page="mhead.jsp"></jsp:include></td></tr>
      <tr>
        <td>
          <table border="1" width=100%>
            <tr><td>書名</td><td>出版社</td><td>商品價格</td><td width="5%">數量</td></tr>
            <c:forEach var="bk" items="${books }">
              <tr>
                <td>${bk.bname }</td>
                <td>${bk.press }</td>
                <td>${bk.price }</td>${bk.buyCount }本
              </tr>
            </c:forEach>
              <tr>
                <td colspan="4" align="center">帳戶餘額:"$"${user.account }&nbsp;&nbsp;&nbsp;&nbsp;商品總價:"$"
                  <fmt:formatNumber value="${allMoney }" pattern="#.00" type="number"></fmt:formatNumber>
                  <input type="hidden" name="allMoney" value="${allMoney }">
                </td>
              </tr>
          </table>
        </td>
      </tr>
      <tr>
        <td align="center">
          <c:if test="${user.account >= allMoney }">
            <input type="submit" value="確認付款">
          </c:if>
          &nbsp;
          <a href="<%=basePath%>MainSvl>">返回</a>
        </td>
      </tr>
    </table>
  </form>

記憶重點

  • 使用<c:if>標籤決定是否顯示"確認付款"按鈕
  • 使用<input type="hidden"...>來暫存要給後台的資料
  • 使用標籤設計數字的顯示格式。

尚未有邦友留言

立即登入留言