内容:“商品秒杀”功能模块基于“商品详情”功能模块。对于该功能模块,其主要核心流程为:前端发起抢购请求,请求中会携带一些请求数据:等待秒杀Id和当前用户Id等数据;后端接口收到请求后,会执行一系列的判断和秒杀处理逻辑,最后将处理结果返回给前端。其中,后台接口的一系列判断和秒杀处理逻辑比较复杂,Debug将其画成如下流程图:从业务流程图可以看出,后台接口正在接收秒杀请求从前端用户来说,核心处理逻辑是:(1)首先判断当前用户是否抢购过商品,如果没有,则说明用户没有抢购过商品,可以进入下一个处理逻辑(2)判断商品是否可以抢购剩余数量,即库存是否充足(即是否大于0),如果是则进入下一步处理逻辑(3)扣除库存,并更新数据库中抢购记录对应的库存(一般减去一次操作),判断数据库更新库存操作是否成功,如果成功则创建一个成功订单供用户秒杀,以及发简讯或邮件通知信息异步通知用户(4)如果上述操作逻辑中有哪一步不满足条件,则直接结束整个秒杀流程,即秒杀失败!接下来,我们还是基于MVC的开发模式,用实际的代码来实现这个功能模块!(1)首先在KillController控制器中开发接收“前端用户秒杀请求”的函数方法。其中,该方法需要接收前端请求的“等待秒杀Id”,当前用户的Id可以通过上一篇博文Shiro的会话模块Session来获取!其源码如下:privatestaticfinalStringprefix="kill";@AutowiredprivateIKillServicekillService;@AutowiredprivateItemKillSuccessMapperitemKillSuccessMapper;/****商品秒杀核心业务逻辑*/@RequestMapping(value=prefix+"/execute",method=RequestMethod.POST,consumes=MediaType.APPLICATION_JSON_UTF8_VALUE)@ResponseBodypublicBaseResponseexecute(@RequestBody@ValidatedKillDtodto,BindingResultresult,HttpSessionsession){if(result.hasErrors()||dto.getKillId()<=0){returnnewBaseResponse(StatusCode.InvalidParams);}//获取当前登录用户的信息ObjectuId=session.getAttribute("uid");if(uId==null){returnnewBaseResponse(StatusCode.UserNotLogin);}IntegeruserId=(Integer)uId;BaseResponseresponse=newBaseResponse(StatusCode.Success);try{Booleanres=killService.killItem(dto.getKillId(),userId);if(!res){returnnewBaseResponse(StatusCode.Fail.getCode(),"哈哈~商品已被抢购或不在抢购期!");}}catch(Exceptione){response=newBaseResponse(StatusCode.Fail.getCode(),e.getMessage());}returnresponse;}复制代码其中KillDto对象主要封装了“PendingseckillId”等字段信息,主要用于接收用户秒杀请求来自前端的信息,源码如下:@Data@ToStringpublicclassKillDtoimplementsSerializable{@NotNullprivateIntegerkillId;privateIntegeruserId;//集成shiro后,userId字段不用了!因为}复制代码(2)是通过session获取的,后面开发了killService.killItem(dto.getKillId(),userId)函数,该函数对应的代码编写逻辑编辑可以参考本文开头的流程图!其完整源码如下:@AutowiredprivateItemKillSuccessMapperitemKillSuccessMapper;@AutowiredprivateItemKillMapperitemKillMapper;@AutowiredprivateRabbitSenderServicerabbitSenderService;//处理商品秒杀的核心业务逻辑@OverridepublicBooleankillItem(IntegerkillId,TOegeruserId)throwsException/{Boolesean;当前商品if(itemKillSuccessMapper.countByKillUserId(killId,userId)<=0){//TODO:查询秒杀商品详情ItemKillitemKill=itemKillMapper.selectById(killId);//TODO:判断是否可以被秒杀秒杀canKill=1?if(itemKill!=null&&1==itemKill.getCanKill()){//TODO:扣除库存-减一intres=itemKillMapper.updateKillItem(killId);//TODO:是否扣除成功?是-生成秒杀成功命令,同时通知用户秒杀成功消息if(res>0){commonRecordKillSuccessInfo(itemKill,userId);result=true;}}}else{thrownewException("Youhavealready抢购此商品!”);}returnresult;}复制代码where,itemKillMapper.selectById(killId);表示用于秒级获取待售商品的详细信息,上一章介绍过;和itemKillMapper.updateKillItem(killId);主要用于扣除库存(这里是减1操作),对应的动态Sql如下:
