【电商项目实战】实现订单超时支付取消

🎉🎉欢迎来到我的CSDN主页!🎉🎉

🏅我是Java方文山,一个在CSDN分享笔记的博主。📚📚

🌟推荐给大家我的专栏《电商项目实战》。🎯🎯

👉点击这里,就可以查看我的主页啦!👇👇

Java方文山的个人主页

🎁如果感觉还不错的话请给我点赞吧!🎁🎁

💖期待你的加入,一起学习,一起进步!💖💖

请添加图片描述

前言

大家对电商购物应该都比较熟悉了,我们应该注意到,在下单之后,通常会有一个倒计时,如果超过支付时间,订单就会被自动取消。这个功能说难也不难,说简单但也足以难倒一大片人,今天我就为大家提供一种思路。

一、订单显示

我们在购物车页面点击结算的时候肯定还是没有直接让我们交钱的,是跳转一个订单确认页面,确认订单信息无误,选择收货地址支付方式等才会生成订单。

订单详情页面

<!DOCTYPE html>
<html><head lang="en"><#include "common/head.html"><link rel="stylesheet" type="text/css" href="css/public.css"/><link rel="stylesheet" type="text/css" href="css/proList.css" /><link rel="stylesheet" type="text/css" href="css/mygxin.css" /></head><body><!----------------------------------------order------------------><div class="head ding"><div class="wrapper clearfix"><div class="clearfix" id="top"><h1 class="fl"><a href="${ctx}/"><img src="img/logo.png"/></a></h1><div class="fr clearfix" id="top1"><form action="#" method="get" class="fl"><input type="text" placeholder="搜索" /><input type="button" /></form></div></div></div></div><!-----------------site-------------------><div class="order cart mt"><div class="site"><p class="wrapper clearfix"><span class="fl">订单确认</span><img class="top" src="img/temp/cartTop02.png"></p></div><!-----------------orderCon-------------------><div class="orderCon wrapper clearfix"><div class="orderL fl"><!--------h3----------------><h3>收件信息<a href="#" class="fr">新增地址</a></h3><!--------addres----------------><div class="addres clearfix"><div class="addre fl on"><div class="tit clearfix"><p class="fl">张三1<span class="default">[默认地址]</span></p><p class="fr"><a href="#">删除</a><span>|</span><a href="#" class="edit">编辑</a></p></div><div class="addCon"><p>河北省&nbsp;唐山市&nbsp;路北区&nbsp;大学生公寓村</p><p>15732570937</p></div></div><div class="addre fl"><div class="tit clearfix"><p class="fl">张三2</p><p class="fr"><a href="#" class="setDefault">设为默认</a><span>|</span><a href="#">删除</a><span>|</span><a href="#" class="edit">编辑</a></p></div><div class="addCon"><p>河北省&nbsp;唐山市&nbsp;路北区&nbsp;大学生公寓村</p><p>15732570937</p></div></div><div class="addre fl"><div class="tit clearfix"><p class="fl">张三3</p><p class="fr"><a href="#" class="setDefault">设为默认</a><span>|</span><a href="#">删除</a><span>|</span><a href="#" class="edit">编辑</a></p></div><div class="addCon"><p>河北省&nbsp;唐山市&nbsp;路北区&nbsp;大学生公寓村</p><p>15732570937</p></div></div></div><h3>支付方式</h3><!--------way----------------><div class="way clearfix"><img class="on" value="0" src="img/temp/way01.jpg"><img value="1" src="img/temp/way02.jpg"><img value="2" src="img/temp/way03.jpg"><img value="3" src="img/temp/way04.jpg"></div><h3>选择快递</h3><!--------dis----------------><div class="dis clearfix"><span class="on">顺风快递</span><span>百世汇通</span><span>圆通快递</span><span>中通快递</span></div></div><div class="orderR fr"><div class="msg"><h3>订单内容<a href="${ctx}/cart/getCart" class="fr">返回购物车</a></h3><#--定义商品总价--><#assign sumnum=0><#--遍历商品信息--><#if item??><#list item as g><ul class="clearfix"><li class="fl"><img src="${g.goodsImg}" style="width: 100px;height: 100px"></li><li class="fl"><p>${g.goodsTitle}</p><p>${g.goodsName}</p><p>数量:${g.num}</p><#assign xiaoji=g.num*g.goodsPrice></li><li class="fr">¥${g.goodsPrice}</li></ul><#assign sumnum=sumnum+xiaoji></#list></#if></div><!--------tips----------------><div class="tips"><p><span class="fl">商品金额:</span><span class="fr">¥${sumnum}</span></p><p><span class="fl">优惠金额:</span><span class="fr">¥0.00</span></p><p><span class="fl">运费:</span><span class="fr">免运费</span></p></div><!--------tips count----------------><div class="count tips"><p><span class="fl">合计:</span><span class="fr">¥${sumnum}</span></p></div><!--<input type="button" name="" value="去支付"> --><a href="javascript:void(0);" class="pay">去支付</a></div></div></div><!--编辑弹框--><!--遮罩--><div class="mask"></div><div class="adddz editAddre"><form action="#" method="get"><input type="text" placeholder="姓名" class="on" /><input type="text" placeholder="手机号" /><div class="city"><select name=""><option value="省份/自治区">省份/自治区</option></select><select><option value="城市/地区">城市/地区</option></select><select><option value="区/县">区/县</option></select><select><option value="配送区域">配送区域</option></select></div><textarea name="" rows="" cols="" placeholder="详细地址"></textarea><input type="text" placeholder="邮政编码" /><div class="bc"><input type="button" value="保存" /><input type="button" value="取消" /></div></form></div><!--返回顶部--><input type="hidden" id="gids" value="${RequestParameters['gids']!}"/><#include "common/footer.html"><script src="js/others/order.js" type="text/javascript" charset="utf-8"></script><script src="js/public.js" type="text/javascript" charset="utf-8"></script><script src="js/pro.js" type="text/javascript" charset="utf-8"></script><script src="js/user.js" type="text/javascript" charset="utf-8"></script></body>
</html>

