15、书城项目第四阶段

232 阅读8分钟

15、书城项目第四阶段

一、保持登录状态

1、创建module

  • 迁移src目录下的Java代码
  • 迁移web目录下的static目录
  • 迁移web/WEB-INF目录下的lib目录和pages目录
  • 将lib目录下的jar包添加到运行时环境
  • 将旧的web.xml中的配置复制到新module的web.xml中

2、将登录成功的User对象存入会话域

ace17d7d95824211ad15cd985882dcfe.png

protected void doLogin(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    // 1.从请求参数中获取用户名和密码
    String username = request.getParameter("username");
    String password = request.getParameter("password");

    // 2.封装为User对象
    User userForm = new User(null, username, password, null);

    // 3.调用UserService的方法执行登录验证
    try {
        User userDB = userService.doLogin(userForm);

        // ※保持登录状态,将User对象存入会话域
        HttpSession session = request.getSession();

        // 注意:不要放错,这里要使用从数据库查询得到的User对象
        session.setAttribute("user", userDB);

        // 4.登录成功后跳转到登录成功页面
        response.sendRedirect(request.getContextPath() + "/UserServlet?method=toLoginSuccessPage");
    } catch (Exception e) {
        e.printStackTrace();

        // 5.登录失败则显示提示消息
        // ①将登录失败的提示消息存入请求域
        request.setAttribute("message", e.getMessage());

        // ②执行登录页面的模板渲染
        String viewName = "user/login";

        processTemplate(viewName, request, response);
    }

}

3、修改欢迎信息

①登录成功页面

<span>欢迎<span class="um_span" th:text="${session.user.username}">张总</span>光临尚硅谷书城</span>

②首页

<div class="topbar-right" th:if="${session.user == null}">
    <a href="UserServlet?method=toLoginPage" class="login">登录</a>
    <a href="UserServlet?method=toRegisterPage" class="register">注册</a>
    <a href="pages/cart/cart.html" class="cart iconfont icon-gouwuche">
        购物车
        <div class="cart-num">3</div>
    </a>
    <a href="AdminServlet?method=toPortalPage" class="admin">后台管理</a>
</div>
<!--          登录后风格-->
<div class="topbar-right" th:if="${session.user != null}">
    <span>欢迎你<b th:text="${session.user.userName}">张总</b></span>
    <a href="#" class="register">注销</a>
    <a href="pages/cart/cart.jsp" class="cart iconfont icon-gouwuche">
        购物车
        <div class="cart-num">3</div>
    </a>
    <a href="pages/manager/book_manager.html" class="admin">后台管理</a>
</div>

4、退出登录功能

①页面超链接

<a href="UserServlet?method=logout">注销</a>

②UserServlet.logout()

protected void logout(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    HttpSession session = request.getSession();

    // 退出登录方案一:从会话域移除User对象
    // session.removeAttribute("user");

    // 退出登录方案二:强制Session对象失效
    session.invalidate();

    processTemplate("index", request, response);
}

二、验证码

1、目标

通过让用户填写验证码并在服务器端检查,防止浏览器端使用程序恶意访问。

2、思路

c998281dbb304726a009a3b75a539cc1.png

3、操作

①导入jar包

kaptcha-2.3.2.jar

②配置KaptchaServlet

jar包中已经写好了Servlet的Java类,我们只需要在web.xml中配置这个Servlet即可。

<servlet>
    <servlet-name>KaptchaServlet</servlet-name>
    <servlet-class>com.google.code.kaptcha.servlet.KaptchaServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>KaptchaServlet</servlet-name>
    <url-pattern>/KaptchaServlet</url-pattern>
</servlet-mapping>

③通过页面访问测试

http://localhost:8080/bookstore/KaptchaServlet

④在注册页面显示验证码图片

7185f881df524e1db581720b629fa532.png

<img src="KaptchaServlet" alt="" />

⑤调整验证码图片的显示效果

[1]去掉边框

KaptchaServlet会在初始化时读取init-param,而它能够识别的init-param在下面类中:

com.google.code.kaptcha.util.Config

web.xml中具体配置如下:

