一、客户端轮询
<script>
function getMiaoshaResult(goodsId){//做一个查询 

 g_showLoading();//加载中 

 $.ajax({ 

 url: '/miaosha/result',  // 
调用后台轮询功能的接口 

 type: "GET", 

 data: {//post提交表单的时候,url参数可以放在data中 

 goodsId: goodsId 

 //goodsId: $("#goodsId").val() 

 }, 

 success:function(data){//成功的时候会有一个回调,data是返回的数据,该数据应该是一个对象类型,或字典类型 

 var result = data.data; 

 if(data.code == 0){ 

 if(result > 0){//秒杀成功 

 layer.confirm("秒杀成功,查看订单?",{btn: ["确定","取消"]}, 

 function(){ 

 window.location.href="/order_detail.htm?orderId=" + result; 

 },function(){ 

 layer.closeAll(); 

 } 

 ); 

 }else if(result == 0){//排队中 

 //继续轮询 

 setTimeout(getMiaoshaResult(goodsId),50);//50毫秒 

 }else{//秒杀失败 

 layer.msg("秒杀失败"); 

 } 

 }else{ 

 layer.msg(data.msg); 

 } 

 }, 

 error:function(){ 

 layer.msg("客户端请求有误"); 

 } 

 }); 

} 



function doMiaosha(){//秒杀的时候,需要向服务端传递参数 

  

 $.ajax({ 

 url: '/miaosha/do_miaosha',  // 
调用后台的实现秒杀功能的接口 

 type: "POST", 

 data: { 

 goodsId: $("#goodsId").val() 

 }, 

 success:function(data){//成功的时候会有一个回调,data是返回的数据,该数据应该是一个对象类型,或字典类型 

 if(data.code == 0){ 

 /* render(data.data);//这里需要一个渲染页面的函数 render */ 

 //window.location.href="/order_detail.htm?orderId=" + data.data.id; 

  
getMiaoshaResult($("#goodsId").val()); 

 }else{ 

 layer.msg(data.msg); 

 } 

 }, 

 error:function(){ 

 layer.msg("客户端请求有误"); 

 } 

 }); 

}
二、后台接口
后台的实现秒杀功能的接口:
@RequestMapping(value="/do_miaosha", method=RequestMethod.POST) 
 @ResponseBody
    public Result<Integer> miaosha(MiaoshaUser user, @RequestParam("goodsId")long goodsId) {
 //RequestParam可以把保单隐含提交的input标签对应name属性的元素取出
 if(user == null){
 return Result.error(CodeMsg.SESSION_ERROR);
 }
 //判断内存标记
 boolean over = isOverMap.get(goodsId);
 if(over){
 return Result.error(CodeMsg.MIAO_SHA_OVER);
 }
 
 //预减库存
 long stock = redisService.decr(GoodsKey.getMiaoshaGoodsStock, "" + goodsId);
 if(stock < 0){
 isOverMap.put(goodsId, true);
 return Result.error(CodeMsg.MIAO_SHA_OVER);
 }
 //判断是否已经进行了秒杀
 MiaoshaOrder miaoshaOrder = orderService.getMiaoshaOrderByUserIdGoodsId(user.getId(),goodsId);
 if(miaoshaOrder != null){
 return Result.error(CodeMsg.REPEAT_MIAOSHA);
 }
 //入队
 MiaoshaMessage mm = new MiaoshaMessage();
 mm.setMiaoshaUser(user);
 mm.setGoodsId(goodsId);
 sender.sendMiaoshsaMessage(mm);
 return Result.success(0); }
后台轮询功能的接口:
/*
 
  
 * orderId: 成功
  * -1   : 秒杀失败
  * 0 : 还在排队 

  * */ 

 @RequestMapping(value="/result", method=RequestMethod.GET) 

 @ResponseBody 

    public Result<Long> result(MiaoshaUser user, @RequestParam("goodsId")long goodsId) { 

 //RequestParam可以把保单隐含提交的input标签对应name属性的元素取出 

 if(user == null){ 

 return Result.error(CodeMsg.SESSION_ERROR); 

 } 

 //根据result的三种数值范围,来判断下一步的操作 

 long result = miaoshaService.getMiaoshaResult(user.getId(), goodsId); 

 return Result.success(result); 

 }
MiaoshaService:
 @Transactional
 public OrderInfo miaosha(MiaoshaUser user, GoodsVo goodsVo) {
 //减库存(减miaosha_goods的库存), 写入秒杀订单
 boolean success = goodsService.reduceStock(goodsVo);
 if(success){
 //下订单, 包含两步:一、order_info  二、miaosha_order  实际上是两步操作
 return orderService.createOrder(user, goodsVo);
 }else{//商品已经被秒杀完了
 setGoodsOver(goodsVo.getId());
 return null;
 }
 }
 public long getMiaoshaResult(Long userId, long goodsId) {
 MiaoshaOrder order = orderService.getMiaoshaOrderByUserIdGoodsId(userId, goodsId);
 if(order != null){//说明本次查询的时候,已经秒杀成功了
 return order.getOrderId();
 }else{
 boolean isOver = getGoodsOver(goodsId);
 if(isOver){
 return -1; //代表卖完了
 }else{
 return 0; //继续轮询
 }
 } }
 private void setGoodsOver(Long id) {
 redisService.set(MiaoshaKey.isGoodsOver, "" + id, true);
 }
 private boolean getGoodsOver(long goodsId) {
 return redisService.exists(MiaoshaKey.isGoodsOver, "" + goodsId);
 }三、出队
@RabbitListener(queues=MQConfig.MIAOSHA_QUEUE)
 public void receiverMiaosha(String message){
 logger.info("receiver message: " + message);在接收消息的时候,就可以将字符串转换为对象了,然后对对象进行处理
 MiaoshaMessage miaoshaMessage = RedisService.stringToBean(message, MiaoshaMessage.class);
 MiaoshaUser user = miaoshaMessage.getMiaoshaUser();
 long goodsId = miaoshaMessage.getGoodsId();
 //收到消息之后做的事情和controller做的事情是一样的
 GoodsVo goodsVo = goodsService.getOneGoodsVoById(goodsId);
 int stockCount = goodsVo.getStockCount();
 if(stockCount <= 0){
 return;
 }
 //防止一个人秒杀多个商品,判断是否已经秒杀到了  ==> 到OrderService中去查找(查找生成的秒杀类型的订单,这种订单必须是一个用户和一个特价商品关联产生的,且每个用户只能产生一个)
 MiaoshaOrder miaoshaOrder = orderService.getMiaoshaOrderByUserIdGoodsId(user.getId(),goodsId);
 if(miaoshaOrder != null){
 return;
 }
 //减库存,下(写)订单,写入秒杀订单(需要在一个事物当中去做,搞一个service,做一个MiaoshaService,然后进行一个Transaction操作)
 OrderInfo orderInfo = miaoshaService.miaosha(user, goodsVo);//为什么成功了以后要返回订单呢?因为我们想秒杀成功之后直接进入到订单详情页
 //把订单的详细信息写入到我们的页面上
 //return Result.success(orderInfo);
 }