[TOC]

day11 书城项目第四阶段

第一章 添加商品进购物车

1 创建购物车模型

day11_书城项目第四阶段 - 图1

1.1 购物项详情类

day11_书城项目第四阶段 - 图2

public class CartItem {
package com.atguigu.bean;

/
包名:com.atguigu.bean

@author Chunsheng Zhang
日期2021-05-17 09:06
*/
public class CartItem {
private Integer bookId;
private String bookName;
private String imgPath;
/

商品的单价
/
private Double price;
private Integer count;
/*
购物项的金额
*/
private Double amount;

public CartItem() {<br />    }

@Override<br />    public String toString() {<br />        return "CartItem{" +<br />                "bookId=" + bookId +<br />                ", bookName='" + bookName + '\'' +<br />                ", imgPath='" + imgPath + '\'' +<br />                ", price=" + price +<br />                ", count=" + count +<br />                ", amount=" + amount +<br />                '}';<br />    }

public CartItem(Integer bookId, String bookName, String imgPath, Double price, Integer count, Double amount) {<br />        this.bookId = bookId;<br />        this.bookName = bookName;<br />        this.imgPath = imgPath;<br />        this.price = price;<br />        this.count = count;<br />        this.amount = amount;<br />    }

public Integer getBookId() {<br />        return bookId;<br />    }

public void setBookId(Integer bookId) {<br />        this.bookId = bookId;<br />    }

public String getBookName() {<br />        return bookName;<br />    }

public void setBookName(String bookName) {<br />        this.bookName = bookName;<br />    }

public String getImgPath() {<br />        return imgPath;<br />    }

public void setImgPath(String imgPath) {<br />        this.imgPath = imgPath;<br />    }

public Double getPrice() {<br />        return price;<br />    }

public void setPrice(Double price) {<br />        this.price = price;<br />    }

public Integer getCount() {<br />        return count;<br />    }

public void setCount(Integer count) {<br />        this.count = count;<br />    }

/**<br />     * 这个方法获取总价:要通过计算才能获取<br />     * @return<br />     */<br />    public Double getAmount() {<br />        return this.price*this.count;<br />    }

public void setAmount(Double amount) {<br />        this.amount = amount;<br />    }

/**<br />     * 数量+1<br />     */<br />    public void countIncrease(){<br />        this.count ++;<br />    }

/**<br />     * 数量-1<br />     */<br />    public void countDecrease(){<br />        this.count --;<br />    }<br />}

1.2 购物车类:Cart

package com.atguigu.bean;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

/
包名:com.atguigu.bean

@author Chunsheng Zhang
日期2021-05-17 09:09
*/
public class Cart {
/

存储购物车中的购物项
以购物项中的书的ID作为key,以购物项作为value
*/
private Map cartItemMap = new HashMap<>();

/**<br />     * 将书添加进购物车<br />     * @param book<br />     */<br />    public void addBookToCart(Book book){<br />        //1. 判断购物车中是否已经有这件商品<br />        if (cartItemMap.containsKey(book.getBookId())) {<br />            //2. 如果购物车中已经有这件商品了,那么就对其数量+1<br />            itemCountIncrease(book.getBookId());<br />        }else {<br />            //3. 如果购物车中还没有这件商品,那么我们就新增一个购物项<br />            //第一次添加商品进购物车,那么数量count肯定是1,那么总价就是单价<br />            CartItem cartItem = new CartItem(book.getBookId(),book.getBookName(),book.getImgPath(),book.getPrice(),1,book.getPrice());<br />            cartItemMap.put(cartItem.getBookId(),cartItem);<br />        }<br />    }

@Override<br />    public String toString() {<br />        return "Cart{" +<br />            "cartItemMap=" + cartItemMap +<br />            '}';<br />    }

/**<br />     * 显示购物车信息,为了在Thymeleaf中便于使用OGNL表达式获取购物车的信息,<br />     * 我们的方法名要叫作getCartItemMap(),那么我们在Thymeleaf中就可以使用 .cartItemMap获取<br />     * @return<br />     */<br />    public Map<Integer,CartItem> getCartItemMap(){<br />        return cartItemMap;<br />    }

/**<br />     * 将购物车中的某个购物项的数量+1<br />     * @param bookId<br />     */<br />    public void itemCountIncrease(Integer bookId){<br />        cartItemMap.get(bookId).countIncrease();<br />    }

/**<br />     * 将购物车中的某个购物项的数量-1<br />     * @param bookId<br />     */<br />    public void itemCountDecrease(Integer bookId){<br />        CartItem cartItem = cartItemMap.get(bookId);<br />        //1.先将当前购物项的数量-1<br />        cartItem.countDecrease();<br />        //2.判断当前购物项的count是否等于0<br />        if (cartItem.getCount() == 0) {<br />            //说明要将当前购物项从购物车中移除<br />            removeCartItem(bookId);<br />        }<br />    }

/**<br />     * 从购物车中移除购物项<br />     * @param bookId<br />     */<br />    public void removeCartItem(Integer bookId){<br />        cartItemMap.remove(bookId);<br />    }

/**<br />     * 修改某个购物项的数量<br />     * @param bookId<br />     */<br />    public void updateItemCount(Integer bookId,Integer newCount){<br />        cartItemMap.get(bookId).setCount(newCount);<br />    }

/**<br />     * 获取购物车中的购物项中的商品的总数<br />     * 就是将所有购物项的count进行累加<br />     * @return<br />     */<br />    public Integer getTotalCount(){<br />        //遍历出每一个CartItem的count然后累加<br />        //方式一: 采用JDK1.8的新特性<br />        /*AtomicReference<Integer> totalCount = new AtomicReference<>(0);<br />        cartItemMap.forEach((k,cartItem) -> {<br />            totalCount.updateAndGet(v -> v + cartItem.getCount());<br />        });

    return totalCount.get();*/

    //方式二: 使用原生的entrySet遍历Map<br />        Integer totalCount = 0;<br />        for (Map.Entry<Integer, CartItem> cartItemEntry : cartItemMap.entrySet()) {<br />            totalCount += cartItemEntry.getValue().getCount();<br />        }<br />        return totalCount;<br />    }

/**<br />     * 获取总金额<br />     * 就是遍历出每个购物项的金额再累加<br />     * @return<br />     */<br />    public Double getTotalAmount(){<br />        //解决精度问题的核心: 就是将要进行运算的数据转成BigDecimal类型之后再计算<br />        //声明一个总金额<br />        Double totalAmount = 0.0;<br />        for (Map.Entry<Integer, CartItem> cartItemEntry : cartItemMap.entrySet()) {<br />            //cartItemEntry.getValue().getAmount()是获取每一个购物项的金额

        //使用总金额加上遍历出来的购物项的金额<br />            totalAmount += cartItemEntry.getValue().getAmount();<br />        }<br />        return totalAmount;<br />    }<br />}

2. 目标

在首页点击『加入购物车』将该条图书加入『购物车』

3. 思路

首页→加入购物车→CartServlet.addCartItem()→执行添加操作→回到首页

4. 代码实现

4.1 创建CartServlet

day11_书城项目第四阶段 - 图3

public class CartServlet extends ModelBaseServlet {
private BookService bookService = new BookServiceImpl();
/*
添加商品进购物车
@param request
@param response
*/
public void addCartItem(HttpServletRequest request, HttpServletResponse response){
try {
//1. 获取请求参数id的值
Integer id = Integer.valueOf(request.getParameter(“id”));
//2. 调用bookService的方法根据id查询book信息
Book book = bookService.getBookById(id);
//3. 尝试从会话域中获取购物车
HttpSession session = request.getSession();
Cart cart = (Cart) session.getAttribute(“cart”);
//4. 判断之前是否已经添加过购物车了
if (cart == null) {
//说明这是第一次添加购物车
//那么就要新创建一个购物车对象
cart = new Cart();
//然后将当前book加入到这个购物车
cart.addBookToCart(book);
//然后将cart存入到session
session.setAttribute(“cart”,cart);
}else {
//说明不是第一次添加购物车
//那么就直接用之前的购物车,添加当前book就行
cart.addBookToCart(book);
}

        //跳转到首页<br />            response.sendRedirect(request.getContextPath()+"/index.html");<br />        } catch (Exception e) {<br />            e.printStackTrace();<br />        }<br />    }<br />}

4.2 index.html页面

购物车数量显示:



注册
href=”#”
class=”cart iconfont icon-gouwuche

>
购物车
3


后台管理



欢迎你张总
注销
href=”#”
class=”cart iconfont icon-gouwuche
“>
购物车
3


后台管理

加入购物车:
加入购物车

4.3 CSS样式

day11_书城项目第四阶段 - 图4

.books-list .list-content .list-item a {
display: block;
width: 80px;
height: 30px;
border: none;
line-height: 30px;
background-color: #39987c;
margin-top: 5px;
outline: none;
color: #fff;
cursor:pointer;
font-size:12px;
text-align:center;
}
如果修改完成后页面效果没有改变,可以使用Ctrl+F5强制刷新。

第二章 显示购物车页面

1目标

把购物车信息在专门的页面显示出来

2思路

首页→购物车超链接→CartServlet.showCart()→cart.html

3代码实现

3.1 购物车超链接

登录状态和未登录状态



注册
href=”cart?method=toCartPage”
class=”cart iconfont icon-gouwuche

>
购物车
3


后台管理



欢迎你张总
注销
href=”cart?method=toCartPage”
class=”cart iconfont icon-gouwuche
“>
购物车
3


后台管理

3.2 CartServlet

/*
跳转到显示购物车列表的页面
@param request
@param response
*/
public void toCartPage(HttpServletRequest request,HttpServletResponse response) throws IOException {
processTemplate(“cart/cart”,request,response);
}

3.3 cart.html





        <th>数量</th><br />            <th>单价</th><br />            <th>金额</th><br />            <th>操作</th><br />        </tr><br />    </thead><br />    <tbody th:if="${session.cart == null}"><br />        <tr><br />            <td th:colspan="6"><br />                <a href="index.html">购物车空空如也,请抓紧购物吧!!!!</a><br />            </td><br />        </tr><br />    </tbody><br />    <tbody th:if="${session.cart != null}"><br />        <tr th:each="cartItemEntry : ${session.cart.cartItemMap}"><br />            <td><br />                <img th:src="${cartItemEntry.value.imgPath}" alt="" /><br />            </td><br />            <td th:text="${cartItemEntry.value.bookName}">活着</td><br />            <td><br />                <a class="count" th:href="#">-</a><br />                <input class="count-num" type="text" th:value="${cartItemEntry.value.count}" value="1" /><br />                <input type="hidden" th:value="${cartItemEntry.value.bookId}"/><br />                <a class="count" th:href="#">+</a><br />            </td><br />            <td th:text="${cartItemEntry.value.price}">36.8</td><br />            <td th:text="${cartItemEntry.value.amount}">36.8</td><br />            <td><a th:href="#">删除</a></td><br />        </tr><br />    </tbody><br /></table><br /><div><br />    <div class="footer" th:if="${session.cart != null}"><br />        <div class="footer-left"><br />            <a href="#" class="clear-cart">清空购物车</a><br />            <a href="#">继续购物</a><br />        </div><br />        <div class="footer-right"><br />            <div>共<span th:text="${session.cart.totalCount}">3</span>件商品</div><br />            <div class="total-price">总金额<span th:text="${session.cart.totalAmount}">99.9</span>元</div><br />            <a class="pay" href="pages/cart/checkout.html">去结账</a><br />        </div><br />    </div><br /></div>

第三章 清空购物车

1 目标

当用户确定点击清空购物车,将Session域中的Cart对象移除。

2 思路

cart.html→清空购物车超链接→绑定单击响应函数→confirm()确认→确定→CartServlet.clearCart()→从Session域移除Cart对象

3 代码实现

3.1 清空购物车超链接



清空购物车

3.2 CartServlet.cleanCart()

/*
清空购物车
@param request
@param response
@throws IOException
/
public void cleanCart(HttpServletRequest request,HttpServletResponse response) throws IOException {
//就是移除掉session中的cart就行了
request.getSession().removeAttribute(“cart”);
//跳转到购物车展示页面
processTemplate(“cart/cart”,request,response);
}

第四章 减号

1. 目标

  • 在大于1的数值基础上-1:执行-1的逻辑
  • 在1的基础上-1:执行删除item的逻辑

2. 思路

减号a标签绑定单击响应函数→获取文本框中的数据:当前数量→检查数量是否等于1,如果它等于1的话,则弹出一个确认框,询问其是否想删除?如果不想删除,则阻止a标签的事件

3. 后端代码

CartServlet.countDecrease()方法
/*
购物车中某个一个购物项的数量-1
@param request
@param response
@throws IOException
/
public void countDecrease(HttpServletRequest request,HttpServletResponse response) throws IOException {
//1. 获取到要-1的书的id
Integer id = Integer.valueOf(request.getParameter(“id”));
//2. 从session中获取购物车信息
Cart cart = (Cart) request.getSession().getAttribute(“cart”);
//3. 调用购物车的-1方法
cart.itemCountDecrease(id);
//4. 跳转回到购物车页面
processTemplate(“cart/cart”,request,response);
}

4. 前端代码

HTML代码给“减号”设置访问路径以及绑定点击事件:
需要注意:只能使用onclick绑定不能使用Vue绑定(通过实践得出的)
-
js代码:

第四章 删除

1. 目标

点击删除超链接后,把对应的CartItem从Cart中删除

2. 思路

cart.html→删除超链接→CartServlet.removeCartItem()→回到cart.html
需要注意:删除之前要确认

3. 代码实现

3.1 后端代码

CartServlet.removeCartItem()
/*
删除购物项
@param request
@param response
@throws IOException
/
public void removeCartItem(HttpServletRequest request,HttpServletResponse response) throws IOException {
//1. 获取要删除的购物项的书的id
Integer id = Integer.valueOf(request.getParameter(“id”));
//2.从session中获取购物车
Cart cart = (Cart) request.getSession().getAttribute(“cart”);
//3. 调用cart的删除购物项的方法
cart.removeCartItem(id);
//4. 跳转回到购物车页面
processTemplate(“cart/cart”,request,response);
}

3.2 前端代码

HTML代码:


Vue代码:
var vue = new Vue({
“el”:”#app”,
“methods”:{

    deleteCartItem(){<br />            //想办法使用JavaScript获取要删除的购物项的书名<br />            //event.target就表示获取当前事件的标签<br />            var bookName = event.target.parentElement.parentElement.getElementsByTagName("td")[1].innerText;<br />            if (!confirm("你确定要删除这个"+bookName+"吗?")) {<br />                event.preventDefault()<br />            }<br />        }<br />    }<br />});

第五章 文本框修改

1. 目标

用户在文本框输入新数据后,根据用户输入在Session中的Cart中修改CartItem中的count

2. 思路

cart.html→前端数据校验→CartServlet.updateCartItemCount()→回到cart.html

3. 代码实现

3.1 后端代码

CartServlet.updateCartItemCount()
/*
修改购物项的数量
@param request
@param response
@throws IOException
/
public void updateCartItemCount(HttpServletRequest request,HttpServletResponse response) throws IOException {
//1. 获取请求参数:id,newCount
Integer id = Integer.valueOf(request.getParameter(“id”));
Integer newCount = Integer.valueOf(request.getParameter(“newCount”));
//2. 从session中获取购物车信息
Cart cart = (Cart) request.getSession().getAttribute(“cart”);
//3. 调用cart中跟新数量的方法
cart.updateItemCount(id,newCount);

//4. 跳转到购物车页面<br />    processTemplate("cart/cart",request,response);<br />}

3.2 前端代码

HTML代码:


Vue代码:
var vue = new Vue({
“el”:”#app”,
“methods”:{
updateCartItemCount(){
//获取bookId
var bookId = event.target.nextElementSibling.value;
//获取newCount
var newCount = event.target.value;

        //校验newCount的格式是否正确<br />            var reg = /^[1-9][0-9]*$/

        if (reg.test(newCount)) {<br />                //发送请求携带请求参数<br />                location.href = "cart?method=updateCartItemCount&id="+bookId+"&newCount="+newCount

        }else {<br />                alert("请输入正确的数量")<br />            }<br />        }<br />    }<br />});

第六章 加号

1. 目标

告诉Servlet将Session域中Cart对象里面对应的CartItem执行count+1操作

2. 思路

加号span绑定单击响应函数→获取文本框中的数据:当前数量→CartServlet.countIncrease()→回到cart.html

3. 代码实现

3.1 后端代码

CartServlet.countIncrease()
/*
购物车中某个一个购物项的数量+1
@param request
@param response
@throws IOException
/
public void countIncrease(HttpServletRequest request,HttpServletResponse response) throws IOException {
//1. 获取到要-+1的书的id
Integer id = Integer.valueOf(request.getParameter(“id”));
//2. 从session中获取购物车信息
Cart cart = (Cart) request.getSession().getAttribute(“cart”);
//3. 调用购物车的+1方法
cart.itemCountIncrease(id);
//4. 跳转回到购物车页面
processTemplate(“cart/cart”,request,response);
}

3.2 前端代码

HTML代码:
+

第七章 Double数据运算过程中精度调整

1. 问题现象

day11_书城项目第四阶段 - 图5

2. 解决方案

  • 使用BigDecimal类型来进行Double类型数据运算
  • 创建BigDecimal类型对象时将Double类型的数据转换为字符串

Cart类:
/*
获取总金额
@return
/
public Double getTotalAmount(){
//解决精度问题的核心: 就是将要进行运算的数据转成BigDecimal类型之后再计算
//声明一个总金额
BigDecimal bigDecimalTotalAmount = new BigDecimal(“0.0”);
for (Map.Entry cartItemEntry : cartItemMap.entrySet()) {
//cartItemEntry.getValue().getAmount()是获取每一个购物项的金额

    //使用总金额加上遍历出来的购物项的金额<br />        bigDecimalTotalAmount = bigDecimalTotalAmount.add(new BigDecimal(cartItemEntry.getValue().getAmount() + ""));<br />    }<br />    return bigDecimalTotalAmount.doubleValue();<br />}<br />CartItem类:<br />/**<br />     * 这个方法获取总价:要通过计算才能获取<br />     * @return<br />     */<br />public Double getAmount() {<br />    //1. 将price和count封装成BigDecimal类型<br />    BigDecimal bigDecimalPrice = new BigDecimal(price + "");<br />    BigDecimal bigDecimalCount = new BigDecimal(count + "");

//2. 使用bigDecimal的方法进行乘法<br />    return bigDecimalCount.multiply(bigDecimalPrice).doubleValue();<br />}
图片 商品名称 删除