引入模态框组件,增加交互体验:
<div class="modal modal-lg fade" id="orderModal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5 text-danger fw-bold">确认订单h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close">button>
div>
<div class="modal-body" id="orderContent">
<table class="table align-middle">
<thead>
<tr>
<th class="px-3" style="width: 120px;">餐品th>
<th style="width: 300px;">描述th>
<th>价格th>
<th>数量th>
tr>
thead>
<tbody id="orderList">
<tr>
<td class="p-2">
<img src="meal/pic?meal_pic=food01.jpeg" class="rounded"
style="width:100px;" />
td>
<td >
XXX
td>
<td class=" fs-5 text-danger">
¥50
td>
<td>
2
td>
tr>
tbody>
table>
div>
<div class="modal-footer">
<div id="orderInfo" class="align-middle">div>
<button id="payingBtn" class="btn btn-danger" style="display: none;"
type="button" disabled>
<span class="spinner-border spinner-border-sm">span>
<span>支付中...span>
button>
<button id="payBtn" type="button" class="btn btn-danger" style="display:block;">
确认支付
button>
div>
div>
div>
div>
创建模态框对象,转化为对象才可以使用模态框组件:
const orderModal = new bootstrap.Modal(document.querySelector("#orderModal"));
在购物车页面,为下订单按钮添加事件响应函数:
<button onclick="placeOrder()" type="button" class="btn btn-warning text-white" style="width:100px;">下订单
最后在购物车页面js部分,定义下订单函数,也就是实现下订单哪里调用的函数:
const placeOrder = async () => {
let total = 0;
let totalPrice = 0;
const boxes = document.querySelectorAll(".my-box:checked");
if (!boxes.length) {
toast("错误!", "请选择要购买的商品!");
return;
}
const idArgs = [...boxes].map(box => `meal_id=${box.value}`).join("&");
const resp = await fetch(`cart/chklist?${idArgs}`);
if (!resp.ok) {
toast("错误!", "查询失败!");
return;
}
const result = await resp.json();
if (!result.success) {
toast("失败!", result.message);
return;
}
const chklist = result.data;
let innerHTML = ``;
for (let i = 0; i < chklist.length; i++) {
const meal = chklist[i];
total += meal.s_num;
totalPrice += meal.s_num * meal.meal_price;
innerHTML += `
${meal.meal_pic}" class="rounded"
style="width:100px;"/>
${meal.meal_desc}
¥${meal.meal_price}
${meal.s_num}
`;
}
document.querySelector("#orderList").innerHTML = innerHTML;
document.querySelector("#orderInfo").innerHTML = `已选
${total}
件,总价
¥${totalPrice}`;
orderModal.show();
}
对一些关键代码进行解释:
let total = 0; 和 let totalPrice = 0;
:初始化两个变量,分别用于存储选中商品的数量总和和价格总和。
const boxes = document.querySelectorAll(".my-box:checked");
:使用 querySelectorAll 方法选择所有被选中的 .my-box 元素(通常是复选框),这些元素代表用户想要购买的商品。
3. if (!boxes.length) {
:检查是否有商品被选中。如果没有,显示一个错误提示,并返回,不继续执行函数。
const idArgs = [...boxes].map(box => meal_id=${box.value}).join("&");
:将选中的商品的 value 属性(也就是商品的ID)转换成查询字符串格式,用于后续的请求,向后端传达参数。
const resp = await fetch(cart/chklist?${idArgs});
:使用 fetch 方法向服务器发送请求,获取选中商品的详细信息。请求的URL包含了之前生成的查询字符串。
6. if (!resp.ok) {
:检查响应是否成功。如果不成功,显示错误提示,并返回。
const result = await resp.json();
:解析响应的JSON数据。
if (!result.success) {
:检查从服务器返回的结果是否表示成功。如果不成功,显示错误提示,并返回。
const chklist = result.data;
:获取服务器返回的商品列表。
let innerHTML = ``;
:初始化一个字符串,用于构建订单列表的HTML内容。
for (let i = 0; i < chklist.length; i++) {
:遍历商品列表,为每个商品构建HTML表格行。
在循环内部,构建每个商品的HTML表格行,包括商品图片、描述、单价和数量。
也就是在引入的模态框中orderList元素的静态内容如下,在循环中做成动态的,获取每一个商品:
<tr>
<td class="p-2">
<img src="meal/pic?meal_pic=food01.jpeg" class="rounded"
style="width:100px;" />
td>
<td >
XXX
td>
<td class=" fs-5 text-danger">
¥50
td>
<td>
2
td>
tr>
document.querySelector("#orderList").innerHTML = innerHTML;
:将构建好的HTML表格行插入为 #orderList 元素的内容,显示订单列表。
document.querySelector("#orderInfo").innerHTML = ...
:更新订单信息,包括已选商品的数量和总价,也是用反引号拼接模态框中orderInfo元素的内容,获取动态数据。
orderModal.show();
:显示订单模态框,通常是一个弹出窗口,用于让用户确认订单详情。
整个函数的流程是:检查用户是否选择了商品,获取商品信息,构建订单列表和订单信息,最后显示订单模态框供用户确认。
关于购物车功能的实现,所以在CartServlet类中进行。依旧三步法,修改代码逻辑就好了。
增加路径 “/cart/chklist”,来调用新的方法:
@WebServlet({
"/cart/list",
"/cart/num",
"/cart/del",
"/cart/chklist"
})
相应的增加新的case子块:
case "/cart/chklist":
cartChkList(req,resp);
break;
最后实现调用的函数。
private void cartChkList(HttpServletRequest req, HttpServletResponse resp) throws IOException {
{
User user = (User) req.getSession().getAttribute("CurrUser");
if (user == null) {
MyWeb.printJson(resp, R.err("请先登录"));
return;
}
String[] mealIds = req.getParameterValues("meal_id");
if (mealIds == null || mealIds.length == 0) {
MyWeb.printJson(resp, R.err("请选择商品!"));
return;
}
String condition = Arrays.stream(mealIds).map(id -> "s.meal_id=" + id).collect(Collectors.joining(" or "));
List<ShoppingCart> list = DaoCreater.currentDao().queryBeanList(ShoppingCart.class, "select s.*, m.meal_desc,m.meal_pic,m.meal_price from t_shoppingcart s join t_meal m on s.meal_id = m.meal_id where u_id = ? and (" + condition + ")", user.getU_id());
MyWeb.printJson(resp, R.OK(list));
}
}
在函数中,代码也是异常的熟悉,主要流程是判断登录状态,判断商品选中状态,获取数据(参数),执行数据库操作,返回响应(包含数据信息)。
User user = (User) req.getSession().getAttribute("CurrUser");
:从HTTP请求的会话中获取当前登录的用户对象。
if (user == null) {
:检查用户是否已经登录。如果用户未登录,返回一个错误信息,并终止方法的执行。
String[] mealIds = req.getParameterValues("meal_id");
:从HTTP请求中获取名为 meal_id 的参数值,这个参数通常是由前端发送的,包含了用户想要查询的商品ID。
4. if (mealIds == null || mealIds.length == 0) {
:检查是否有商品ID被发送。如果没有,返回一个错误信息,并终止方法的执行。
String condition = Arrays.stream(mealIds).map(id -> "s.meal_id=" + id).collect(Collectors.joining(" or "));
:将商品ID数组转换为SQL查询条件字符串,用于后续的数据库查询。每个ID都被转换成 s.meal_id=某个ID 的形式,并且使用 or 连接,以便查询任何一个匹配的商品。关于这行代码,在上一篇文章中有更详细的解释,这里就不在重复解释了。
List
:使用DAO(Data Access Object)模式查询数据库,获取购物车中的商品信息。查询包括购物车表 t_shoppingcart 和商品表 t_meal 的连接查询,条件是用户ID和商品ID。
MyWeb.printJson(resp, R.OK(list));
:将查询结果包装在一个响应对象中,并以JSON格式发送回客户端。
打这里购物车下订单操作就完成了。
用户选择商品点击下订单,会跳出模态框让用户确认,在模态框中进行支付然后加到订单页面中去,数据库中数据也会对应变化。
模态框中的操作在下一篇文章中进行…