(14)SprintBoot 2.X 秒杀地址隐藏
1. 实现思路
1.1 每次点击秒杀按钮,才会生成秒杀地址,秒杀地址不是写死的,是从服务端获取,动态拼接而成的地址。
- 在进行秒杀之前,去后端获取一个动态的秒杀地址path(服务端生成随机数作为path)将该path存入 redis缓存中,在然后将这个path返回给前端,前端用这个path拼接在新的请求url(url : “/miaosha/” + path + “/do_miaosha”)上作为参数,后端秒杀业务逻辑秒杀前需要判断path与缓存中的path是否一致,一致才进入后续秒杀业务逻辑,否则返回非法请求
2.代码实现
2.1 前端代码
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("客户端请求有误");
}
});
}
2.2 Controller层获取秒杀地址
@AccessLimit(seconds=5, maxCount=5, needLogin=true)
@RequestMapping(value="/path", method=RequestMethod.GET)
@ResponseBody
public Result<String> getMiaoshaPath(HttpServletRequest request, MiaoshaUser user,
@RequestParam("goodsId")long goodsId,
@RequestParam(value="verifyCode", defaultValue="0")int verifyCode
) {
if(user == null) {
return Result.error(CodeMsg.SESSION_ERROR);
}
String path = miaoshaService.createMiaoshaPath(user,goodsId);
boolean check = miaoshaService.checkVerifyCode(user, goodsId, verifyCode);
if(!check) {
return Result.error(CodeMsg.REQUEST_ILLEGAL);
}
return Result.success(path);
}
2.3 MiaoshaService层
public String createMiaoshaPath(MiaoshaUser user, long goodsId) {
if(user == null || goodsId <=0) {
return null;
}
String str = MD5Util.md5(UUIDUtil.uuid()+"123456");
redisService.set(MiaoshaKey.getMiaoshaPath, ""+user.getId() + "_"+ goodsId, str);
return str;
}
public boolean checkPath(MiaoshaUser user, long goodsId, String path) {
if(user == null || path == null) {
return false;
}
String pathOld = redisService.get(MiaoshaKey.getMiaoshaPath, ""+user.getId() + "_"+ goodsId, String.class);
return path.equals(pathOld);
}
2.4 Controller层 验证path后进行秒杀逻辑业务处理
- 需要进行path验证,验证通过后才可以进入秒杀业务逻辑,否则返回非法请求
@RequestMapping(value = "/{path}/do_miaosha", method = RequestMethod.POST)
@ResponseBody
public Result<Integer> miaosha(Model model, MiaoshaUser user,
@RequestParam("goodsId")long goodsId,
@PathVariable("path")String path) {
if(user == null){
return Result.error(CodeMsg.SESSION_ERROR);
}
model.addAttribute("user", user);
boolean check = miaoshaService.checkPath(user, goodsId, path);
if(!check){
return Result.error(CodeMsg.REQUEST_ILLEGAL);
}
boolean isOver = localOverMap.get(goodsId);
if(isOver){
return Result.error(CodeMsg.MIAOSHA_OVER);
}
long stock = redisService.decr(GoodsKey.getMiaoshaGoodsStock,""+goodsId);
if(stock < 0){
localOverMap.put(goodsId,true);
return Result.error(CodeMsg.MIAOSHA_OVER);
}
logger.info("判断是否重复秒杀次数:"+ time++);
MiaoshaOrder order = orderService.getMiaoshaOrderByUserIdGoodsId(user.getId(),goodsId);
if(order != null){
redisService.incr(GoodsKey.getMiaoshaGoodsStock,"" + goodsId);
localOverMap.put(goodsId,false);
return Result.error(CodeMsg.REPEATE_MIAOSHA);
}
MiaoshaMessage message = new MiaoshaMessage();
message.setUser(user);
message.setGoodsId(goodsId);
sender.sendMiaoshaMessage(message);
return Result.success(0);
}