1.前端代码 

首先我们为结算按钮设置点击事件

$(".count").click(function (){//拿到所有选中的商品idlet ids=[];$(".th input[type='checkbox']:checked").each(function(j){//获取单条数据上面的gid属性let gid=$(this).attr('data-gid');ids.push(gid)})ids=ids.join(",")//将商品数据发送到后端location.href="/cart/getOrder?ids="+ids;})

2.后端代码 

 拿到选中需要结算的商品后需要先去Redis中将对应的商品拿出来

// 查询用户结算的购物车商品List<GoodsVo> loadCart(User user,List<String> ids);
 @Overridepublic List<GoodsVo> loadCart(User user, List<String> ids) {HashOperations<String,String,GoodsVo> operations=redisTemplate.opsForHash();String bigKey=Constants.REDIS_CART_PREFIX + user.getId();//根据用户Id查询结算的购物车商品List<GoodsVo> goodsVos = operations.multiGet(bigKey, ids);return goodsVos;}

这里拿出来的商品只有商品id和数量所以还需要拿到数据库做比较

    @RequestMapping("/getOrder")public String getOrder(User user, String ids, Model model) {//根据用户查询结算购物车商品List<String> ds = (List<String>) Arrays.asList(ids.split(","));List<GoodsVo> item = redisService.loadCart(user,ds);//根据商品Id查询对应商品List<Integer> gds = item.stream().map(GoodsVo::getGid).collect(Collectors.toList());if (gds.size() > 0) {List<Goods> goods = goodsService.listByIds(gds);
//        进行遍历筛选合适的数据for (Goods g : goods) {//找到对应属性的商品for (GoodsVo gv : item) {if (g.getGid() == gv.getGid()) {BeanUtils.copyProperties(g, gv);}}}}model.addAttribute("item", item);return "order";}

3.数据显示 

最后在前端显示相应的数据即可

//订单详情页面部分代码<#--定义商品总价--><#assign sumnum=0><#--遍历商品信息--><#if item??><#list item as g><ul class="clearfix"><li class="fl"><img src="${g.goodsImg}" style="width: 100px;height: 100px"></li><li class="fl"><p>${g.goodsTitle}</p><p>${g.goodsName}</p><p>数量:${g.num}</p><#assign xiaoji=g.num*g.goodsPrice></li><li class="fr">¥${g.goodsPrice}</li></ul><#assign sumnum=sumnum+xiaoji></#list></#if></div><!--------tips----------------><div class="tips"><p><span class="fl">商品金额:</span><span class="fr">¥${sumnum}</span></p><p><span class="fl">优惠金额:</span><span class="fr">¥0.00</span></p><p><span class="fl">运费:</span><span class="fr">免运费</span></p></div><!--------tips count----------------><div class="count tips"><p><span class="fl">合计:</span><span class="fr">¥${sumnum}</span></p></div>

效果展示: 

这里其他的东西除了商品以外都是定死的,包括收件信息(感兴趣的可以自行优化) 

 二、生成订单

1.表设计

生成订单前,我们先看一下订单表和订单详情表有什么表字段好去拿什么值。

t_orde(订单表

t_order_item(订单详情表

 2.前端取值

我们可以先对页面元素进行判断,拿取我们需要的元素

 这里我为选中的收件信息、支付方式、快递都添加了一个"on"样式,我们只需要根据标签层层抓取即可。

//生成订单
$(".pay").click(function (){let el=$(".addres").find(".on")let person= el.find(".tit .fl").text()let address= el.find(".addCon p:first-child").text()let telephone= el.find(".addCon p:last-child").text()let pay=$(".way .on").attr('value')let mail=$(".dis .on").text()let ids=$(this).attr('data-ids')let order={person,address,telephone,pay,mail,ids}console.log(order)
})

 打印结果没有问题,那么我们就可以向后端发起请求了

 我们把后面的请求写完

//生成订单
$(".pay").click(function (){let el=$(".addres").find(".on")let person= el.find(".tit .fl").text()let address= el.find(".addCon p:first-child").text()let telephone= el.find(".addCon p:last-child").text()let pay=$(".way .on").attr('value')let mail=$(".dis .on").text()let ids=$(this).attr('data-ids')let order={person,address,telephone,pay,mail,ids}// console.log(order)$.post('order/addOrder',order,resp=>{if(resp.code===200){alert("新增订单成功")}},'json')
})

2.后端处理

首先需要一个接收前端参数的Vo类

@Data
public class OrderVo  extends Order implements Serializable {private String ids;
}

 随后就可以开始编写我们的controller层代码

@RestController
@RequestMapping("/order")
public class OrderController {@Autowiredprivate IRedisService redisService;@Autowiredprivate IGoodsService goodsService;@Autowiredprivate IOrderItemService orderItemService;@Autowiredprivate IOrderService orderService;@RequestMapping("/addOrder")public JsonResponseBody<?> addOrder(User user, OrderVo vo) {//从Redis将数据查询出来String ids = vo.getIds();List<String> ds = Arrays.asList(ids.split(","));List<GoodsVo> item = redisService.loadCart(user, ds);//根据商品id到数据库查询商品详情//根据商品Id查询对应商品List<Integer> gds = item.stream().map(GoodsVo::getGid).collect(Collectors.toList());if (gds.size() > 0) {List<Goods> goods = goodsService.listByIds(gds);
//        进行遍历筛选合适的数据for (Goods g : goods) {//找到对应属性的商品for (GoodsVo gv : item) {if (g.getGid() == gv.getGid()) {BeanUtils.copyProperties(g, gv);}}}}BigDecimal sumPrice= BigDecimal.valueOf(0);//保存商品总价long oid = YitIdHelper.nextId();//订单id//新增订单详情//订单项集合List<OrderItem> orderItems=new ArrayList<>();for (GoodsVo it : item) {//生成订单项OrderItem orderItem=new OrderItem();BeanUtils.copyProperties(it,orderItem);orderItem.setQuantity(it.getNum());orderItem.setOoid(YitIdHelper.nextId());orderItem.setGid(Long.valueOf(it.getGid()+""));orderItem.setOid(oid);//将订单项加入集合中orderItems.add(orderItem);BigDecimal sum= BigDecimal.valueOf(it.getNum()*Double.parseDouble((it.getGoodsPrice()+"")));//保存商品小计sumPrice.add(sum);}//为了反正sql过长可选择批量orderItemService.saveBatch(orderItems,5);//新增订单Order order=new Order();BeanUtils.copyProperties(vo,order);order.setTotal(sumPrice);order.setUserId(user.getId());order.setStatus(0);order.setOid(oid);order.setCreateDate(new Date());orderService.save(order);//删除购物车信息redisService.deleteCart(user,ds);return JsonResponseBody.success();}}

 将我们需要的参数一个一个注入进去即可下面实践一下

三、解决订单超时

我这里提供的解决办法是使用Redis,确认订单后将订单存入Redis设置有效期,有效期结束就将该订单的状态设置为已过期,如果用户在有效期内支付了订单,那么我们就删除Redis中的缓存数据

IRedisService

    //将订单信息放入Redisvoid saveOrder(String token, Order order);//根据用户查询未支付订单Order getOder(String token);//根据用户查询未支付订单void deleteOder(String token);

IRedisServiceImpl

    @Overridepublic void saveOrder(String token, Order order) {//将订单信息保存到RedisredisTemplate.opsForValue().set(Constants.REDIS_ORDER_PREFIX +token,order);//设置过期时间(过期自动删除)redisTemplate.expire(Constants.REDIS_ORDER_PREFIX + token, 1800, TimeUnit.SECONDS);}@Overridepublic Order getOder(String token) {return (Order) redisTemplate.opsForValue().get(Constants.REDIS_ORDER_PREFIX +token);}@Overridepublic void deleteOder(String token) {redisTemplate.delete(Constants.REDIS_ORDER_PREFIX +token);}

我们查看订单的时候具体controller代码如下

 @RequestMapping("/unpaidOrder")public String unpaidOrder(User user, Model model) {//根据用户拿到未支付订单List<Order> item = orderService.list(new QueryWrapper<Order>().eq("user_id", user.getId()).eq("status", 0));//在有效期未支付的查询出来,过期的做相应的处理List<Order> items = new ArrayList<>();for (Order order : item) {//将用户未支付的订单查询出来Order oders = redisService.getOder(order.getOid() + "");if (oders == null) {order.setStatus(6);} else {items.add(order);}}//清理过期订单orderService.updateBatchById(item);model.addAttribute("item", items);return "myorderq";}

 

请添加图片描述

到这里我的分享就结束了,欢迎到评论区探讨交流!!

💖如果觉得有用的话还请点个赞吧 💖

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/230404.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

客服智能管理系统是如何应用的

客服系统有很多种类&#xff0c;针对不同场景的客服使用的客服系统也不同&#xff0c;如有网店里的在线客服、实体店里的电话客服、网站上的在线客服、公共服务型的热线客服、售后服务客服等等。所谓客服智能管理系统就是一种可以把多个客服场景都管理起来的系统&#xff0c;提…

【Proteus仿真】【STM32单片机】超声波测距系统

文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用Proteus8仿真STM32单片机控制器&#xff0c;使用动态数码管、按键、HCSR04超声波、蜂鸣器模块等。 主要功能&#xff1a; 系统运行后&#xff0c;数码管显示超声波检测距离&#xff0c;当检测…

Vue中的计算属性与监听器

聚沙成塔每天进步一点点 ⭐ 专栏简介 Vue学习之旅的奇妙世界 欢迎大家来到 Vue 技能树参考资料专栏!创建这个专栏的初衷是为了帮助大家更好地应对 Vue.js 技能树的学习。每篇文章都致力于提供清晰、深入的参考资料,让你能够更轻松、更自信地理解和掌握 Vue.js 的核心概念和技…

面试题:你如何理解 System.out.println()?

文章目录 前言首先分析System源码&#xff1a;out源码分析println分析 前言 如果你能自己读懂System.out.println()&#xff0c;就真正了解了Java面向对象编程的含义。 面向对象编程即创建了对象&#xff0c;所有的事情让对象帮亲力亲为&#xff08;即对象调用方法&#xff09…

k Nearest Neighbour(KNN)建模

介绍&#xff1a; K最近邻&#xff08;K-Nearest Neighbors&#xff0c;KNN&#xff09;是一种基本的分类和回归算法。它的基本思想是对未知样本进行预测时&#xff0c;先找到训练数据集中与该样本最近的K个样本&#xff0c;然后根据这K个样本的标签进行预测。 KNN模型的基本步…

神经网络的核心:帮助新手理解 PyTorch 非线性激活函数

目录 torch.nn子函数非线性激活详解 nn.Softmin Softmin 函数简介 函数工作原理 参数详解 使用技巧与注意事项 示例代码 nn.Softmax Softmax 函数简介 函数工作原理 参数详解 使用技巧与注意事项 示例代码 nn.Softmax2d Softmax2d 函数简介 函数工作原理 输入…

Python 自学(四) 之元组字典与集合

目录 1. 列表&#xff0c;元组&#xff0c;字典与集合的区别 2. 元组的创建和删除 tuple() del P101 3. 单个元素的元组 P102 4. 元组元素的修改 P106 5. 元组的使用场景 6. 字典的创建和删除 dict() zip() : del clear() P1…

金融中IC和IR的定义

当谈到金融领域时&#xff0c;IC&#xff08;Information Coefficient&#xff09;和IR&#xff08;Information Ratio&#xff09;通常是用来评估投资组合管理绩效的指标。它们都涉及到投资者对信息的利用和管理的效果。 信息系数&#xff08;IC - Information Coefficient&a…

Spring高手之路-Spring中Bean的五大作用域

目录 Singleton&#xff08;单例&#xff09;&#xff1a;默认的作用域 Prototype&#xff08;原型&#xff09; Request&#xff08;请求&#xff09; Session&#xff08;会话&#xff09; Global Session&#xff08;全局会话&#xff09; 五大作用域范围对比 作用域…

计算机毕业设计——SpringBoot 招投标 任务发布网站(附源码)

1&#xff0c;绪论 在市场范围内&#xff0c;任务发布网站很受欢迎&#xff0c;有很多开发者以及其他领域的牛人&#xff0c;更倾向于选择工作时间、工作场景更自由的零工市场寻求零散单子来补贴家用。 如今市场上&#xff0c;任务发布网站鱼龙混杂&#xff0c;用户需要找一个…

获取CNN/DM适用于评估Bart的格式的数据集(类似于test.source、test.source.tokenized)

项目场景&#xff1a; 复现文本摘要任务评估CNN/DM数据集 问题描述 abisee老哥的代码获取的是bin格式的数据集 时间久远&#xff0c;一些依赖的配置版本难以复现 笔者需要能评估Bart 格式的数据集 形式类似于test.source、test.source.tokenized 解决方案&#xff1a; 经过坚…

霹雳吧啦Wz《pytorch图像分类》-p5ResNet网络

《pytorch图像分类》p5ResNet网络结构 1 网络中的亮点1.1 超深的网络结构1.2 residual模块1.3 Batch Normalization1.4 迁移学习简介 2 模块类代码2.1 BasicBlock&#xff08;18 & 32 layers&#xff09;2.2 Bottleneck&#xff08;50 & 101 & 152 layers&#xff…

vue-cli创建项目时由esLint校验导致报错或警告的问题及解决

vue-cli创建项目时由esLint校验导致报错或警告的问题及解决 一、万能办法 一、万能办法 //就是在报错的JS文件中第一行写上 /* eslint-disable */链接: https://www.yii666.com/blog/288808.html 其它的方法我遇见了再补充

docker的安装的详细教程,以及出现错的解决办法(阿里云)

docker的安装与使用 1.安装dnf sudo yum -y install dnf Repository extras is listed more than once in the configuration 错误&#xff1a;无法为仓库 appstream 找到一个有效的 baseurl 出现这个错误这是由于阿里云的版本导致的 在阿里云开发者社区有答案&#xff01…

什么是软件安全性测试?如何进行安全测试?

一、什么是软件安全性测试&#xff1f; 软件安全性测试是指对软件系统中的安全漏洞进行检测和评估的过程。其目的是为了确保软件系统在面对各种安全威胁时能够保持其功能的完整性、可用性和机密性。 二、软件安全性测试可以通过以下几个步骤来进行&#xff1a; 1. 需求分析&a…

Django 学习教程- Hello world入门案例

系列 Django 学习教程-介绍与安装-CSDN博客 欢迎来到第Djagno学习教程第二章Hello World 入门案例。 在本教程中&#xff0c;我将引导您完成django的Hello World入门案例。 让我们开始吧&#xff01; 版本 Django 5.0Python 3.10 创建项目 安装 Django 之后&#xff0…

数字孪生与物联网(IoT)技术的结合

数字孪生与物联网&#xff08;IoT&#xff09;技术的结合可以在多个领域实现更智能、更高效的应用。以下是数字孪生在物联网技术中的一些应用&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流合作。 1.实时监…

把苹果手机上的备忘录转为长图片,分享给别人方法教程

在这个信息爆炸的时代&#xff0c;手机备忘录几乎成了我随身携带的“记忆宝库”。每当我脑海中闪现出一个想法、灵感或是需要记住的重要事项&#xff0c;我都会第一时间打开苹果手机的备忘录&#xff0c;将它们一一记录下来。备忘录的简洁界面和高效操作总能让我在忙碌的生活中…

gradle --腾讯国内镜像源

distributionUrlhttps\://mirrors.cloud.tencent.com/gradle/gradle-7.3.3-bin.zip 1.进入到自己工程目录下的wrapper文件夹。 2.编辑gradle-wrapper文件 使用https://mirrors.cloud.tencent.com/gradle/gradle-4.6-all.zip来代替原来的 https\://services.gradle.org/distri…

CDD文件的制作

CDD文件 1、核查诊断调查表2、制作CDD3、Diva测试 1、核查诊断调查表 ECU级别&#xff1a;包括文档相关、控制器的诊断ID和时间参数&#xff0c;支持的服务&#xff0c;DTC、DID、刷写流程。 2、制作CDD 2.1、cddt编辑思路&#xff08;每一步都要根据调查表进行操作&#xf…