针对于这个小案例我们今天讲解结账操作,也是有关这个案例的最后一次博文,说实话这个案例的博文写的很糟糕,不知道该如何去表述自己的思路,所以内容有点水,其实说到底还是功力不够。
注意:该项操作中会使用到事务,其流程必须一次性完成,若中间发生意外导致流程中断,那么就必须将已执行的操作复原。
check 方法从获取到的购物车中所要购买商品的 List,判断该 List 中商品的库存是否充足,将库存不足的商品传回页面用来提示用户具体错误信息;若库存充足则跳转到结账页面 Servlet 的 check 方法
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>
<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 不能解决共享对象的多线程访问问题。