WEB 小案例 -- 网上书城(四)

针对于这个小案例我们今天讲解结账操作,也是有关这个案例的最后一次博文,说实话这个案例的博文写的很糟糕,不知道该如何去表述自己的思路,所以内容有点水,其实说到底还是功力不够。

处理思路

  • 点击结账,发送结账请求到 Servlet 处理;
  • 在 Servlet 相关方法中 获取购物车商品信息,比如:某件商品需要购买的量,价格等基本属性;
  • 接着在 Servlet 方法中获取购物车中商品的库存检测库存是否充足,否则提示某本书库存不足;
  • 若购物车中的所有商品数量充足,接着校验登录用户的账户余额是否充足,否则提示余额不足;

注意:该项操作中会使用到事务,其流程必须一次性完成,若中间发生意外导致流程中断,那么就必须将已执行的操作复原。

案例演示

  • 在数据库中我们可以看到登录账户的余额,如下:
  • 结账操作如下 GIF 所示:

代码展示及解析

  • 购物车页面中点击 “结账” 超链接发送请求到 Servlet 中的 check 方法 shoppingCart.jsp 页面的 结账超链接

check 方法从获取到的购物车中所要购买商品的 List,判断该 List 中商品的库存是否充足,将库存不足的商品传回页面用来提示用户具体错误信息;若库存充足则跳转到结账页面 Servlet 的 check 方法

  • 在结账页面点击确认下单发送请求到 Servlet 方法 payMoney,获取 session 中的购物车页面,从中获取将要下单的商品的总价钱,同时获取到用户登录时存在 session 中的登录信息进而得到登录用户的账户信息,校验余额是否充足,若余额不足则提示如 GIF 所示的信息,若充足则跳转到购物成功页面

pay.jsp

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>Pay</title>
    </head>
    <body>
    <div>
        ${requestScope.moneyMessage}<br><br>
        你共买了 ${sessionScope.shoppingCartPage.totalBookCount} 本书,应付金额 ¥${sessionScope.shoppingCartPage.totalBookMoney}<br><br>
        <a href="${pageContext.request.contextPath}/payMoney.do">确认下单</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
            <a href="${pageContext.request.contextPath}/showCart.do">返回购物车</a>
    </div>
    </body>
    </html> 

Servlet 的 payMoney 方法

    /*
        * 结账操作所执行的方法
        * */
        protected void payMoney(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //        从 session 中获取购物车页面
            ShoppingCartPage shoppingCartPage = (ShoppingCartPage) getSession(request).getAttribute("shoppingCartPage");
    //        从购物车页面中获取到购物车中所有商品的价格和
            Integer totalBookMoney = shoppingCartPage.getTotalBookMoney();
    //        获取用户登录后所存储的 userInfo 对象,可从中获取到用户的 id 属性
            Integer userId = ((Userinfo)getSession(request).getAttribute("userInfo")).getUserId();
    //        利用用户 id 获取用户的 accountId 属性,然后利用账户 id 获取账户余额
            Integer balance = bookService.getBalance(bookService.getAccountId(userId));
    //        判断余额是否充足购买购物车中商品
            if (balance < totalBookMoney) {
    //            若不充足,则返回结账页面并提示用户余额不足
                request.setAttribute("moneyMessage", "您的余额不足!");
    //            请求转发回原页面(结账页面)
                request.getRequestDispatcher("/showView/pay.jsp").forward(request, response);
    //            结束当前方法的执行
                return;
            }
    //        若充足则执行事务操作,即更新余额、库存、销售量等数据
            bookService.transaction(shoppingCartPage, userId);
    //        若支付成功则转发到成功页面
            response.sendRedirect(request.getContextPath() + "/success/successPay.jsp");
        }

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
    <filter>
        <filter-name>ThreadLocalFilter</filter-name>
        <filter-class>com.book.store.filter.ThreadLocalFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>ThreadLocalFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <servlet>
        <servlet-name>BookShopServlet</servlet-name>
        <servlet-class>com.book.store.controler.BookShopServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>BookShopServlet</servlet-name>
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>
</web-app>

以上操作均是按照流程在登录后进行的操作 对于结账操作我们使用 ThreadLocal 完成事务操作,使其在出错的情况下不会完成对数据库的更改 使用 ThreadLocal 处理事务,即通过 ThreadLocal.set() 将对象的引用保存到各线程的自己的一个 map 中,每个线程都有这样一个 map,执行 ThreadLocal.get() 时,各线程从自己的 map 中取出放进去的对象,因此取出来的是各自自己线程中的对象,ThreadLocal 实例是作为 map 的 key 来使用的,这样便可以在最后的结账操作事务中合法完成。 一般情况下,通过 ThreadLocal.set() 到线程中的对象是该线程自己使用的对象,其他线程不需要访问,所以说 ThreadLocal 不能解决共享对象的多线程访问问题。

对于本案例所有我实现的功能就讲述到这里,我自己也知道内容有点烂!!不知道如何将案例表述出来,博文第一次写比较大的案例(对我来说)难免有问题,还望大佬们谅解!!!

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Seebug漏洞平台

Huawei HG532 系列路由器远程命令执行漏洞分析

English version: https://paper.seebug.org/508/

39215
来自专栏web前端教室

定位+思路+方法,三步教你快速敲定前端JS结构

闲话少说, --定位 就是说你现在要写的是什么东西?是一个页面?还是一个组件?还是一个function方法?不同的东西它的定位不同,结构就不同。 如果是页面,那...

21710
来自专栏生信技能树

我的第一R包- 生信配置文件大全

大家好,我是李剑峰,生信技能树论坛的VIP小编,目前在上海交通大学医学院附属瑞金医院进行研究生阶段的学习,主要研究方向是生物信息学、医学信息学、大数据综合分析、...

3949
来自专栏刺客博客

魅蓝Note3降级教程

3.9K6
来自专栏蓝天

Linux下可以替换运行中的程序么?

今天被朋友问及“Linux下可以替换运行中的程序么?”,以前依稀记得Linux下是可以的(而Windows就不让),于是随口答道“OK”。结果朋友发来一个执行结...

1922
来自专栏前端小吉米

域名发散--域的故事(三)

1633
来自专栏北京马哥教育

Python神技能 | 使用爬虫获取汽车之家全车型数据

最近想在工作相关的项目上做技术改进,需要全而准的车型数据,寻寻觅觅而不得,所以就只能自己动手丰衣足食,到网上获(窃)得(取)数据了。 汽车之家是大家公认的数据做...

6479
来自专栏阮一峰的网络日志

如何让搜索引擎抓取AJAX内容?

越来越多的网站,开始采用"单页面结构"(Single-page application)。 整个网站只有一张网页,采用Ajax技术,根据用户的输入,加载不同的内...

3083
来自专栏Google Dart

AngularDart4.0 高级-层级依赖注入器 顶

在Dependency Injection指南中你学会了基础的Angular依赖注入. Angular有一个层级依赖注入 系统. 实际上是一个与组件树相平行的...

641
来自专栏FreeBuf

浅谈非PE的攻击技巧

背景 近日,金山毒霸安全中心捕获到一例利用邮件传播的非PE样本,类型为lnk快捷方式文件,执行后会下载勒索病毒,最终会加密用户机器上的文档、图片、视频等重要文件...

3527

扫码关注云+社区

领取腾讯云代金券