package com.seckill.dis.gateway.seckill;
import com.seckill.dis.common.api.cache.RedisServiceApi;
import com.seckill.dis.common.api.cache.vo.GoodsKeyPrefix;
import com.seckill.dis.common.api.cache.vo.OrderKeyPrefix;
import com.seckill.dis.common.api.cache.vo.SkKeyPrefix;
import com.seckill.dis.common.api.goods.GoodsServiceApi;
import com.seckill.dis.common.api.goods.vo.GoodsVo;
import com.seckill.dis.common.api.mq.MqProviderApi;
import com.seckill.dis.common.api.mq.vo.SkMessage;
import com.seckill.dis.common.api.order.OrderServiceApi;
import com.seckill.dis.common.api.seckill.SeckillServiceApi;
import com.seckill.dis.common.api.seckill.vo.VerifyCodeVo;
import com.seckill.dis.common.api.user.vo.UserVo;
import com.seckill.dis.common.domain.SeckillOrder;
import com.seckill.dis.common.result.CodeMsg;
import com.seckill.dis.common.result.Result;
import com.seckill.dis.common.util.MD5Util;
import com.seckill.dis.common.util.UUIDUtil;
import com.seckill.dis.common.util.VerifyCodeUtil;
import com.seckill.dis.gateway.config.access.AccessLimit;
import org.apache.dubbo.config.annotation.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 秒杀接口
*
* @author mata
*/
@Controller
@RequestMapping("/seckill/")
public class SeckillController implements InitializingBean {
private static Logger logger = LoggerFactory.getLogger(SeckillController.class);
@Reference(interfaceClass = RedisServiceApi.class)
RedisServiceApi redisService;
@Reference(interfaceClass = GoodsServiceApi.class)
GoodsServiceApi goodsService;
@Reference(interfaceClass = SeckillServiceApi.class)
SeckillServiceApi seckillService;
@Reference(interfaceClass = OrderServiceApi.class)
OrderServiceApi orderService;
@Reference(interfaceClass = MqProviderApi.class)
MqProviderApi sender;
/**
* 用于内存标记,标记库存是否为空,从而减少对redis的访问
*/
private Map<Long, Boolean> localOverMap = new HashMap<>();
/**
* 获取秒杀接口地址
* 1. 每一次点击秒杀,都会生成一个随机的秒杀地址返回给客户端
* 2. 对秒杀的次数做限制(通过自定义拦截器注解完成)
*
* @param model
* @param user
* @param goodsId 秒杀的商品id
* @param verifyCode 验证码
* @return 被隐藏的秒杀接口路径
*/
@AccessLimit(seconds = 5, maxAccessCount = 5, needLogin = true)
@RequestMapping(value = "path", method = RequestMethod.GET)
@ResponseBody
public Result<String> getSeckillPath(Model model, UserVo user,
@RequestParam("goodsId") long goodsId,
@RequestParam(value = "verifyCode") int verifyCode) {
/** 在执行下面的逻辑之前,会先对path请求进行拦截处理(@AccessLimit, AccessInterceptor),防止访问次数过于频繁,对服务器造成过大的压力 */
model.addAttribute("user", user);
if (goodsId <= 0) {
return Result.error(CodeMsg.SECKILL_PARM_ILLEGAL.fillArgs("商品id小于0"));
}
// 校验验证码
boolean check = this.checkVerifyCode(user, goodsId, verifyCode);
if (!check)
return Result.error(CodeMsg.VERITF_FAIL);// 检验不通过,请求非法
// 检验通过,获取秒杀路径
String path = this.createSkPath(user, goodsId);
// 向客户端回传随机生成的秒杀地址
return Result.success(path);
}
/* 压力测试时候注释掉 :验证码和秒杀地址隐藏 */
// /**
// * 秒杀逻辑(页面静态化分离,不需要直接将页面返回给客户端,而是返回客户端需要的页面动态数据,返回数据时json格式)
// * <p>
// * QPS:1306
// * 5000 * 10
// * <p>
// * GET/POST的@RequestMapping是有区别的
// * <p>
// * 通过随机的path,客户端隐藏秒杀接口
// * <p>
// * 优化: 不同于每次都去数据库中读取秒杀订单信息,而是在第一次生成秒杀订单成功后,
// * 将订单存储在redis中,再次读取订单信息的时候就直接从redis中读取
// *
// * @param model
// * @param user
// * @param goodsId
// * @param path 隐藏的秒杀地址,为客户端回传的path,最初也是有服务端产生的
// * @return 订单详情或错误码
// */
// // {path}为客户端回传的path,最初也是有服务端产生的
// @RequestMapping(value = "{path}/doSeckill", method = RequestMethod.POST)
// @ResponseBody
// public Result<Integer> doSeckill(Model model, UserVo user,
// @RequestParam("goodsId") long goodsId,
// @PathVariable("path") String path) {
// model.addAttribute("user", user);
// // 验证path是否正确
// boolean check = this.checkPath(user, goodsId, path);
// if (!check)
// return Result.error(CodeMsg.REQUEST_ILLEGAL);// 请求非法
// // 通过内存标记,减少对redis的访问,秒杀未结束才继续访问redis
// Boolean over = localOverMap.get(goodsId);
// if (over)
// return Result.error(CodeMsg.SECKILL_OVER);
// // 预减库存,同时在库存为0时标记该商品已经结束秒杀
// Long stock = redisService.decr(GoodsKeyPrefix.GOODS_STOCK, "" + goodsId);
// if (stock < 0) {
// localOverMap.put(goodsId, true);// 秒杀结束。标记该商品已经秒杀结束
// return Result.error(CodeMsg.SECKILL_OVER);
// }
// // 判断是否重复秒杀
// // 从redis中取缓存,减少数据库的访问
// SeckillOrder order = redisService.get(OrderKeyPrefix.SK_ORDER, ":" + user.getUuid() + "_" + goodsId, SeckillOrder.class);
// // 如果缓存中不存该数据,则从数据库中取
// if (order == null) {
// order = orderService.getSeckillOrderByUserIdAndGoodsId(user.getUuid(), goodsId);
// }
// if (order != null) {
// return Result.error(CodeMsg.REPEATE_SECKILL);
// }
// // 商品有库存且用户为秒杀商品,则将秒杀请求放入MQ
// SkMessage message = new SkMessage();
// message.setUser(user);
// message.setGoodsId(goodsId);
// // 放入MQ(对秒杀请求异步处理,直接返回)
// sender.sendSkMessage(message);
// // 排队中
// return Result.success(0);
// }
/**
* 秒杀逻辑(页面静态化分离,不需要直接将页面返回给客户端,而是返回客户端需要的页面动态数据,返回数据时json格式)
* <p>
* QPS:1117
* 5000 * 10
* <p>
* GET/POST的@RequestMapping是有区别的
* <p>
* 通过随机的path,客户端隐藏秒杀接口
* <p>
* 优化: 不同于每次都去数据库中读取秒杀订单信息,而是在第一次生成秒杀订单成功后,
* 将订单存储在redis中,再次读取订单信息的时候就直接从redis中读取
*
* @param model
* @param user
* @param goodsId
* @return 订单详情或错误码
*/
// 秒杀压力测试时接口
@RequestMapping(value = "doSeckill", method = RequestMethod.POST)
@ResponseBody
public Result<Integer> doSeckill( UserVo user,
@RequestPara
没有合适的资源?快使用搜索试试~ 我知道了~
温馨提示
【资源介绍】 基于SpringBoot+Zookeeper+Dubbo打造分布式高并发商品秒杀系统.zip基于SpringBoot+Zookeeper+Dubbo打造分布式高并发商品秒杀系统.zip基于SpringBoot+Zookeeper+Dubbo打造分布式高并发商品秒杀系统.zip基于SpringBoot+Zookeeper+Dubbo打造分布式高并发商品秒杀系统.zip基于SpringBoot+Zookeeper+Dubbo打造分布式高并发商品秒杀系统.zip基于SpringBoot+Zookeeper+Dubbo打造分布式高并发商品秒杀系统.zip基于SpringBoot+Zookeeper+Dubbo打造分布式高并发商品秒杀系统.zip基于SpringBoot+Zookeeper+Dubbo打造分布式高并发商品秒杀系统.zip基于SpringBoot+Zookeeper+Dubbo打造分布式高并发商品秒杀系统.zip基于SpringBoot+Zookeeper+Dubbo打造分布式高并发商品秒杀系统.zip基于SpringBoot+Zookeeper+Dubbo打造分布式高并发商品秒杀系统.zip 【备注】 该项目是个人毕设项目,答辩评审分达到95分,代码都经过调试测试,确保可以运行!欢迎下载使用,可用于小白学习、进阶。 该资源主要针对计算机、通信、人工智能、自动化等相关专业的学生、老师或从业者下载使用,亦可作为期末课程设计、课程大作业、毕业设计等。 项目整体具有较高的学习借鉴价值!基础能力强的可以在此基础上修改调整,以实现不同的功能。 欢迎下载,欢迎沟通,互相学习,共同进步!提供答疑!
资源推荐
资源详情
资源评论





















收起资源包目录





































































































共 146 条
- 1
- 2
资源评论


manylinux
- 粉丝: 5097
上传资源 快速赚钱
我的内容管理 展开
我的资源 快来上传第一个资源
我的收益
登录查看自己的收益我的积分 登录查看自己的积分
我的C币 登录后查看C币余额
我的收藏
我的下载
下载帮助


最新资源
- Gin 框架接口开发脚手架:集成数据库日志配置,Go 快速开发开箱即用
- HGIS输变电设备状态检修技术探讨.doc
- 基于网络时代的高校思想政治教育创新研究.docx
- 计算机基础和网络技术试题a.doc
- 高中信息技术与网络资源的有效对接.docx
- 《软件工程设计》课程设计分析报告.doc
- 2007年4月全国计算机二级ACCESS真题.pdf
- 论甲方工程项目管理要点分析.docx
- 基于Docker的容器化实践.pptx
- 软件开发团队的管理.ppt
- 年度电子商务C2C产业分析报告.docx
- 现代学徒制在中职计算机应用专业的应用.docx
- 基于高职移动通信技术原理与实训的课程改革.docx
- PLC方案设计书实例:小型SBR废水处理PLC电气控制系统课程方案设计书.doc
- 调度自动化实时系统与数字化变电站接入研究.docx
- 计算机网络信息安全防护策略探究.docx
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈



安全验证
文档复制为VIP权益,开通VIP直接复制
