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

处理思路

  • 点击结账,发送结账请求到 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. iOS 多线程之GCD的简单使用

    在iOS开发中,遇到耗时操作,我们经常用到多线程技术.Grand Central Dispatch (GCD)是Apple开发的一个多核编程的解决方法,只需定义想要执行的任务,然后添加到适当的调度队列 ...

  2. mysql中case的一个例子

    最近遇到一个问题: year amount num 1991 1 1.1 1991 2 1.2 1991 3 1.3 1992 1 2.1 1992 2 2.2 1992 3 3.3 把上面表格的数据 ...

  3. 【Lucene4.8教程之中的一个】使用Lucene4.8进行索引及搜索的基本操作

    版权声明:本文为博主原创文章.转载请注明来自http://blog.csdn.net/jediael_lu/ https://blog.csdn.net/jediael_lu/article/deta ...

  4. chm文件转换成html文件,解决chm文件无法使用浏览器打开的问题

    每天学习一点点 编程PDF电子书免费下载: http://www.shitanlife.com/code CHM是英语“Compiled Help Manual”的简写,即“已编译的帮助文件”.CHM ...

  5. D - C Looooops POJ - 2115 欧几里德拓展

    题意:就是看看for(; ;)多久停止. 最让我蛋疼的是1L和1LL的区别!让我足足wa了12发! 1L 是long类型的, 1LL为long long类型的! 思路: 这就是欧几里德扩展的标准式子了 ...

  6. java--Git学习使用

    第一步:安装 很简单,什么都不用管,一直下一步直到完成 第二步:Git配置                   1.打开GIt Bash         2.依次输入   git config --g ...

  7. Blinker 后台数据分析

    如何解析出后台服务器认证信息,供自己的设备连接. 测试程序 天气 增加了 Debug输出信息功能 1手机APP添加控件信息   2硬件烧录程序 #define BLINKER_PRINT Serial ...

  8. P1004 方格取数-洛谷luogu-dp动态规划

    题目描述 设有N \times NN×N的方格图(N \le 9)(N≤9),我们将其中的某些方格中填入正整数,而其他的方格中则放入数字00.如下图所示(见样例): A 0 0 0 0 0 0 0 0 ...

  9. PAT A1075 PAT Judge (25 分)——结构体初始化,排序

    The ranklist of PAT is generated from the status list, which shows the scores of the submissions. Th ...

  10. PAT A1134 Vertex Cover (25 分)——图遍历

    A vertex cover of a graph is a set of vertices such that each edge of the graph is incident to at le ...