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


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

    处理思路

    • 点击结账,发送结账请求到 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 不能解决共享对象的多线程访问问题。

    对于本案例所有我实现的功能就讲述到这里,我自己也知道内容有点烂!!不知道如何将案例表述出来,博文第一次写比较大的案例(对我来说)难免有问题,还望大佬们谅解!!!
  • 相关阅读:
    netty系列之:基于流的数据传输
    netty系列之:中国加油
    netty系列之:Event、Handler和Pipeline
    netty系列之:netty中的Channel详解
    netty系列之:netty架构概述
    Python 列表解析式竟然支持异步?
    Python 数值中的下划线是怎么回事?
    Nginx+keepalived 双机主从模式下修改主Nginx自动同步nginx.conf配置文件至备Nginx
    Oracle nvarchar2存储特殊字符乱码问题
    Oracle 11.2.0.4.0版本下大表添加默认值字段影响因素
  • 原文地址:https://www.cnblogs.com/bgzyy/p/8579066.html
Copyright © 2020-2023  润新知