文章目录
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)
;即可获取最迟支付的事件