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

🎉🎉欢迎来到我的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.mzph.cn/news/596062.shtml

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

相关文章

大创项目推荐 深度学习卷积神经网络垃圾分类系统 - 深度学习 神经网络 图像识别 垃圾分类 算法 小程序

文章目录 0 简介1 背景意义2 数据集3 数据探索4 数据增广(数据集补充)5 垃圾图像分类5.1 迁移学习5.1.1 什么是迁移学习&#xff1f;5.1.2 为什么要迁移学习&#xff1f; 5.2 模型选择5.3 训练环境5.3.1 硬件配置5.3.2 软件配置 5.4 训练过程5.5 模型分类效果(PC端) 6 构建垃圾…

网络通信(9)-C#TCP服务端实例

本文使用Socket在C#语言环境下完成TCP服务端的实例。 实例完成的功能: 服务器能够连接多个客户端显示在列表中,实现实时刷新。 服务器接收客户端的字符串数据。 选中列表中的客户端发送字符串数据。 在VS中创建C# Winform项目,编辑界面,如下: UI文件 namespace MyTc…

多元线性回归案例--客户价值模型

文章目录 step 1&#xff1a;读取数据step 2&#xff1a;搭建模型step 3&#xff1a;构造回归方程step 4&#xff1a;评估模型 利用多元线性回归模型可以根据多个因素来预测客户价值&#xff0c;当模型搭建完成后&#xff0c;便可对不同价值的客户采用不同的业务策略。 这里以信…

RuoYi-Cloud-Plus使用minio进行文件上传图片后无法预览解决_修改minio配置minio桶权限---SpringCloud工作笔记198

在文件管理的位置,发现刚刚上传的图片文件,会显示 预览图片失败 后来经过多方查看,发现是minio的配置的问题 可以从这里: 可以看到首先登录RuoYi-Cloud-Plus系统然后,打开文件管理页面可以看到,当上传了图片文件以后 显示文件展示中,文件预览失败,那么这个时候,去修改minio的配…

python识别验证码+灰度图片base64转换图片

一、为后面识别验证码准备 1、base64转换为图片&#xff0c;保存本地、并且置灰 上文中的base64,后面的就是包含Base64编码的PNG图像的字符串复制下来 import base64 from PIL import Image import io# 这里是你的Base64编码的字符串 base64_data "iVBORw0KGgoAAAANSUhE…

鸿鹄电子招投标系统:源码级别解析电子招投标的精髓

招投标管理系统是一个集门户管理、立项管理、采购项目管理、采购公告管理、考核管理、报表管理、评审管理、企业管理、采购管理和系统管理于一体的综合性应用平台。它适用于招标代理、政府采购、企业采购和工程交易等业务的企业&#xff0c;旨在提高项目管理的效率和质量。该系…

大数据HCIE成神之路之特征工程——特征选择

特征选择 1.1 特征选择 - Filter方法1.1.1 实验任务1.1.1.1 实验背景1.1.1.2 实验目标1.1.1.3 实验数据解析1.1.1.4 实验思路 1.1.2 实验操作步骤 1.2 特征选择 - Wrapper方法1.2.1 实验任务1.2.1.1 实验背景1.2.1.2 实验目标1.2.1.3 实验数据解析1.2.1.4 实验思路 1.2.2 实验操…

【Spring】19 AOP介绍及实例详解

文章目录 1. 定义1&#xff09;什么意思呢&#xff1f;2&#xff09;如何解决呢&#xff1f; 2. 基本概念1&#xff09;切面&#xff08;Aspect&#xff09;2&#xff09;切点&#xff08;Pointcut&#xff09;3&#xff09;通知&#xff08;Advice&#xff09;4&#xff09;连…

iOS 组件开发教程——手把手轻松实现灵动岛

1、先在项目里创建一个Widget Target 2、一定要勾选 Include live Activity&#xff0c;然后输入名称&#xff0c;点击完成既可。 3、在 Info.plist 文件中声明开启&#xff0c;打开 Info.plist 文件添加 NSSupportsLiveActivities&#xff0c;并将其布尔值设置为 YES。 4、我…

MySQL之四大引擎、建库建表以及账号管理

