京东秒杀之秒杀实现

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.hqwc.cn/news/234799.html

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

相关文章

three.js结合vue

作者&#xff1a;baekpcyyy&#x1f41f; 1.搭建环境 ps&#xff1a;这里要按照node.js在之前有关vue搭建中有介绍 新建文件夹并在vsc终端中打开 1.输入vite创建指令 npm init vitelatest然后我们cd进入刚才创建的目录下 npm install安装所需依赖 npm run dev启动该项目 …

【Java案例】用户登录注册

案例介绍&#xff1a; 编写程序实现简单的用户登录注册功能。程序包含以下4个功能&#xff1a; &#xff08;1&#xff09;登录功能&#xff0c;用户输入正确的账号密码登录成功&#xff1b; &#xff08;2&#xff09;注册功能&#xff0c;输入用户名和密码进行注册&#x…

【C++】异常处理 ② ( 异常捕获类型 | 异常捕获机制 - 严格匹配异常类型 | 未知异常捕获 - 不知道异常类型 )

文章目录 一、异常捕获机制 - 严格匹配异常类型1、异常捕获机制 - 严格匹配异常类型2、代码示例 - 异常捕获严格匹配异常类型 二、异常捕获机制 - 未知异常捕获1、未知异常捕获 - 不知道异常类型2、代码示例 - 未知异常捕获 一、异常捕获机制 - 严格匹配异常类型 1、异常捕获机…

[vue3] 使用 vite 创建vue3项目的详细流程

一、vite介绍 Vite&#xff08;法语意为 “快速的”&#xff0c;发音 /vit/&#xff0c;发音同 “veet”) 是一种新型前端构建工具&#xff0c;能够显著提升前端开发体验&#xff08;热更新、打包构建速度更快&#xff09;。 二、使用vite构建项目 【学习指南】学习新技能最…

3dsMax插件Datasmith Exporter安装使用方法

3dsMax插件Datasmith Exporter安装使用方法 某些文件格式无法用Datasmith直接导入虚幻引擎&#xff0c;这些数据必须先被转换为Datasmith能够识别的文件格式。Datasmith Exporter插件就可以帮助您的软件导出可以被Datasmith导入虚幻引擎的.udatasmith格式文件。 在开始使用虚幻…

css 字体倾斜

css 字体倾斜 //左右倾斜 transform: skew(40deg, 0deg);//上下倾斜 transform: skew(0deg, 16deg);

在Rust中编写自动化测试

1.摘要 Rust中的测试函数是用来验证非测试代码是否是按照期望的方式运行的, 测试函数体通常需要执行三种操作:1.设置任何所需的数据或状态;2.运行需要测试的代码;3.断言其结果是我们所期望的。本篇文章主要探讨了Rust自动化测试的几种常见场景。 2.测试函数详解 在Rust项目工…

JUC并发编程 01——多线程基础知识

一.线程应用 异步调用 以调用方角度来讲&#xff0c;如果 需要等待结果返回&#xff0c;才能继续运行就是同步 不需要等待结果返回&#xff0c;就能继续运行就是异步 应用 比如在项目中&#xff0c;视频文件需要转换格式等操作比较费时&#xff0c;这时开一个新线程处理视…

C/C++ 实现FTP文件上传下载

FTP&#xff08;文件传输协议&#xff09;是一种用于在网络上传输文件的标准协议。它属于因特网标准化的协议族之一&#xff0c;为文件的上传、下载和文件管理提供了一种标准化的方法&#xff0c;在Windows系统中操作FTP上传下载可以使用WinINet库&#xff0c;WinINet&#xff…

卡码网语言基础课 | 17. 判断集合成员

目录 一、 set 集合 二、 创建集合 2.1 引入头文件 2.2 创建 2.3 插入元素 2.4 删除元素 三、 find的用法 四、 实现基本解题 五、 延伸拓展 题目&#xff1a;编写一个程序&#xff0c;判断给定的整数 n 是否存在于给定的集合中。 输入描述&#xff1a; 有多组测试…

单点登录平台设计

1.基本介绍 1.1什么是单点登录 单点登录&#xff08;Single Sign-On&#xff0c;简称SSO&#xff09;是一种身份认证的解决方案&#xff0c;它允许用户只需一次登录即可访问多个应用程序或系统。在一个典型的SSO系统中&#xff0c;用户只需通过一次身份认证&#xff0c;就可以…

css新闻链接案例

利用html和css构建出新闻链接案例&#xff0c;使用渐变色做出背景色变化 background: linear-gradient(to bottom, rgb(137, 210, 251), rgb(238, 248, 254), white); 利用背景图片&#xff0c;调整位置完成 dd { height: 28px; line-height: 28px; background-image: url(./图…