购物车类及购物车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" 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="deleteAlert-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">
<div class="col-md-6 col-md-offset-3 col-sm-8 col-sm-offset-2">
<%
User user = (User)session.getAttribute("user");
if(user == null){
// 未登录
%>
<div class="withoutlogin-area">
<p>您尚未登录,登录后将显示您购物车中商品</p>
</div>
<%
}else{
%>
<div class="table-responsive table-shadow">
<table class="table table-striped">
<thead>
<tr>
<th></th>
<th>商品名</th>
<th>单价(元)</th>
<th>数量</th>
<th>金额</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<%
String uid = user.getUid();
CartDAO cartdao = new CartDAO();
Cart cart = cartdao.getCart(uid);
HashMap<Book,Integer> books = cart.getBooks();
Set<Book> bookSet = books.keySet();
Iterator<Book> it = bookSet.iterator();
double totalPrice = 0;
while(it.hasNext())
{
Book book = it.next();
double cost = cart.getOneTypeBookCostInCart(book);
totalPrice += cost;
%>
<tr>
<td><input type="checkbox" /></td>
<td>《<%= book.getName() %>》</td>
<td><%= String.format("%.2f",book.getPrice()) %></td>
<td><%=books.get(book) %></td>
<td><%= String.format("%.2f",cost)%></td>
<td><a href="javascript:void(0)" class="delete" data-cost="<%= cost %>" data-book-isbn="<%=book.getIsbn() %>">删除</a></td>
</tr>
<%
}
%>
</tbody>
</table>
</div>
<div class="divider divider-light"></div>
<div class="amount">
<div class="tag-left">
<input class="allchose" type="checkbox" />全选
</div>
<div class="tag-right">
总计:¥<span class="amount-cost"><%= String.format("%.2f",totalPrice) %></span><button type="submit" class="btn">提交订单</button>
</div>
</div>
<%
}
%>
</div>
</div>
</div>
</div>
<%@ include file="footer.jsp" %>
删除商品
ajax实现
$(".delete").click(function(){
var isbn = $(this).data("book-isbn");
var cost = $(this).data("cost");
var $tr = $(this).closest("tr");
$.ajax({
url: "/SimpleShop/cart",
type: "GET",
dataType:"json",
data: {
isbn: isbn,
action: "delete"
},
success: function(result){
$('#deleteAlert-content').text(result.message);
$('#deleteAlert').modal('show');
if(result.err == "success"){
$tr.fadeOut();
$(".amount-cost").text(($(".amount-cost").text() - cost).toFixed(2));
}
},
error: function(result){
$('#deleteAlert-content').text(result.message);
$('#deleteAlert').modal('show');
}
});
});
Servlet处理请求输出,通过PrintWriter返回给ajax
只需要调用CartDAO
中的deleteBook
方法即可。具体实现见上面的商品添加。