图书商城_day5遇到难点

1.1 将来到商品,并且设置了购买数量之后,加入购物车之后,购买数量依旧是1

当我们选中了某一个商品,之后,设置购买数量为4,然后加入购物车,然后我们就会来到购物车的界面,看到我们新加入的商品以及购买的数量,如下所示:
在这里插入图片描述

在这里插入图片描述

但是一开始在点击"加入购物车"这个超链接之后,来到了第二个界面,显示的购买数量却是1,后来才发现,在超链接中并没有传递参数count,而在自己的Servlet中代码中,如果没有传递参数count,那么就默认购买了1本,所以就到了错误。那么我们将如何实现我们上面的要求呢?我们只需要向请求中发送count参数即可,并且count的值就是我们在第一个界面中设置的值。但是我们又该如何获取设置的值呢?。也即这个问题变成了,超链接将如何获取表中的值呢?其实很简单,我们只需要给这个超链接设置一个点击事件,然后再这个点击事件中,获取我们想要的标签的值,然后再来设置这个超链接的href属性即可实现我们的需求了。所以我们只需要修改第一个界面的代码即可,主要代码如下:

--------------html代码--------------------------
<div id="top" style="text-align: right">
        <div id="right">
            <c:if test="${not empty requestScope.book}">
                <form action="/OrderServlet" method="post">
                    <input type="hidden" name="method" value="produceOrder">
                    <input type="hidden" name="id" value="${book.id}"> <!--提交订单的时候,需要传递这个图书的相关信息-->
                    <div id="image_frame">
                        <img src="/images/${book.name}.png">
                    </div>
                    <div id="desc_frame">
                        <p>${book.name}</p>
                        <p name="price">¥ ${book.price} 元</p>
                        <p>
                            <input type="button" id="sub" value="-">
                            <input type="text" name="count" id="count" value="1" style="width: 50px;"> <!--默认购买一本-->
                            <input type="button" id="add" value="+">
                        </p>
                        <p>
                            <input type="submit" value="立刻购买">
                            <a id="a" style="margin-left: 25px; background-color: lightgreen; " onclick="getHref(${book.id})">加入购物车</a>
                        </p>
                    </div>
                </form>
            </c:if>
        </div>
    </div>

------------js代码--------------------------
<script type="text/javascript" src="<c:url value="/ajax.js"></c:url>"></script>
<script type="text/javascript">
    function getHref(id){
        var a = document.getElementById("a");
        var count = document.getElementById("count").value;//获取文本框的值
        a.href = "/CartServlet?method=addItem&id=" + id + "&count=" + count;
    }
</script>

1.2 生成订单的过程