目录 一. 数据库存储引擎 1.1 存储引擎查看 1.2 InnoDB 1.3 MyISAM 1.4 MEMORY 1.5 ARCHIVE 二. 数据库管理 2.1 元数据库简介 2.2 元数据库分类 2.3 数据库的增删改查及使用&#xff1a; 2.4 MySQL库的权限 三. 数据表管理 3.1 三大范式 3.2 基本数据类型 3.2.1 优化原则 3…

这个方法可以让你把图片无损放大

随着数字技术的不断发展&#xff0c;照片无损放大已经成为了摄影领域中的一项重要技术。照片无损放大能够让摄影师在不损失细节和画质的情况下&#xff0c;将照片放大到更大的尺寸&#xff0c;从而让观众能够更加清晰地欣赏到照片中的每一个细节。 今天推荐的这款软件主要是通…

Mysql隔离级别MVCC多版本并发控制机制

欢迎大家关注我的微信公众号&#xff1a; 传送门&#xff1a;Mysql事务原理与优化 目录 概述 undo日志版本链与read view机制详解 深入浅出分析MVCC可见性算法的操作示例 关于readview和可见性算法的原理解释 总结 概述 在之前的文章中讲过&#xff0c;Mysql在可重…

基于Segformer实现PCB缺陷检测(步骤 + 代码)

导 读 本文主要介绍基于Segformer实现PCB缺陷检测 &#xff0c;并给出步骤和代码。 背景介绍 PCB缺陷检测是电子制造的一个重要方面。利用Segformer等先进模型不仅可以提高准确性&#xff0c;还可以大大减少检测时间。传统方法涉及手动检查&#xff0c;无法扩展且容易出错…

魏副业而战:手机副业新风口,短剧内容创作实操,日赚500+的创业指南

我是魏哥&#xff0c;与其躺平&#xff0c;不如魏副业而战&#xff01; 今天魏哥给大家分享一个短剧推广的副业项目。 有人会有疑惑&#xff0c;短剧推广是去年爆火的副业项目&#xff0c;现在操作是不是有点晚了。 这个大家不要有太多的顾虑。 恰恰相反&#xff0c;短剧推广…

【springboot项目】之秒杀项目常见问题(Seckill)

秒杀问题分为两部分&#xff1a;用户查看商品详情页、用户下单 项目简介&#xff1a; 模拟了高并发场景的商城系统&#xff0c;它具备秒杀功能&#xff0c;为了解决秒杀场景下的高并发问题。引入了 redis 作为缓存中间件&#xff0c;1.主要作用是缓存预热、预减库存等等。2.针…

新年话节能 电梯也减排

小伍恭祝大家2024年元旦快乐&#xff01;&#xff01; 目前&#xff0c;电梯的节能已经得到业界的广泛重视&#xff0c;积极推动相关的节能技术的实施&#xff0c;努力宣传和倡导规范的电梯的使用行为&#xff0c;将极大地改变我国电梯的耗能状况&#xff0c;为节能减排做出较大…

遥测终端机:数据世界的千里眼与顺风耳

在当今这个信息爆炸的时代&#xff0c;数据的重要性日益凸显。如何高效、准确地收集、传输和处理这些数据&#xff0c;成为了众多企业和研究机构关注的焦点。而遥测终端机&#xff0c;正是这样一种解决这一问题的强大工具。 遥测终端机&#xff0c;顾名思义&#xff0c;是一种…

JavaScript 基础(一)

实验需新建一个 test.html 文件&#xff0c;用于编写代码。后续的例子中&#xff0c;将不再提醒建立文件&#xff0c;大家根据个人需求自行创建对应的 html 文件&#xff0c;并完成代码练习&#xff1a; 首先来看看范例代码&#xff1a; <!doctype html> <html>&…

OpenAI API/Plus会员信用卡绑定付款方式经历

前言 9月25日起ChatGPT风控升级&#xff0c;428813的卡只可以支付Open ai API-key&#xff0c;直接订阅plus会被拒。部分用户将卡绑定美区Google pay使用app store进行订阅可以成功&#xff0c;如果您没有这两种支付方式&#xff0c;请您重新开一张534786的万事达美卡升级订阅…

光伏效果图是用什么软件建模设计的?

光伏效果图是展示光伏系统在建筑或地面上的外观和效果的图像。要创建这样的效果图&#xff0c;需要使用专业的建模和设计软件。那么&#xff0c;光伏效果图是用什么软件建模设计的呢&#xff1f; 鹧鸪云光伏设计软件&#xff1a;鹧鸪云是一款集开发、设计和施工为一体的设计软…