京东秒杀之秒杀实现

1 登录判断

用户在未登录状态下可以查看商品列别以及秒杀商品详情,但不可以在未登录状态进行秒杀商品的操作,当用户点击开始秒杀时,进行登陆验证

<!DOCTYPE html>
<head><title>商品详情</title><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><script type="text/javascript" src="/js/jquery.min.js"></script><link rel="stylesheet" type="text/css" href="/bootstrap/css/bootstrap.min.css" /><!-- bootstrap --><script type="text/javascript" src="/bootstrap/js/bootstrap.min.js"></script><script type="text/javascript" src="/jquery-validation/jquery.validate.min.js"></script> <!-- jquery-validator --><script type="text/javascript" src="/jquery-validation/localization/messages_zh.min.js"></script><script type="text/javascript" src="/layer/layer.js"></script><!-- layer --><script type="text/javascript" src="/js/md5.min.js"></script><!-- md5.js --><script type="text/javascript" src="/js/common.js"></script><!-- common.js --><script type="text/javascript" src="/js/socket.js"></script><!-- common.js -->
</head>
<body>
<div class="panel panel-default"><div class="panel-heading">秒杀商品详情</div><div class="panel-body"><div id="userTip" style="display: none"><span> 您还没有登录,请<a href="/login.html">登陆</a>后再操作<br/></span></div><span>没有收货地址的提示。。。</span></div><table class="table"><tr><td>商品名称</td><td colspan="3" id="goodName"></td></tr><tr><td>商品图片</td><td colspan="3"><img id="goodImg"  width="200" height="200" /></td></tr><tr><td>秒杀开始时间</td><td id="startDate"></td><td id="seckillTip"></td><td><img id="verifyCodeImg" width="80" height="32"  onclick="initVerifyCodeImg()" style="display: none"><input id="verifyCode" style="display: none"><button class="btn btn-primary btn-block" type="button" id="buyButton" onclick="">立即秒杀</button></td></tr><tr><td>商品原价</td><td colspan="3" id="goodPrice"></td></tr><tr><td>秒杀价</td><td colspan="3" id="seckillPrice"></td></tr><tr><td>库存数量</td><td colspan="3" id="stockCount"></td></tr></table>
</div>
<script type="text/javascript">var seckillId;$(function () {seckillId = getQueryString("seckillId");initGood();initUser();});function initGood(){$(function () {$.ajax({url: "http://localhost:9000/seckill/seckillGood/find?seckillId="+seckillId,type: "get",xhrFields: {withCredentials: true}, //启用cookiesuccess:function (data) {if(data.code==200){//填充表格中的数据renderGood(data.data);}else{layer.msg(data.msg)}}});});}function renderGood(good) {$("#goodName").html(good.goodName);$("#goodImg").prop("src",good.goodImg);$("#startDate").html(good.startDate);$("#goodPrice").html(good.goodPrice);$("#stockCount").html(good.stockCount);$("#seckillPrice").html(good.seckillPrice);//调用时间renderDate(good.startDate,good.endDate);}//定义秒杀的三个阶段var timer;  //计时器//距离抢购开始还有多久var remainStartSeconds;//距离结束还有多久var remainEndSeconds;function renderDate(sDate,eDate) {var startTime = new Date(sDate);  // 2023-11-25 16:00var endTime = new Date(eDate);   // 2023-11-25 18:00var now = new Date();        // 2023-11-25 14:37remainStartSeconds=parseInt((startTime.getTime()-now.getTime())/1000);//秒remainEndSeconds=parseInt((endTime.getTime()-now.getTime())/1000);//秒timer=window.setInterval(showSeckillTip,1000);}function showSeckillTip() {remainStartSeconds--;remainEndSeconds--;if(remainStartSeconds>0){$("#seckillTip").html("距离本场秒杀开始还有"+remainStartSeconds+"秒");//禁用按钮$("#buyButton").prop("disabled",true);}else{if(remainEndSeconds>0){//秒杀中$("#seckillTip").html("秒杀进行中....");//禁用按钮$("#buyButton").prop("disabled",false);}else{$("#seckillTip").html("秒杀结束了");//禁用按钮$("#buyButton").prop("disabled",true);window.clearInterval(timer);//取消计时器}}}function initUser(){$(function () {$.ajax({url: "http://localhost:9000/member/token/getCurrent",type: "get",xhrFields: {withCredentials: true}, //启用cookiesuccess:function (data) {if(data.code==200){//填充表格中的数据renderUser(data.data);}else{layer.msg(data.msg)}}});});}var user;function renderUser(u){if(u){user=u;}else{//没有数据$("#userTip").show();}}</script>
</body>
</html>

1.1 编写前端登录判断

1.2 编写后端登录判断方法

1 编写sevice接口及其实现类方法


sevice接口

    public User getUserByToken(String token);

实现类

    /*** 根据token查询用户* @param token* @return*/@Overridepublic User getUserByToken(String token) {return myRedisTemplate.get(MemberServerKeyPrefix.USER_TOKEN, token, User.class);}

2 编写controller层方法

    /*** 获取当前用户* @param token 利用cookie中存储的token来判断用户* @return*/@GetMapping("/getCurrent")public Result<User> getCurrent(@CookieValue(value = CookieUtil.TOKEN_COOKIE_NAME, required = false) String token){User user = userService.getUserByToken(token);return Result.success(user);}

3 测试

2 后端登陆判断方法的优化

2.1 调整项目结构

1 添加依赖

2 将member-server下MemberServerKeyPrefix类移动至member-api下

3 将member-server下CookieUtil类移动至member-api下

4 编写getCookie方法

    /*** 获取cookie* @param request* @param tokenCookieName* @return*/public static String getCookie(HttpServletRequest request, String tokenCookieName) {Cookie[] cookies = request.getCookies();if (cookies != null && cookies.length > 0){for (Cookie cookie : cookies) {//找到cookieif (cookie.getName().equals(tokenCookieName)){return cookie.getValue();}}}return null;}

2.2 编写自定义SpringMVC参数解析器

public class UserMethodArgumentResolver implements HandlerMethodArgumentResolver {@Autowiredprivate MyRedisTemplate myRedisTemplate;/*** 判断参数类型是否为User* @param methodParameter* @return*/@Overridepublic boolean supportsParameter(MethodParameter methodParameter) {return methodParameter.getParameterType() == User.class &&methodParameter.getParameterAnnotation(RedisValue.class) != null;}/*** 自定义参数解析器* @param parameter* @param mavContainer* @param webRequest* @param binderFactory* @return* @throws Exception*/@Overridepublic Object resolveArgument(MethodParameter parameter,ModelAndViewContainer mavContainer,NativeWebRequest webRequest,WebDataBinderFactory binderFactory) throws Exception {//获取请求对象HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);//获取cookieString token = CookieUtil.getCookie(request, CookieUtil.TOKEN_COOKIE_NAME);if (StringUtils.isEmpty(token)){return null;}return myRedisTemplate.get(MemberServerKeyPrefix.USER_TOKEN, token, User.class);}}

2.3 编写配置类

@Configuration
public class WebConfig implements WebMvcConfigurer {//注入参数解析器@Autowiredprivate UserMethodArgumentResolver userMethodArgumentResolver;/*** 添加参数解析器* @param resolvers*/@Overridepublic void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {resolvers.add(userMethodArgumentResolver);}@Beanpublic UserMethodArgumentResolver userMethodArgumentResolver() {return new UserMethodArgumentResolver();}
}

2.4 编写自定义注解

@Target(ElementType.PARAMETER) //定义该注解应用于方法参数上
@Retention(RetentionPolicy.RUNTIME) //不仅保存在class中,JVM加载时也存在
public @interface RedisValue {}

2.5 编写登陆判断方法

    @RequestMapping("/getCurrent")public Result<User> getCurrent(@RedisValue User user){return Result.success(user);}

3 秒杀实现

实现流程:

    1. 判断用户是否登录
    1. 判断场次是否正常
    1. 根据秒杀的场次查出当前场次对应的秒杀商品
    1. 秒杀时间的问题 处于秒杀中才能抢购
    1. 判断用户是否已经参与过当前场次的抢购
    1. 判断库存是否足够
    1. 秒杀的原子性 【 做三件事 】
    • 7.1 商品的库存 -1 t_seckill_goods(生成抢购订单)
    • 7.2 创建商品的订单表 t_order_info(参与抢购的商品表)
    • 7.3 创建秒杀订单 t_seckill_order(防止用户重复抢购的表)

3.1 编写前端秒杀动作

3.2 调整项目结构

1 添加依赖

2 添加参数解析器的配置类

将member-server下的参数解析器的配置类复制到seckill-server下

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

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

相关文章

中兴亮相中国国际现代化铁路技术装备展览会 筑智铁路5G同行

近日&#xff0c;第十六届中国国际现代化铁路技术装备展览会在北京中国国际展览中心举办&#xff0c;中兴以“数智铁路&#xff0c;5G同行”主题亮相本次展览会&#xff0c;并全面展示了“数字铁路网络基础设施”、“云边结合的铁路行业云”、“数字铁路赋能赋智”等方面的最新…

市场调研:2023年SLG游戏行业需求及发展前景预测

SLG游戏(SLG游戏)一般指策略游戏&#xff0c;策略游戏是一种以取得各种形式胜利为主题的游戏。这类游戏提供给玩家一个可以动脑筋思考问题来处理较复杂事情的环境&#xff0c;允许玩家自由控制、管理和使用游戏中的人、或事物&#xff0c;通过这种自由的手段以及玩家们开动脑筋…

vue3播放音频

const audio ref(new Audio()) const voicePath ref()const playVoice () > {// 外部链接//voicePath.value https://mp3在线地址// 本地链接voicePath.value new URL(/assets/本地mp3文件, import.meta.url).hrefnextTick(() > {// 从头开始audio.value.currentTim…

定时器时钟

/* 1、按键可以调整当时时间 2、按键可以调节定时时间 3、定时时间到继电器吸合 *8位数码管显示 时间格式格式 12-08-00 标示12点08分00秒 S1 用于小时 加1操作 S2 用于分钟 加1操作 S2 用于分钟减1操作 */ #include <reg52.h> sbit KEY1P3^2; sbit KEY2P3^3; sbit …

java-HashMap、TreeMap、LinkedHashMap、ArrayList、LinkedList使用笔记

背景 Map<String, Integer> unsortedMap new HashMap<>(); unsortedMap.put("One", 1); unsortedMap.put("Two", 2); unsortedMap.put("Three", 3); unsortedMap.put("Four", 4); 一、关于排序 TreeMap&#…

【Linux篇】gdb调试器的使用

gdb调试器之常用指令 前言一 . 程序的两种发布模式二 . gdb调试器的使用1> 调用调试器进入调试环境2 > 退出调试3 > gdb中常用调试指令 前言 gdb作为Linux下一款好用且强队的调试工具&#xff0c; 支持对 C C go Java 等多种高级编程语言进行调试.对于在Linux下进行编…

智能优化算法应用:基于旗鱼算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于旗鱼算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于旗鱼算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.旗鱼算法4.实验参数设定5.算法结果6.参考文献7.MATLAB…

PyTorch模型训练过程内存泄漏问题解决

近日&#xff0c;在模型训练过程中&#xff0c;发现过一段时间后进程会被kill&#xff0c;观察发现是由于内存泄漏问题造成的。通过逐行代码注释&#xff0c;发现问题在于数据集中的此行代码&#xff1a; info self.data_list[index]这里&#xff0c;self.data_list是dataset…

传统算法:使用 Pygame 实现K-Means 聚类算法

使用 Pygame 模块演示了 K-Means 聚类算法的基本原理。让我逐步解释它的实现: 初始化和基本设置 Pygame 初始化: 通过 pygame.init() 初始化 Pygame。 定义颜色和屏幕大小: 定义了一些颜色常量(WHITE, BLACK, RED, GREEN, BLUE)和屏幕的宽度和高度。 创建 Pygame 窗口:…

[LeetCode] 380. O(1) 时间插入、删除、获取随机元素

380. O(1) 时间插入、删除和获取随机元素 labuladong 题解 实现RandomizedSet 类&#xff1a; RandomizedSet() 初始化 RandomizedSet 对象bool insert(int val) 当元素 val 不存在时&#xff0c;向集合中插入该项&#xff0c;并返回 true &#xff1b;否则&#xff0c;返回…

软件测试编写文档模板【附文档模板】

一、测试岗位必备的文档 在一个常规的软件测试流程中&#xff0c;会涉及到测试计划、测试方案、测试用例、测试报告的编写&#xff0c;这些文档也是软件测试岗位必须掌握的文档类型。 1、测试计划 测试计划是组织管理层面的文件&#xff0c;从组织管理的角度对一次测试活动进…

设计模式-创建型模式之工厂设计模式

文章目录 五、工厂方法六、抽象工厂 五、工厂方法 工厂方法&#xff0c;使用工厂可以像使用人员屏蔽对象创建的细节&#xff0c;使用者无需指定具体的类即可使用功能&#xff0c;达到信息隐蔽的作用&#xff0c;便于后期的维护&#xff0c;修改和扩展。 在看工厂方法前还有一…

华纳云:linux中怎么实现apache安装与配置

在 Linux 系统中&#xff0c;安装和配置 Apache HTTP 服务器通常涉及以下步骤。以下以 Ubuntu 为例&#xff0c;其他 Linux 发行版的步骤也大致相同。 步骤 1&#xff1a;安装 Apache 打开终端并运行以下命令&#xff1a; sudo apt update sudo apt install apache2 步骤 …

Java实现堆

堆是一种基于完全二叉树的数据结构&#xff0c;它分为大根堆和小根堆。在大根堆中&#xff0c;每个节点的值都大于或等于其子节点的值&#xff1b;而在小根堆中&#xff0c;每个节点的值都小于或等于其子节点的值。 在Java中&#xff0c;我们可以使用数组来表示堆。由于完全二…

网工内推 | 云计算运维,云相关认证优先,最高30K,带薪年假

01 安畅网络 招聘岗位&#xff1a;云计算运维工程师 职责描述&#xff1a; 1、负责对公有云平台的计算、存储、网络资源等IAAS/SAAS/PAAS层产品组件日常交付部署运维工作&#xff0c;包括调试、配置、维护、监控、优化等工作&#xff1b; 2、负责对操作系统及应用日常运行维护…

MySQL事务详解

MySQL事务详解 数据库事务概述事务是如何实现的事务的ACID特性事务的状态 事务的使用显式事务隐式事务示例自动提交回滚回滚到保存点 事务的隔离级别数据并发问题MySQL 支持的四种隔离级别注意示例 设置隔离级别 事务的常见分类 数据库事务概述 数据库事务是数据库管理系统&am…

《山水间的家》第二季收官,国台酒业解锁中国式浪漫

执笔 | 洪大大 编辑 | 萧 萧 近日&#xff0c;由国台酒特别支持的大型文旅探访节目《山水间的家》第二季在总台央视综合频道&#xff08;CCTV-1&#xff09;正式收官。 第二季节目以家庭为视角切入&#xff0c;先后走进江苏、四川、重庆、江西、湖北、贵州、浙江等地24个特色…

Python subprocess模块的高级玩法

Python的subprocess模块是一个非常强大的工具&#xff0c;用于启动和与外部进程进行交互。它允许执行外部命令、访问系统Shell、管道数据、捕获输出和错误信息&#xff0c;以及更多。 本文详细介绍 subprocess模块的各个方面&#xff0c;包括如何执行外部命令、传递参数、处理…

Redis安装和部署详细流程

文章目录 一、Windows环境下安装 Redis1.1 下载Redis1.2 启动redis服务器1.3 启动redis客户端1.4 配置环境变量 参考资料 一、Windows环境下安装 Redis windows系统环境下&#xff0c;redis安装方式主要有&#xff1a; zip压缩包方式 https://redis.io/download 或者 https:/…

MMdetection3.0 问题

MMdetection3.0 问题 希望各位路过的大佬指教一下&#xff1a; 问题&#xff1a; 1、NWPU-VHR-10有标注的数据一共650张&#xff0c;我将其分为了455张训练集&#xff0c;195张验证集。 2、然后使用MMdetection3.0框架中的Faster-rcnn网络进行训练&#xff0c;设置训练参数b…