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

处理思路

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

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

案例演示

  • 在数据库中我们可以看到登录账户的余额,如下:

  • 结账操作如下 GIF 所示:

代码展示及解析

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

shoppingCart.jsp 页面的 结账超链接

		<tr>
<td><a href="${pageContext.request.contextPath}/query.do?pageNo=${param.pageNo}">继续购物</a></td>
<td><a href="${pageContext.request.contextPath}/truncated.do?pageNo=${param.pageNo}">清空购物车</a></td>
<td><a href="${pageContext.request.contextPath}/check.do?pageNo=${param.pageNo}">结账</a></td>
</tr>
  • check 方法从获取到的购物车中所要购买商品的 List,判断该 List 中商品的库存是否充足,将库存不足的商品传回页面用来提示用户具体错误信息;若库存充足则跳转到结账页面

Servlet 的 check 方法

	    /*
* 校验操作所执行的方法(库存是否充足)
* */
protected void check(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 从 session 中获取购物车页面对象
ShoppingCartPage shoppingCartPage = (ShoppingCartPage) getSession(request).getAttribute("shoppingCartPage");
// 设置一个标识,用于后面判断
boolean flag = true;
// 获取购物车中商品对象的 list
List<ShoppingCartItem> shoppingCartItemList = shoppingCartPage.getShoppingCartItemList();
// 将购物车中所有库存不足的商品加入 list,回传至页面,方便显示
List<String> messageList = new ArrayList<String>();
// 遍历购物车中所有商品
for (ShoppingCartItem shoppingCartItem : shoppingCartItemList) {
// 获取书名
String bookName = shoppingCartItem.getCartName();
// 获取该书的库存
Integer storeNumber = bookService.getStoreNumber(bookName);
// 判断库存量是否充足
if (shoppingCartItem.getCartCount() > storeNumber) {
// 若库存量不充足则将其加入预先定义好的 list 变量中
messageList.add(shoppingCartItem.getCartName());
// 并将标识设置为 false
flag = false;
}
}
// 判断标识
if (!flag) {
// 若标识为 false,则表名存在库存不足的商品,所以将库存不足的商品列表存入 request 中
request.setAttribute("messageList", messageList);
// 并转发回购物车页面
request.getRequestDispatcher("/showView/shoppingCart.jsp").forward(request, response);
// 结束本方法
return;
}
// 若库存充足,那么就进行结账操作
request.getRequestDispatcher("/showView/pay.jsp").forward(request, response);
}
  • 在结账页面点击确认下单发送请求到 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 不能解决共享对象的多线程访问问题。

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