首先我们生成订单主要有2种方式:一种是从购物车中生成,另一种方式则是从商品界面中直接生成。但是不管哪一种方式,我们点击购买之后,都需要先设置收货人,收获地址以及联系电话,然后点击提交订单之后才可以生成订单,否则是不会产生订单的。我们可以参考以下淘宝支付的过程就可以理解了。之前就是在这里生成订单的时候弄了好久。所以我们需要的流程主要是这样的:
在这里插入图片描述
所以主要的代码如下所示:

    //来到了购物车之后,点击下单就生成对应的订单,然后转发到对应的界面中
    public String produceFromCart(HttpServletRequest request, HttpServletResponse response){
        request.setAttribute("source","produceFromCart");
        HttpSession session = request.getSession();
        double total = ((CartList)session.getAttribute("cartList")).getTotal();//购物车的总计
        session.setAttribute("total",total);
        //来到订单预支付的界面,来选择收货人,电话等信息
        return "f:/jsps/orders/prePay.jsp";
    }

    //来到某一个商品界面,点击购买
    public String produceOrder(HttpServletRequest request, HttpServletResponse response){
        //获取商品的id
        String value = request.getParameter("id");
        if(value == null){
            throw new RuntimeException("没有传递参数id,没有办法生成Order");
        }
        int id = Integer.parseInt(value);
        Book book = null;
        //获取购买的图书
        try {
            book = bookService.queryById(id);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        value = request.getParameter("count");//获取购买数量
        if(value == null){
            throw new RuntimeException("没有传递购买数量");
        }
        int count = Integer.parseInt(value);
        double total = book.getPrice() * count;
        //生成订单
        HttpSession session = request.getSession();
        //生成订单条目
        OrderItem orderItem = new OrderItem();
        orderItem.setCount(count);
        orderItem.setBook(book);
        session.setAttribute("orderItem",orderItem);
        request.setAttribute("source","produceOrder");
        session.setAttribute("total",total);
        return "f:/jsps/orders/prePay.jsp";
    }
    
    public String payOrder(HttpServletRequest request,HttpServletResponse response){
        //设计生成订单的时间以及最迟支付订单的时间
        Date date = new Date();//获取当前下单的时间
        Date dead_date = DateUtils.addMinutes(date, 30);//获取最迟支付的事件
        Timestamp timestamp = new Timestamp(date.getTime());
        Timestamp dead_time = new Timestamp(dead_date.getTime());
        String value = request.getParameter("province_id");
        if(value == null){
            throw new RuntimeException("没有传递province_id参数");
        }
        int province_id = Integer.parseInt(value);
        //获取这个id的城市
        String province = null;
        try {
            province = new ProvinceService().queryById(province_id).getName();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        String city = request.getParameter("city");
        //获取这个订单,设置收件人,收获地址以及收件人的电话
        String detail = request.getParameter("detail");
        String address = province + city + detail;
        String receiver = request.getParameter("receiver");
        String phone = request.getParameter("phone");
        //将购物车中的商品生成对应OrderItem
        String source = request.getParameter("source");
        HttpSession session = request.getSession();
        Customer customer = (Customer)session.getAttribute("customer");
        int customer_id = customer.getId();
        double total = (Double)session.getAttribute("total");
        System.out.println(address + ", " + receiver + ", " + phone + ", " + source);
        try {
            int order_id = service.produceOrder(total, customer_id, timestamp,dead_time,address,receiver,phone);
            if(source != null && "produceFromCart".equals(source)){
                //从购物车中生成orderItem,然后从购物车中生成订单的,并需要将购物车清空
                CartList cartList = (CartList)(session.getAttribute("cartList"));
                List<OrderItem> orderItems = produceOrderItemFromCart(cartList);
                for(OrderItem orderItem : orderItems){
                    System.out.println(orderItem);
                    orderItem.setOrder_id(order_id);
                }
                //将订单条目添加到orderItem表中
                orderItemService.addItem(orderItems);
                cartList.clearItems();
            }else{
                //如果时点击某一个商品之后,立即购买
                OrderItem orderItem = (OrderItem)session.getAttribute("orderItem");
                orderItem.setOrder_id(order_id);
                orderItemService.addItem(orderItem);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        //支付完毕之后,来到首页
        return "d:/jsps/index.jsp";
    }

prePay界面的主要代码为:

<!--如果产生订单的来源不为空-->
<c:if test="${not empty requestScope.source}">
     <form action="/OrderServlet" method="post">
         <input type="hidden" name="method" value="payOrder">
         <input type="hidden" name="source" value="${requestScope.source}">
         所在地址: <select id="province" name="province_id"><option>===请选择===</option></select> <select id="city" name="city"><option>===请选择===</option></select><br>
         详细地址: <input type="text" id="detail" name="detail"><br>
         收件人: <input type="text" id="receiver" name="receiver"><br>
         电话: <input type="text" id="phone" name="phone"><br>
         <table>
             <c:choose>
                 <c:when test="${requestScope.source eq 'produceFromCart'}">
                     <c:forEach items="${sessionScope.cartList.cartItems.values()}" var="item">
                         <tr>
                             <td><img src="<c:url value='/images/${item.book.name}.png'></c:url>"></td>
                             <td>${item.book.name}</td>
                             <td>${item.book.catagory_name}</td>
                             <td>${item.book.price} x ${item.count} 本</td>
                             <td>
                                 <!--pattern的格式为0.00,规定保留两位小数--><f:formatNumber value="${item.total}" pattern="0.00"></f:formatNumber></td>
                         </tr>
                     </c:forEach>
                 </c:when>
                 <c:otherwise>
                     <tr>
                         <td><img src="<c:url value='/images/${sessionScope.orderItem.book.name}.png'></c:url>"></td>
                         <td>${sessionScope.orderItem.book.name}</td>
                         <td>${sessionScope.orderItem.book.catagory_name}</td>
                         <td>${sessionScope.orderItem.book.price} x ${sessionScope.orderItem.count} 本</td>
                         <td>
                             <!--pattern的格式为0.00,规定保留两位小数--><f:formatNumber value="${sessionScope.orderItem.subtotal}" pattern="0.00"></f:formatNumber></td>
                     </tr>
                 </c:otherwise>
             </c:choose>
         </table>
         <span style="margin-left: 800px;text-align: right;" name="total">总计: ¥ <f:formatNumber pattern="0.00" value="${sessionScope.total}"></f:formatNumber></span>
         <input style="margin-left: 10px;" type="submit" value="提交订单">
     </form>
 </c:if>
</div>

1.3 生成订单的时候,生成的事件和实际的时间相差8个小时

当我们生成订单之后,如果我们来查看数据库的时候,会发现生成订单的时间和实际时间相差了8个小时,虽然我们在配置c3p0-config.xml的时候,有添加了serverTimezone=UTC,但是依旧是发生了这样的报错,如果我们在用命令行执行select now()的时候,发现获取的时间和我们实际的时间一样的,所以关键就在于我们c3p0-confing.xml中serverTimezone的值了,要解决这个问题,我们需要将serverTimezone的值设置为Asia/Shanghai即可

1.4 多条订单未支付的时候,需要显示倒计时,超过相应时间自动取消订单

如果我们来到了我的订单界面,如果订单还没有支付的话,那么我们需要倒计时,那么我们将如何来实现呢?
在这里插入图片描述
我们要实现订单的倒计时,我们需要利用定时器,即js调用setInternal()方法即可,因为是以毫秒为单位的,所以是每1000毫秒就要执行一次

但是我们拥有多条订单,怎么获取某一个订单的的最迟支付时间,又该如何在时间超过了最迟支付的时间,取消订单呢?

  • 设置多条订单的倒计时支付
    ①准备工作: 因为是多条订单,所以我们需要在js中利用遍历,首先我们需要先获取显示时间倒计时的span,因为不只一个,所以我们需要将span的class属性定义为time_span,然后利用document.getElementsByClassName("time_span")来获取所有的time_span,同时我们需要获取每一个订单的最迟支付时间,这时候我们需要给这个span标签定义一个属性left_time,对应的值就是订单的最迟支付时间。
    ②js中遍历span标签,每获取到一个span标签,就获取属性left_time的值,这样就可以生成一个字符串,根据这个字符串,来新建Date对象,调用getTime方法,即获取到了最迟支付时间的long类型的值dead_time,注意的是此时获取到的值是一个毫秒单位的值
    ③新建Date对象,调用getTime方法,来获取当前的时间cur_time。
    ④如果cur_time大于等于了dead_time,那么就需要利用ajax来取消订单
    ⑤否则,获取两者的差值sub,此时的sub依旧是以毫秒为单位的。我们需要先除以1000
    ⑥获取剩余的时间:hour: sub / 3600; minute: (sub - hour * 3600) / 60; second: sub - hour * 3600 - minute * 60;
    ⭐⭐⭐注意的是,在js中,/并不是象在java中的是一个整除,而是最后得到的是一个浮点数。所以我们需要利用Math.floor来实现。注意不是以Math.round,否则就会导致倒计时有问题,比如我测试的时候,剩余9分00秒的时候,下一个时间本应该是8分59秒,如果是用Math.round的话,就会导致是9分59秒.所以我才使用的是Math.floor,目前也是可以正常运行的。
    ⑦在获取hour,minute,second之后,将他们拼接成为字符串,然后赋值给span。但是span.value是不可以实现我们的需求的,这时候我们就利用innerHTML来给span赋值即可。
    ⑧上面的方法就是我们定时器需要执行的代码,所以我们调用setInterval(xxx,1000),这样就可以实现每隔1秒就执行对应的代码了。

  • 如果时间超过了最迟支付的时间,那么我们将利用ajax来取消订单,在取消订单之后,就会重定向到了首页,所以我们再次来点击我的订单的时候,就会发现超时未支付的订单已经没有了,再来到数据库查看的时候,发现对应的order的确已经删除了。

所以对应的代码为:

--------------------------html代码----------------------------------
<c:if test="${not empty requestScope.orders}">
            <table>
                <c:set var="index" value="0"></c:set>
                <c:forEach items="${requestScope.orders}" var="order" varStatus="vs">
                    <tr>
                        <td colspan="6" style="background-color: lightseagreen;height: 20px;">
                            <c:if test="${order.state == 1}">
                                <!--如果这个订单时已经生成了,但是未支付的状态-->
                                剩余支付时间: <span class="time_span" left_time="${order.dead_time}" order_id="${order.id}"></span>
                                <a href="/OrderServlet?method=cancelOrder&order_id=${order.id}">取消订单</a>
                            </c:if>

                            <a href="/OrderServlet?method=detailOrder&order_id=${order.id}">订单详情</a>
                        </td>
                    </tr>
                    <c:forEach items="${order.items}" var="item">
                           <tr>
                                <td><img src="<c:url value='/images/${item.book.name}.png'></c:url>"></td>
                                <td>${item.book.name}</td>
                                <td>${item.book.catagory_name}</td>
                                <td>${item.book.price} x ${item.count} 本</td>
                                <td>
                                    <!--pattern的格式为0.00,规定保留两位小数--><f:formatNumber value="${item.subtotal}" pattern="0.00"></f:formatNumber></td>
                                <td>
                                    <a href="/OrderServlet?method=cancelItem&id=${item.id}">取消</a>
                                </td>
                            </tr>
                        </c:forEach>
                </c:forEach>
            </table>
        </c:if>
--------------------------js代码------------------------------------
<script type="text/javascript" src="<c:url value="/ajax.js"></c:url>"></script>
<script type="text/javascript">
function time_expire(){
            //获取所有time的span标签
            var spans = document.getElementsByClassName("time_span");
            for(var i = 0; i < spans.length; ++i){
                //对于每一个span,都需要获取它的最迟购买时间
                var left_time = spans[i].getAttribute("left_time"); //yyyy-MM-dd HH:mm:ss的形式字符串
                var dead_time = new Date(left_time).getTime();
                //判断当前的时间是否等于left_time
                var cur_time = new Date().getTime();
                if(dead_time <= cur_time){
                    //将这个订单取消,然后重定向到了首页
                    var order_id = spans[i].getAttribute("order_id");
                    request({
                        method: "POST",
                        resource: "/OrderServlet",
                        params: "method=cancelOrder&order_id=" + order_id
                    })
                    window.location.reload();
                }else{
                    //剩余共有sub秒
                    var sub = dead_time - cur_time;//getTime返回的是毫秒值,所以还需要将其除以1000
                    sub = Math.floor(sub / 1000);
                    var hour = Math.floor(sub / 3600);
                    var minute = Math.floor((sub - hour * 3600) / 60);
                    var second = sub - hour * 3600 - minute * 60;
                   // spans[i].innerHTML = hour + "时" + minute + "分" + second + "秒";
                   spans[i].innerHTML = hour + "时" + minute + "分" + second + "秒";
                }

            }
        }
        window.setInterval(time_expire,1000);//1000ms就执行一次
</script>

1.4 根据生成订单时间,设置最迟支付时间

生成订单的时候,我们需要设置2时间produce_time(生成订单的时间),以及dead_time(最迟支付时间),但是我们如何生成dead_time,使得和produce_time相差30分钟呢?主要是通过使用DateUtils来实现,例如我们这里最迟支付时间,比生成时间多了30分钟,那么只需要执行DateUtils.addMinutes(date, 30);即可获取最迟支付的事件

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值