購物車類及購物車DAO
購物車
該類也是一個JavaBean,除了普通Getter和Setter,這裡還實現了一個擷取單種書籍的總費用的方法。我們利用一個以書本對象為Key,以相應書本數量為value的HashMap存放購物中的所有書本。這樣就可以有效表示購物車中的書本及其數目。
entiry.Cart.java
package entity;import java.util.HashMap;import java.util.Iterator;import java.util.Set;public class Cart {// 車裡會有很多的商品,所以我們可以用一個Map存放起來// 商品集合 private HashMap<Book, Integer> books; public Cart(){} public HashMap<Book, Integer> getBooks() { return books; } public void setBooks(HashMap<Book, Integer> books) { this.books = books; } public double getOneTypeBookCostInCart(Book book){ return book.getPrice()* books.get(book); }}
購物車DAO
對操作邏輯進行必要的分析,我們可以知道UserDAO需要有如下方法: 判斷購物車中是否已有選中書本,用於判斷是插入資料還是更新資料 添加書本 刪除書本 擷取使用者購物車
在購物車中,我們通過uid和isbn對一本書進行確定,也就確定是誰的購物車,哪一本書。在添加一本書中,我們需要先判斷購物車中是否已有該書,有則更新資料,沒有則插入一條記錄。
dao.CartDAO.java
package dao;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import java.util.HashMap;import entity.Book;import entity.Cart;import util.DBHelper;public class CartDAO {// 判斷是否已有該書 public String isExist(String uid, String isbn){ Connection conn = null; PreparedStatement preStmt = null; ResultSet userSet = null; System.out.println("添加書本"); try{ conn = DBHelper.getConnection();// 判斷商品是否已經存在 String sql = "select * from cart where uid=? and isbn=?"; preStmt = conn.prepareStatement(sql); preStmt.setString(1, uid); preStmt.setString(2, isbn); userSet = preStmt.executeQuery(); if(userSet.next()){ return "true"; } return "false"; }catch(Exception ex){ ex.printStackTrace(); return "error"; }finally{ if(preStmt != null){ try { preStmt.close(); preStmt = null; } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }// 添加商品 public boolean addBook(String uid, String isbn, int num){ Connection conn = null; PreparedStatement preStmt = null; ResultSet userSet = null; System.out.println("添加書本"); try{ conn = DBHelper.getConnection();// 判斷商品是否已經存在 String exist = isExist(uid, isbn); if(exist == "error"){ return false; }if(exist == "false"){ String sql = "insert into cart(uid, isbn, num) values(?, ?, ?)"; preStmt = conn.prepareStatement(sql); preStmt.setInt(3, num); }else if(exist == "true"){ String sql = "update cart set num=num+1 where uid=? and isbn=?"; preStmt = conn.prepareStatement(sql); } preStmt.setString(1, uid); preStmt.setString(2, isbn); int affectedRowNum = preStmt.executeUpdate(); if(affectedRowNum > 0){ return true; } else{ return false; } }catch(Exception ex){ ex.printStackTrace(); return false; }finally{ if(preStmt != null){ try { preStmt.close(); preStmt = null; } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }// 添加一件商品 public boolean addOneBook(String uid, String isbn){ System.out.println("添加一本書"); return addBook(uid, isbn, 1); }// 刪除商品 public boolean deleteBook(String uid, String isbn){ Connection conn = null; PreparedStatement preStmt = null; try{ conn = DBHelper.getConnection(); String sql = "delete from cart where uid=? and isbn=?"; preStmt = conn.prepareStatement(sql); preStmt.setString(1, uid); preStmt.setString(2, isbn); int affectedRowNum = preStmt.executeUpdate(); if(affectedRowNum < 1){ return false; } return true; }catch(Exception ex){ ex.printStackTrace(); return false; }finally{ if(preStmt != null){ try{ preStmt.close(); preStmt = null; }catch(Exception ex){ ex.printStackTrace(); } } } }// 擷取使用者購物車 public Cart getCart(String uid){ Connection conn = null; PreparedStatement preStmt = null; ResultSet bookSet = null; Cart cart = null; try{ conn = DBHelper.getConnection(); String sql = "select B.name, B.isbn, B.price, C.num from book B, Cart C where B.isbn = C.isbn and C.uid = ?"; preStmt = conn.prepareStatement(sql); preStmt.setString(1, uid); bookSet = preStmt.executeQuery(); HashMap<Book, Integer> books = new HashMap<Book, Integer>(); double tolalCost = 0; while(bookSet.next()){ Book book = new Book(); book.setName(bookSet.getString("name")); book.setIsbn(bookSet.getString("isbn")); float price = bookSet.getFloat("price"); book.setPrice(price); int num = Integer.parseInt(bookSet.getString("num")); books.put(book, num); tolalCost += price * num; } cart = new Cart(); cart.setBooks(books); cart.setTotalCost(tolalCost); return cart; }catch(Exception ex){ ex.printStackTrace(); return null; }finally{ if(bookSet != null){ try{ bookSet.close(); bookSet = null; }catch(Exception ex){ ex.printStackTrace(); } } if(preStmt != null){ try{ preStmt.close(); preStmt = null; }catch(Exception ex){ ex.printStackTrace(); } } } }}
添加商品
前端修改與ajax請求
我們點擊[Add To Cart]按鈕,網頁會通過ajax非同步請求伺服器,然後根據伺服器返回的資料以模態框的方式顯示提示資訊(成功與否)。為了滿足這個功能,我們需要修改index.jsp代碼,之前的代碼另存新檔了index-before.jsp。
<%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%><%@ page import="entity.Book" %><%@ page import="dao.BookDAO" %><%@ include file="header.jsp" %> <div class="main"> <!-- 模態框(Modal) --> <div class="modal fade" id="addAlert" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true"> <div class="modal-dialog modal-sm"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> <h4 class="modal-title" id="myModalLabel">提示</h4> </div> <div class="modal-body" id="addAlert-content">操作錯誤</div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">關閉</button> </div> </div><!-- /.modal-content --> </div><!-- /.modal-dialog --> </div> <div class="container-fluid"> <div class="row"> <%-- 通過BookDao擷取資料庫中的書籍資料 --%> <% BookDAO bookDao = new BookDAO(); ArrayList<Book> books = bookDao.getAllBooks(); if(books != null && books.size() > 0){ for(Book book:books){ %> <div class="book-box col-md-3 col-sm-6"> <div class="book"> <a href="single.jsp?isbn=<%= book.getIsbn() %>"><img src="img/<%= book.getImg() %>"/></a> <p class="book-name">《<%= book.getName() %>》</p> <p class="book-intro"><%= book.getIntro() %></p> <div class="add-button"> <span class="cost">¥<%= book.getPrice() %></span> / <span class="cost-original">¥<%= book.getPrice_original() %></span> <button class="add-btn" data-book-isbn="<%= book.getIsbn() %>">Add To Cart</button> </div> </div> </div> <% } } %> </div> </div> </div><%@ include file="footer.jsp" %>
除了添加一個模態框,按鈕的修改非常的重要。該按鈕中通過data存入了對應書本的isbn。
<button class="add-btn" data-book-isbn="<%= book.getIsbn() %>">Add To Cart</button>
如下為點擊按鈕時非同步請求伺服器的代碼。這裡和其他所有的ajax非同步編程都是一樣的。注意提交的路徑為:/SimpleShop/cart。在我們提交的資料中,包含兩個欄位,分別是isbn和操作類型的action,這裡不同提交uid,uid可以在session中獲得。.modal是bootstrap架構模態框的方法,這裡是將id為addAlert的模態框顯示出來。這時候應該思考的是:後台如何返回資料呢。
// 添加書本到購物車$(".add-btn").click(function(){ var isbn = $(this).data("book-isbn"); $.ajax({ url: "/SimpleShop/cart", type: "GET", dataType:"json", data: { isbn: isbn, action: "add" }, success: function(result){ $('#addAlert-content').text(result.message); $('#addAlert').modal('show'); }, error: function(result){ $('#addAlert-content').text(result.message); $('#addAlert').modal('show'); } });});
Servlet處理請求輸出,通過PrintWriter返回給ajax
這裡對於前端的非同步請求,只需要將資料通過PrintWriter通過流的方式將資料返回即可。程式碼片段格式如下。print中的內容是按照json的格式返回,以返回一個物件類型給前端。由於點擊一次增加一本書,所以只要調用CartDAO的addOneBook方法即可,對於刪除,我們只要調用deleteBook方法即可。是不是覺得封裝了CartDAO,之後寫代碼就方便了很多呢。
// 確保返回的資料不亂碼response.setCharacterEncoding("utf-8");PrintWriter out = response.getWriter();if(user == null){// 尚未登入// 以json格式返回 out.print("{\"err\":\"error\",\"message\":\"您尚未登入\"}"); out.flush(); out.close(); return;}
servlet.Cart.java
package servlet;import java.io.IOException;import java.io.PrintWriter;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 dao.CartDAO;import entity.User;/** * Servlet implementation class Cart */@WebServlet("/cart")public class Cart extends HttpServlet { private static final long serialVersionUID = 1L; /** * @see HttpServlet#HttpServlet() */ public Cart() { super(); // TODO Auto-generated constructor stub } /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { User user = (User)request.getSession().getAttribute("user");// 確保返回的資料不亂碼 response.setCharacterEncoding("utf-8"); PrintWriter out = response.getWriter(); if(user == null){// 尚未登入 out.print("{\"err\":\"error\",\"message\":\"您尚未登入\"}"); out.flush(); out.close(); return; } String isbn = request.getParameter("isbn"); String action = request.getParameter("action"); String uid = user.getUid(); if(action.equals("add")){ CartDAO cartdao = new CartDAO(); if(cartdao.addOneBook(uid, isbn)){ out.print("{\"message\":\"添加成功\"}"); }else{ out.print("{\"message\":\"添加失敗\"}"); } }else if(action.equals("delete")){ CartDAO cartdao = new CartDAO(); if(cartdao.deleteBook(uid, isbn)){ out.print("{\"err\":\"success\",\"message\":\"刪除成功\"}"); }else{ out.print("{\"err\":\"fail\",\"message\":\"刪除失敗\"}"); } } out.flush(); out.close();// 不存在操作 } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub doGet(request, response); }}
顯示購車
購物車的商品只有在使用者登入只有才會展示,所以這裡也需要利用session中的user判斷使用者是否已經登入了,並根據不同的狀態做出不同的處理。由於HashMap無法進行遍曆,所以這裡需要先取出其中的key值的Set集合,遍曆該集合在利用get方法來實現對HashMap的遍曆。這裡注意delete上的資料,由於我們也需要用到ajax來實現刪除,所以為了方便操作需要用data儲存isbn,同時因為刪除一本書之後,總價需要更新,減所以這裡也用data儲存了每種書需要的總花費,這樣只要擷取下來一減就可以了。
cart.jsp
<%@ page language="java" import="java.util.*" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%><%@ page import="dao.CartDAO" %><%@ page import="entity.*" %><%@ include file="header.jsp" %> <div class="main main-white"> <!-- 模態框(Modal) --> <div class="modal fade" id="deleteAlert" tabindex="-1"