WEB 小案例 -- 网上书城(四)的更多相关文章

  1. WEB 小案例 -- 网上书城(一)

    距离上次写博客有两周了吧,最多的原因就是自己期末考试了,上课没听就只能在期末狠狠的复习了,毕竟已经挂科了.当然还是因为自己懒吧!!!废话不多说开始我们今天的正题,网上书城! 一. 新建数据表(MySQ ...

  2. Web 小案例 -- 网上书城(三)

    内容有点乱,有兴趣的同伙可依照后面的案例结构结合文章进行阅读 和网上购买东西一样,你可以在不登录的状态下去浏览商品,但是当你想把自己中意的东西加入购物车或是收藏起来就需要你拥有自己的账号然后登录后才可 ...

  3. WEB 小案例 -- 网上书城(二)

    寒假结束了,自己的颓废时间同样结束了,早该继续写博客了,尽管我的格式以及内容由于各种原因老被卡,但必须坚持写下去!!! 上次我们对于本案例的数据库部分进行了阐述,这次主要接着上次的内容分享本案例的翻页 ...

  4. 02SpringMvc_springmvc快速入门小案例(XML版本)

    这篇文章中,我们要写一个入门案例,去整体了解整个SpringMVC. 先给出整个项目的结构图:

  5. Android JSON解析库Gson和Fast-json的使用对比和图书列表小案例

    Android JSON解析库Gson和Fast-json的使用对比和图书列表小案例 继上篇json解析,我用了原生的json解析,但是在有些情况下我们不得不承认,一些优秀的json解析框架确实十分的 ...

  6. SqlDependency缓存数据库表小案例

    SqlDependency的简介: SqlDependency是outputcache网页缓存的一个参数,它的作用是指定缓存失效的数据库依赖项,可以具体到数据库和表. SqlDependency能解决 ...

  7. MVC 小案例 -- 信息管理

    前几次更新博客都是每次周日晚上到周一,这次是周一晚上开始写,肯定也是有原因的!那就是我的 Tomact 忽然报错,无法启动,错误信息如下!同时我的 win10 也崩了,重启之后连 WIFI 的标志也不 ...

  8. 8天入门docker系列 —— 第五天 使用aspnetcore小案例熟悉容器互联和docker-compose一键部署

    这一篇继续完善webnotebook,如果你读过上一篇的内容,你应该知道怎么去挂载webnotebook日志和容器的远程访问,但是这些还远不够,webnotebook 总要和一些数据库打交道吧,比如说 ...

  9. spring boot入门小案例

    spring boot 入门小案例搭建 (1) 在Eclipse中新建一个maven project项目,目录结构如下所示: cn.com.rxyb中存放spring boot的启动类,applica ...

随机推荐

  1. fedora 配置使用点滴

    fedora 配置使用点滴 fedora 16 无线网设置 fodera16是3.x的内核,无线网卡的驱动有点不一样. 可以用如下方法安装,需要先用有线网来安装几个包,步骤如下: 执行这个命令看看网卡 ...

  2. Alpha冲刺! Day10 - 砍柴

    Alpha冲刺! Day10 - 砍柴 今日已完成 晨瑶:处理一些杂碎: 反思. 昭锡:主页添加时间选择器,实现随机分布的光点与数据绑定. 永盛:定下来了 MVC 的许多东西,完成 Router 的样 ...

  3. 【Ansible 文档】【译文】Playbooks 变量

    Variables 变量 自动化的存在使得重复的做事情变得很容易,但是我们的系统不可能完全一样. 在某些系统中,你可能想要设置一些与其他系统不一样的行为和配置. 同样地,远程系统的行为和状态也可以影响 ...

  4. BZOJ1024:[SCOI2009]生日快乐(DFS)

    Description windy的生日到了,为了庆祝生日,他的朋友们帮他买了一个边长分别为 X 和 Y 的矩形蛋糕. 现在包括windy,一共有 N 个人来分这块大蛋糕,要求每个人必须获得相同面积的 ...

  5. firewalld

    1.查看firewalld防火墙自带的区域名 [root@web ~]# firewall-cmd --get-zones block dmz drop external home internal ...

  6. iptables四表五链及默认规则使用,

    网络基础 TCP/IP模型: 应用层===传输层===网络层===数据链里层===物理层 数据封装: MAC帧头+IP报头+TCP/UDP报头===HTTP请求 数据帧 TCP/UDP报头: 随机产生 ...

  7. Centos 6.5配置rsync+inotify实现文件实时同步

    1.安装rsync(两台机器执行相同的步骤)yum install gcc yum install rsyncd xinetd -y因为rsync是由xinetd启动的,所以需要修改一个配置vim / ...

  8. 搭建LNMP环境(CentOS 6)

    本文档介绍如何使用一台普通配置的云服务器ECS实例搭建LNMP平台的web环境. Linux:自由和开放源码的类UNIX操作系统. Nginx:轻量级网页服务器.反向代理服务器. MySQL:关系型数 ...

  9. <转>七种测试驱动模式

    本文转载自微信公众号:中国软件测试联盟 在进行软件测试时,我们都需要一个出发点,从哪里开始分析?测试设计是基于什么?简单说,就是什么驱动测试工作的进行? 基于对软件工程.产品质量和测试的理解,归纳出以 ...

  10. Linux下对inode和块的理解

    基本概念 首先讲下inode和块的基本概念.在Linux系统中,文件由元数据和数据块组成.数据块就是多个连续性的扇区(sector),扇区是文件存储的最小单位(每个512字节).块(block)的大小 ...