<servlet>
    <servlet-name>KaptchaServlet</servlet-name>
    <servlet-class>com.google.code.kaptcha.servlet.KaptchaServlet</servlet-class>

    <!-- 通过配置初始化参数影响KaptchaServlet的工作方式 -->
    <!-- 可以使用的配置项参考com.google.code.kaptcha.util.Config类 -->
    <!-- 配置kaptcha.border的值为false取消图片边框 -->
    <init-param>
        <param-name>kaptcha.border</param-name>
        <param-value>no</param-value>
    </init-param>
</servlet>
<servlet-mapping>
    <servlet-name>KaptchaServlet</servlet-name>
    <url-pattern>/KaptchaServlet</url-pattern>
</servlet-mapping>

开发过程中的工程化细节:

no、false、none等等单词从含义上来说都表示『没有边框』这个意思,但是这里必须使用no。

参考的依据是下面的源码:

public boolean getBoolean(String paramName, String paramValue, boolean defaultValue) {
    boolean booleanValue;
    if (!"yes".equals(paramValue) && !"".equals(paramValue) && paramValue != null) {
        if (!"no".equals(paramValue)) {
            throw new ConfigException(paramName, paramValue, "Value must be either yes or no.");
        }

        booleanValue = false;
    } else {
        booleanValue = defaultValue;
    }

    return booleanValue;
}
[2]设置图片大小
<img style="width: 150px; height: 40px;" src="KaptchaServlet" alt="" />

⑥点击图片刷新

[1]目的

验证码图片都是经过刻意扭曲、添加了干扰、角度偏转,故意增加了识别的难度。所以必须允许用户在看不出来的时候点击图片刷新,生成新的图片重新辨认。

[2]实现的代码

修改图片的img标签:

<img @click="refreshCodeImage" style="width: 150px; height: 40px;" src="KaptchaServlet" alt="" />

Vue代码:将refreshCodeImage()单击响应函数声明到注册表单验证功能的Vue对象的methods属性中

,
"refreshCodeImage":function () {

    // 通过event事件对象的target属性获取当前正在点击的img标签
    var imgEle = event.target;

    // 设置img标签的src属性
    imgEle.src = "KaptchaServlet?random=" + Math.random();
}

⑦执行注册前检查验证码

156b008292964b5da7c16c9d04b6e5e8.png

[1]确认KaptchaServlet将验证码存入Session域时使用的属性名

dc9fee76dad64e9ebdde780b98278440.png

通过查看源码,找到验证码存入Session域时使用的属性名是:

KAPTCHA_SESSION_KEY

