【左京淳的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"...>来暂存要给後台的资料
  • 使用标签设计数字的显示格式。

<<:  如何取出阵列中重复/不重复的值

>>:  如何取出物件中重复/不重复的值

Day 09- Shell之Bash & Zsh

想谈这个,因为原本使用Mac制作购物车系统,发现Mac终端机的Shell预设为Bash,但看到网路上...

[30天 Vue学好学满 DAY28] keep-alive 状态保留

简介 vue原生元件,可达到cache目的。 使元件状态维持不变,不重走生命周期。 新增钩子 act...

Day 07 - Transduce I

从一个简单的问题开始 假设我们目前有一组长度为一百万的阵列,需要将阵列内的每个数值乘三并且只保留偶数...

密码开发方法

概述 此处参考NIST的加密标准和准则(CSRC)文件,当中的加密需求最佳指南。 参考资料 -lib...

18 | WordPress 自订 HTML 区块 Custom HTML Block

超文字标记语言 (HTML) 是用於描述网页语意内容的语言。你可以使用自订 HTML 区块新增此语言...