目录
- 前言
- 第一次请求
- 第二次请求
- 第三次请求
- 后言
前言
书接上文,上面的两个章节后我们都知道秒杀的一个业务处理该如何去优化,
java代码优化方案3(redis预减库存,redis标记商品)
java代码优化方案4(Rabbitmq异步下单)
当然也仅仅就是后台对性能的一个优化,本次的话就是结合后台redis缓存的机制和前台多次请求来隐藏自己的接口。
怎么叫多次请求呢?其实就是你操作起来可能就一次请求,可实际上。。。
1、发送请求到后台动态获取一个地址(并redis保存),前台接收地址(path)。
2、在第一次请求成功后会调用第二次请求,第二次请求(我们上两章的内容)携带了path作为我们的路径(redis判断),等处理业务过后,虽然我们会知道后台是否处理成功,但是我们无法知道秒杀是否成功!!(Rabbitmq的原因)
3、第二次请求成功响应过后发送最后第三次请求,用来判断这个用户的这个商品是否成功秒杀
所以我会从三次请求来讲这个借口地址隐藏。
第一次请求
getMiaoshaPath
function getMiaoshaPath(){
var goodsId = $("#goodsId").val();
g_showLoading();
$.ajax({
url:"/miaosha/path",
type:"GET",
data:{
goodsId:goodsId,
verifyCode:$("#verifyCode").val()
},
success:function(data){
if(data.code == 0){
var path = data.data;
doMiaosha(path);
}else{
layer.msg(data.msg);
}
},
error:function(){
layer.msg("客户端请求有误");
}
});
}
getMiaoshaPath
/**第二阶段
* 生成秒杀地址,把秒杀的时间数字传过来
* @param request
* @param user
* @param goodsId
* @param verifyCode
* @return
*/
@RequestMapping(value="/path", method=RequestMethod.GET)
@ResponseBody
public Result<String> getMiaoshaPath(HttpServletRequest request, HttpServletResponse response, MiaoshaUser user,
@RequestParam("goodsId")long goodsId,
@RequestParam(value="verifyCode", defaultValue="0")int verifyCode
) {
if(user == null) {//判断用户是否有cookie
return Result.error(CodeMsg.SESSION_ERROR);
}
boolean check = miaoshaService.checkVerifyCode(user, goodsId, verifyCode);//(vc)判断这个验证码是否正确,获取redis中的数据
if(!check) {
return Result.error(CodeMsg.REQUEST_ILLEGAL);
}
String path =miaoshaService.createMiaoshaPath(user, goodsId);//(mp) 生成一个地址,并存储在redis中
return Result.success(path);
}
前台请求:
后台:
第二次请求
doMiaosha
function doMiaosha(path){
$.ajax({
url:"/miaosha/"+path+"/do_miaosha",
type:"POST",
data:{
goodsId:$("#goodsId").val()
},
success:function(data){
if(data.code == 0){
//window.location.href="/order_detail.htm?orderId="+data.data.id;
getMiaoshaResult($("#goodsId").val());
}else{
layer.msg(data.msg);
}
},
error:function(){
layer.msg("客户端请求有误");
}
});
}
miaosha
/**第二阶段
* QPS:1306
* 5000 * 10
* QPS: 2114
*
* 隐藏原有的秒杀地址
* */
@RequestMapping(value="/{path}/do_miaosha", method=RequestMethod.POST)
@ResponseBody
public Result<Integer> miaosha(HttpServletRequest request, HttpServletResponse response,
Model model,MiaoshaUser user,
@RequestParam("goodsId")long goodsId,
@PathVariable("path") String path) {
model.addAttribute("user", user);
if(user == null) {
return Result.error(CodeMsg.SESSION_ERROR);
}
//1、验证path
boolean check = miaoshaService.checkPath(user, goodsId, path);//(mp)判断传过来的地址,获取redis中的数据
if(!check){
return Result.error(CodeMsg.REQUEST_ILLEGAL);
}
//2、内存标记,减少redis访问
boolean over = localOverMap.get(goodsId);
if(over) {
return Result.error(CodeMsg.MIAO_SHA_OVER);
}
//3、预减库存
long stock = redisService.decr(GoodsKey.getMiaoshaGoodsStock, ""+goodsId);//10
if(stock < 0) {
localOverMap.put(goodsId, true);
redisService.set(MiaoshaKey.isGoodsOver, ""+goodsId, true);//商品库存设置为空
return Result.error(CodeMsg.MIAO_SHA_OVER);
}
//4、判断是否已经秒杀到了
MiaoshaOrder order = orderService.getMiaoshaOrderByUserIdGoodsId(user.getId(), goodsId);
if(order != null) {
return Result.error(CodeMsg.REPEATE_MIAOSHA);
}
//入队
MiaoshaMessage mm = new MiaoshaMessage();
mm.setUser(user);
mm.setGoodsId(goodsId);
sender.sendMiaoshaMessage(mm);
return Result.success(0);//排队中
}
前台:
后台:
重点:
其实按照我们以前的套路来说,其实在这个请求就已经结束了,因为以前我们的基本业务都在这个请求里面,
可是就是因为我们使用了rabbitmq去异步处理下单的这个业务,所以我们在这个请求的返回结果中是无法直接的获取到秒杀是否成功!!
但是异步处理就是说这个下单的业务处理就完全从那个线程去除掉了。那提高的性能不言而喻。
可是至于另外线程完成的事,我们并不了解,只能通过某个标识来确定是否秒杀过。
第三次请求
getMiaoshaResult
function getMiaoshaResult(goodsId){
g_showLoading();
$.ajax({
url:"/miaosha/result",
type:"GET",
data:{
goodsId:$("#goodsId").val(),
},
success:function(data){
if(data.code == 0){
var result = data.data;
if(result < 0){
layer.msg("对不起,秒杀失败");
}else if(result == 0){//继续轮询
setTimeout(function(){
getMiaoshaResult(goodsId);
}, 200);
}else{
layer.confirm("恭喜你,秒杀成功!查看订单?", {btn:["确定","取消"]},
function(){
window.location.href="/order_detail.htm?orderId="+result;
},
function(){
layer.closeAll();
});
}
}else{
layer.msg(data.msg);
}
},
error:function(){
layer.msg("客户端请求有误");
}
});
}
miaoshaResult
/**第二阶段
* orderId:成功
* -1:秒杀失败
* 0: 排队中
* */
@RequestMapping(value="/result", method=RequestMethod.GET)
@ResponseBody
public Result<Long> miaoshaResult(HttpServletRequest request, HttpServletResponse response,Model model,MiaoshaUser user,
@RequestParam("goodsId")long goodsId) {
model.addAttribute("user", user);
if(user == null) {
return Result.error(CodeMsg.SESSION_ERROR);
}
long result = miaoshaService.getMiaoshaResult(user.getId(), goodsId);//(moug) 判断是否已经秒杀
return Result.success(result);
}
前台
是否存在的一个判断
后台:
后言
重点是要了解这个借口地址是如何获取的,
其次是要判断的一个获取是否还有库存
项目代码:
链接:https://pan.baidu.com/s/1lLuT_BdfpdYxuKSGe_TQqw
提取码:iqeb