[2]在执行注册的方法中添加新的代码
    protected void doRegister(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        // ※检查验证码
        // 1.从请求参数中获取用户提交的验证码
        String codeForm = request.getParameter("code");

        // 2.获取Session域中保存的验证码
        HttpSession session = request.getSession();
        String codeSystem = (String) session.getAttribute("KAPTCHA_SESSION_KEY");

        // 3.将表单验证码和系统验证码进行比较
        if (Objects.equals(codeForm, codeSystem)) {

            // 4.如果比较后发现二者一致,则将用过的验证码从Session域移除
            session.removeAttribute("KAPTCHA_SESSION_KEY");

        }else{

            // 5.如果比较后发现二者不一致,则返回注册的表单页面显示提示信息
            request.setAttribute("message", "验证码不正确,请重新填写");

            String viewName = "user/regist";

            processTemplate(viewName, request, response);

            // 6.停止执行当前方法
            return ;
        }

        // 后续是原来的代码……

三、购物车

1、功能清单

  • 添加购物车
  • 显示购物车信息
  • 修改购物车中具体商品的数量
  • 删除购物车中某个具体商品
  • 清空购物车

2、创建购物车模型

2d3ecb34108b42f9a6af8ed0cb82d4c5.png

①购物车详情类:CartItem

a27aeb3101ec4b8387f829fd1f294904.png

public class CartItem {

    private String bookId;
    private String bookName;
    private String imgPath;
    private Double price;
    private Integer count;
    private Double amount;

    // 获取金额时需要计算得到
    public Double getAmount() {
        return this.count * this.price;
    }

②购物车类:Cart

public class Cart {

    private Map<String, CartItem> cartItemMap = new HashMap<>();

    // 添加购物车
    public void addCartItem(Book book) {

        // 1.获取当前Book对象的id值
        String bookId = book.getBookId() + "";

        // 2.根据id值到Map中检查是否已存在
        if (cartItemMap.containsKey(bookId)) {
            // 3.如果存在,则给原有的CartItem增加数量
            CartItem cartItem = cartItemMap.get(bookId);

            int newCount = cartItem.getCount() + 1;

            cartItem.setCount(newCount);
        } else {
            // 4.如果不存在,则创建新的CartItem对象
            CartItem cartItem = new CartItem();
            cartItem.setBookId(bookId);
            cartItem.setBookName(book.getBookName());
            cartItem.setCount(1);
            cartItem.setImgPath(book.getImgPath());
            cartItem.setPrice(book.getPrice());

            // 5.将新的CartItem对象存入cartItemMap
            cartItemMap.put(bookId, cartItem);
        }

    }

    // 从购物车中删除CartItem
    public void removeCartItem(String bookId) {

        cartItemMap.remove(bookId);

    }

    // 把某个CartItem的数量修改为指定值
    public void updateItemCount(String bookId, Integer newCount) {

        // 根据bookId从Map中获取对应的CartItem对象
        CartItem cartItem = cartItemMap.get(bookId);

        // 设置新的数量值
        cartItem.setCount(newCount);

    }

    // 把某个CartItem的数量+1
    public void itemCountIncrease(String bookId) {

        CartItem cartItem = cartItemMap.get(bookId);

        cartItem.setCount(cartItem.getCount() + 1);

    }

    // 把某个CartItem的数量-1
    public void itemCountDecrease(String bookId) {

        CartItem cartItem = cartItemMap.get(bookId);

        cartItem.setCount(cartItem.getCount() - 1);

        if (cartItem.getCount() == 0) {
            removeCartItem(bookId);
        }
    }

    public Map<String, CartItem> getCartItemMap() {
        return cartItemMap;
    }

    // 计算总数量
    public Integer getTotalCount() {

        // 1.声明一个变量用于存储累加结果
        Integer sum = 0;

        // 2.遍历Map集合
        Set<String> keySet = cartItemMap.keySet();

        for (String key : keySet) {
            CartItem cartItem = cartItemMap.get(key);
            Integer count = cartItem.getCount();
            sum = sum + count;
        }

        // 3.返回累加结果
        return sum;
    }

    // 计算总金额
    public Double getTotalAmount() {

        // 1.声明一个变量用于存储累加结果
        Double sum = 0.0;

        // 2.遍历Map集合
        Set<String> keySet = cartItemMap.keySet();

        for (String key : keySet) {
            CartItem cartItem = cartItemMap.get(key);
            Double amount = cartItem.getAmount();

            sum = sum + amount;
        }

        // 3.返回累加结果
        return sum;

    }
}

3、添加购物车功能

①目标

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

②思路

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

③代码实现

[1]创建CartServlet

6f55d71d03b94bbdb0c48b4315621595.png

public class CartServlet extends ModelBaseServlet {

    private BookService bookService = new BookServiceImpl();

    protected void addCart(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        // 1.从请求参数中获取bookId
        String bookId = request.getParameter("bookId");

        // 2.根据bookId查询图书数据
        Book book = bookService.getBookById(bookId);

        // 3.获取Session对象
        HttpSession session = request.getSession();

        // 4.尝试从Session域获取购物车对象
        Cart cart = (Cart) session.getAttribute("cart");

        // 5.判断Cart对象是否存在
        if (cart == null) {

            // 6.如果不存在,则创建新的Cart对象
            cart = new Cart();

            // 7.将新创建的Cart对象存入Session域
            session.setAttribute("cart", cart);
        }

        // 8.添加购物车
        cart.addCartItem(book);

        // 9.回首页
        response.sendRedirect(request.getContextPath() + "/index.html");
    }

}
[2]index.html页面

购物车数量显示:

<!--          登录后风格-->
<div class="topbar-right" th:if="${session.user != null}">
    <span>欢迎你<b th:text="${session.user.userName}">张总</b></span>
    <a href="#" class="register">注销</a>
    <a href="pages/cart/cart.jsp" class="cart iconfont icon-gouwuche">
        购物车
        <div class="cart-num" th:if="${session.cart != null}" th:text="${session.cart.totalCount}">3</div>
    </a>
    <a href="pages/manager/book_manager.html" class="admin">后台管理</a>
</div>

加入购物车:

<div class="list-content" th:if="${not #lists.isEmpty(bookList)}">
    <div class="list-item" th:each="book : ${bookList}">
        <img th:src="${book.imgPath}" src="static/uploads/huozhe.jpg" alt="">
        <p>书名:<span th:text="${book.bookName}">活着</span></p>
        <p>作者:<span th:text="${book.author}">余华</span></p>
        <p>价格:¥<span th:text="${book.price}">66.6</span></p>
        <p>销量:<span th:text="${book.sales}">230</span></p>
        <p>库存:<span th:text="${book.stock}">1000</span></p>
        <!--<button>加入购物车</button>-->
        <a th:href="@{/CartServlet(method=addCart,bookId=${book.bookId})}">加入购物车</a>
    </div>
</div>

④CSS样式

e4d19601081844249cb4ae4cd8b50e19.png

.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强制刷新。

4、显示购物车页面

①目标

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

②思路

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

③代码实现

[1]购物车超链接

登录状态和未登录状态

<a href="CartServlet?method=showCart" class="cart iconfont icon-gouwuche">购物车</a>
[2]CartServlet
protected void showCart(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    String viewName = "cart/cart";

    processTemplate(viewName, request, response);

}
[3]cart.html
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <base th:href="@{/}"/>
    ……
    <div class="header-right" th:include="segment/welcome :: welcome-page"></div>
    ……
    <tbody th:if="${session.cart == null || session.cart.cartItemMap.size() == 0}">
        <tr>
            <td colspan="6">购物车还是空空的,赶紧去添加吧!</td>
        </tr>
    </tbody>
    <tbody th:if="${session.cart != null && session.cart.cartItemMap.size() > 0}">
    <tr th:each="cartItemEntry : ${session.cart.cartItemMap}">
        <td>
            <img th:src="${cartItemEntry.value.imgPath}" src="static/uploads/huozhe.jpg" alt=""/>
        </td>
        <td th:text="${cartItemEntry.value.bookName}">活着</td>
        <td>
            <span class="count">-</span>
            <input class="count-num" type="text" th:value="${cartItemEntry.value.count}" value="1"/>
            <span class="count">+</span>
        </td>
        <td th:text="${cartItemEntry.value.price}">36.8</td>
        <td th:text="${cartItemEntry.value.amount}">36.8</td>
        <td><a href="">删除</a></td>
    </tr>
    </tbody>
</table>
<div class="footer" th:if="${session.cart != null && session.cart.cartItemMap.size() > 0}">
    <div class="footer-left">
        <a href="#" class="clear-cart">清空购物车</a>
        <a href="index.html">继续购物</a>
    </div>
    <div class="footer-right">
        <div><span th:text="${session.cart.totalCount}">3</span>件商品</div>
        <div class="total-price">总金额<span th:text="${session.cart.totalAmount}">99.9</span></div>
        <a class="pay" href="checkout.html">去结账</a>
    </div>
</div>

5、清空购物车

①目标

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

②思路

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

③代码实现

[1]清空购物车超链接
<a href="CartServlet?method=clearCart" class="clear-cart">清空购物车</a>
[2]绑定单击响应函数
(1)引入Vue
<script src="static/script/vue.js" type="text/javascript" charset="utf-8"></script>
(2)编写Vue代码
new Vue({
    "el":"#appCart",
    "methods":{
        "clearCart":function () {
            // 1.使用confirm()弹框向用户确认是否要清空
            var confirmResult = confirm("您真的要清空购物车吗?");

            // 2.如果用户点击了取消
            if (!confirmResult) {

                // 3.调用事件对象的方法阻止超链接跳转页面
                event.preventDefault();
            }

        }
    }
});
[3]CartServlet.clearCart()
protected void clearCart(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    // 1.通过request对象获取Session对象
    HttpSession session = request.getSession();

    // 2.将Session域的Cart对象移除
    session.removeAttribute("cart");

    // 3.渲染视图
    String viewName = "cart/cart";

    processTemplate(viewName, request, response);
}

6、减号

①目标

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

②思路

减号span绑定单击响应函数→获取文本框中的数据:当前数量→检查数量是否大于1

  • 数量大于1:发送请求访问CartServlet.decrease()方法→回到cart.html
  • 数量等于1:confirm确认→发送请求访问CartServlet.removeItem()方法→回到cart.html

③后端代码

CartServlet.decrease()

protected void decrease(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    // 1.通过请求参数获取bookId
    String bookId = request.getParameter("bookId");

    // 2.通过request对象获取Session对象
    HttpSession session = request.getSession();

    // 3.从Session域获取购物车对象
    Cart cart = (Cart) session.getAttribute("cart");

    // ※考虑到如果Session超时会导致购物车数据丢失,所以先判断购物车数据是否为空
    if (cart != null) {

        // 4.从购物车对象中根据bookId执行-1操作
        cart.itemCountDecrease(bookId);

    }

    // 5.回到购物车页面
    String viewName = "cart/cart";

    processTemplate(viewName, request, response);

}

④前端代码

HTML代码:

<td>
    <input type="hidden" name="bookId" th:value="${cartItemEntry.value.bookId}" />
    <span @click="itemDecrease" class="count">-</span>
    ……
</td>

Vue代码:

,
"itemDecrease":function () {

    // 0.不管执行两种逻辑中的哪一种,都需要将当前item的bookId发送到Servlet
    // event:事件对象
    // event.target:当前事件操作的控件(HTML元素)
    // previousSibling:上一个兄弟节点。当前span标签的上一个兄弟节点是空格,所以要再找上一个兄弟
    var bookId = event.target.previousSibling.previousSibling.value;

    console.log("bookId="+bookId);

    // 1.获取文本框中的value属性值:当前item的数量
    // event:事件对象
    // event.target:当前事件操作的控件(HTML元素)
    // nextSibling:下一个兄弟节点。当前span标签的下一个兄弟节点是空格,所以要再找下一个兄弟
    // value:获取input标签的value属性值
    var currentCount = event.target.nextSibling.nextSibling.value;

    console.log("currentCount="+currentCount);

    // 2.判断currentCount是否大于1
    if (currentCount > 1) {

        // 3.应用-1逻辑
        console.log("currentCount > 1");

        window.location.href = "CartServlet?method=decrease&bookId="+bookId;

    } else {

        // 通过DOM树形结构获取图书名称数据
        // event:事件对象
        // event.target:当前事件操作的控件(HTML元素)
        // parentNode:访问父节点
        // parentNode.getElementsByTagName():在父节点范围内根据标签名称查找元素,返回数组
        // innerHTML:返回标签内部HTML代码
        var bookName = event.target.parentNode.parentNode.getElementsByTagName("td")[1].innerHTML;

        // 4.应用删除item的逻辑
        var confirmResult = confirm("你真的要从购物车中删除『"+bookName+"』这条记录吗?");

        if (confirmResult) {

            window.location.href = "CartServlet?method=removeItem&bookId="+bookId;
        }

    }
}

7、删除

①目标

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

②思路

cart.html→删除超链接→CartServlet.removeItem()→回到cart.html

③代码实现

[1]后端代码

CartServlet.removeItem()

protected void removeItem(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    // 1.从请求参数获取bookId
    String bookId = request.getParameter("bookId");

    // 2.通过request对象获取Session对象
    HttpSession session = request.getSession();

    // 3.从Session域获取购物车对象
    Cart cart = (Cart) session.getAttribute("cart");

    // ※考虑到如果Session超时会导致购物车数据丢失,所以先判断购物车数据是否为空
    if (cart != null) {

        // 4.执行删除item操作
        cart.removeCartItem(bookId);

    }

    // 5.回到购物车页面
    String viewName = "cart/cart";

    processTemplate(viewName, request, response);

}

[2]前端代码

HTML代码:

<a @click="removeConfirm" th:href="@{/CartServlet(method=removeItem,bookId=${cartItemEntry.value.bookId})}">删除</a>

Vue代码:

,
"removeConfirm":function () {

    // 通过DOM树形结构获取图书名称数据
    // event:事件对象
    // event.target:当前事件操作的控件(HTML元素)
    // parentNode:访问父节点
    // parentNode.getElementsByTagName():在父节点范围内根据标签名称查找元素,返回数组
    // innerHTML:返回标签内部HTML代码
    var bookName = event.target.parentNode.parentNode.getElementsByTagName("td")[1].innerHTML;
    console.log("bookName=" + bookName);

    if(!confirm("你真的要从购物车中删除『"+bookName+"』这条记录吗?")) {
        event.preventDefault();
    }

}

8、文本框修改

①目标

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

②思路

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

③代码实现

[1]后端代码

CartServlet.changeCount()

protected void changeCount(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    // 1.从请求参数获取bookId和newCount
    String bookId = request.getParameter("bookId");
    Integer newCount = Integer.parseInt(request.getParameter("newCount"));

    // 2.通过request对象获取Session对象
    HttpSession session = request.getSession();

    // 3.从Session域获取购物车对象
    Cart cart = (Cart) session.getAttribute("cart");

    // ※考虑到如果Session超时会导致购物车数据丢失,所以先判断购物车数据是否为空
    if (cart != null) {

        // 4.执行修改数量操作
        cart.updateItemCount(bookId, newCount);

    }

    // 5.回到购物车页面
    String viewName = "cart/cart";

    processTemplate(viewName, request, response);

}
[2]前端代码

HTML代码:

<td>
    <input type="hidden" name="bookId" th:value="${cartItemEntry.value.bookId}" />
    ……
    <input @change="itemCountChange" class="count-num" type="text" th:value="${cartItemEntry.value.count}" value="1"/>
    ……
</td>

Vue代码:

,
"itemCountChange":function () {

    // 1.获取文本框中输入的数据
    var newCount = event.target.value;

    // 6.排除小数或零或负数的情况
    var regExp = /^[0-9]+$/;

    if (!regExp.test(newCount) || newCount == 0) {

        // 7.如果用户输入的数据不是数字,给出提示
        alert("请输入正整数!");

        // 8.将文本框恢复为默认值
        event.target.value = event.target.defaultValue;

        // 9.当前函数停止执行
        return ;
    }

    // 10.获取bookId值
    var bookId = event.target.parentNode.getElementsByTagName("input")[0].value;
    console.log("bookId="+bookId);

    // 11.发送请求执行修改
    window.location.href = "CartServlet?method=changeCount&bookId="+bookId+"&newCount="+newCount;
}

9、加号

①目标

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

②思路

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

③代码实现

[1]后端代码

CartServlet.increase()

protected void increase(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    // 1.通过请求参数获取bookId
    String bookId = request.getParameter("bookId");

    // 2.通过request对象获取Session对象
    HttpSession session = request.getSession();

    // 3.从Session域获取购物车对象
    Cart cart = (Cart) session.getAttribute("cart");

    // ※考虑到如果Session超时会导致购物车数据丢失,所以先判断购物车数据是否为空
    if (cart != null) {

        // 4.从购物车对象中根据bookId执行-1操作
        cart.itemCountIncrease(bookId);

    }

    // 5.回到购物车页面
    String viewName = "cart/cart";

    processTemplate(viewName, request, response);

}
[2]前端代码

HTML代码:

<td>
    <input type="hidden" name="bookId" th:value="${cartItemEntry.value.bookId}" />
    ……
    <span @click="itemIncrease" class="count">+</span>
</td>

Vue代码:

,
"itemIncrease":function () {

    // 1.获取bookId值
    var bookId = event.target.parentNode.getElementsByTagName("input")[0].value;

    // 2.发送请求执行+1
    window.location.href = "CartServlet?method=increase&bookId="+bookId;

}

10、Double数据运算过程中精度调整

①问题现象

53e7e6e8c28b45a7a76416a231b92ae4.png

②解决方案

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

Cart类:

// 计算总金额
public Double getTotalAmount() {

    // 1.声明一个变量用于存储累加结果
    BigDecimal sum = new BigDecimal("0.0");

    // 2.遍历Map集合
    Set<String> keySet = cartItemMap.keySet();

    for (String key : keySet) {
        CartItem cartItem = cartItemMap.get(key);
        Double amount = cartItem.getAmount();

        sum = sum.add(new BigDecimal(amount + ""));
    }

    // 3.返回累加结果
    return sum.doubleValue();

}

CartItem类:

// 获取金额时需要计算得到
public Double getAmount() {

    BigDecimal bigDecimalCount = new BigDecimal(this.count + "");
    BigDecimal bigDecimalPrice = new BigDecimal(this.price + "");

    BigDecimal multiReuslt = bigDecimalCount.multiply(bigDecimalPrice);

    return multiReuslt.doubleValue();
}