你的位置:首页 > Java教程

[Java教程]利用java实现抽奖转盘(着重安全控制)


本文是针对jquery 实现抽奖转盘作者的一个补充(主要用java去实现转盘结果生成及存储,解决jquery 做法 非法用户采用模拟器实现改变转盘值的风险性),针对jQuery的具体实现,请看案例:http://www.cnblogs.com/mofish/archive/2013/01/24/2875516.html              本文就不一一细说了,那么现在就直入正题。

由于公司产品推广,最近要求实现一个邀请用户注册即可抽奖的转盘,页面展示如下:

 

 

java 实现方式如下:

构造实体类

WchatLotteryDomain.java

 1 package com.cy.dcts.domain.activity; 2  3 import java.io.Serializable; 4  5 /** 6 * 微信用户分享中奖基础数据类 7 * @author yanst 2016/4/23 9:36 8 */ 9 public class WchatLotteryDomain implements Serializable{10 private static final long serialVersionUID = -1595371216905016135L;11 12 private Integer id;13 14 //中奖金额15 private String prize;16 17 //中奖率18 private Integer v;19 20 public WchatLotteryDomain(Integer id, String prize, Integer v){21 this.id = id;22 this.prize = prize;23 this.v = v;24 }25 26 public Integer getId() {27 return id;28 }29 30 public void setId(Integer id) {31 this.id = id;32 }33 34 public String getPrize() {35 return prize;36 }37 38 public void setPrize(String prize) {39 this.prize = prize;40 }41 42 public Integer getV() {43 return v;44 }45 46 public void setV(Integer v) {47 this.v = v;48 }49 }

 

 

抽奖算法实现类:  

     1.初始数据集合:initDrawList  。

 2.generateAward方法实现根据概率随机生成中奖对象WchatLotteryDomain 

BigWheelDrawUtil.java

 1 package com.cy.dcts.common.util; 2  3 import com.alibaba.fastjson.JSON; 4 import com.cy.dcts.domain.activity.WchatLotteryDomain; 5  6 import java.util.ArrayList; 7 import java.util.List; 8  9 /**10  *11  * wchat大转盘抽奖活动12  *13  * @author yanst 2016/4/23 9:2314 */15 public class BigWheelDrawUtil {16 17 18   /**19    * 给转盘的每个角度赋初始值20    * @return21   */22   private final static List<WchatLotteryDomain> initDrawList = new ArrayList<WchatLotteryDomain>() {{23     add(new WchatLotteryDomain(1, "200", 1));24     add(new WchatLotteryDomain(2, "100", 3));25     add(new WchatLotteryDomain(3, "50", 30));26     add(new WchatLotteryDomain(4, "30", 30));27     add(new WchatLotteryDomain(5, "20", 26));28     add(new WchatLotteryDomain(6, "10", 10));29   }};30 31   /**32    * 生成奖项33    * @return34   */35   public static WchatLotteryDomain generateAward() {36     List<WchatLotteryDomain> initData = initDrawList;37     long result = randomnum(1, 100);38     int line = 0;39     int temp = 0;40     WchatLotteryDomain returnobj = null;41     int index = 0;42     for (int i = 0; i < initDrawList.size(); i++) {43       WchatLotteryDomain obj2 = initDrawList.get(i);44       int c = obj2.getV();45       temp = temp + c;46       line = 100 - temp;47       if (c != 0) {48         if (result > line && result <= (line + c)) {49           returnobj = obj2;50           break;51         }52       }53     }54     return returnobj;55   }56 57   // 获取2个值之间的随机数58   private static long randomnum(int smin, int smax){59       int range = smax - smin;60       double rand = Math.random();61       return (smin + Math.round(rand * range));62   }63 64 65   public static void main(String[] args) {66     System.out.println(JSON.toJSONString(generateAward()));67   }68 69 }

 

 

controller 层 实现 显示抽奖的结果给页面,页面启动转盘,把对应的中间角度显示给用户看,同时把中间金额保存到系统中。

1.调用util类返回中奖项

 //生成中奖金额对象WchatLotteryDomain wchatLotteryDomain = BigWheelDrawUtil.generateAward();

2.修改抽奖次数 

//修改抽奖次数Integer result = appShareService.markLuckDraw(id);

3.把中奖信息持久化

//写入中奖信息 writeXinRecord(mobile, wchatLotteryDomain);

4.把当前中奖信息及剩余中奖次数返回

//代码略,参考ActivityAction.java  107、108行

ActivityAction.java

 1 /** 2    * 抽奖 3    * 4    * @param id id 5    * @param mobile  中奖号码 6    * @return 7   */ 8   @RequestMapping("wXinMarkLuckDraw.jspx") 9   @ResponseBody 10   public JSonRespone markLuckDraw(Long id, String mobile) { 11     //参数验证 12     if (id == null || id.longValue() == 0) { 13       return JSonRespone.makeHasContentJSonRespone("1", "您没有抽奖次数!"); 14     } 15     //参数验证 16     if (StringUtils.isEmpty(mobile)) { 17       return JSonRespone.makeHasContentJSonRespone("1", "中奖手机号码为空!"); 18     } 19  20     //生成中奖金额对象 21     WchatLotteryDomain wchatLotteryDomain = BigWheelDrawUtil.generateAward(); 22     if(wchatLotteryDomain == null){ 23       return JSonRespone.makeHasContentJSonRespone("3", "生成抽奖数据失败"); 24     } 25     try { 26       //修改抽奖次数 27       Integer result = appShareService.markLuckDraw(id); 28       if (result == null || result == 0) { 29         return JSonRespone.makeHasContentJSonRespone("2", "抽奖失败,请刷新重新验证。"); 30       } 31     } catch (Exception e) { 32       logger.debug(e.getMessage()); 33       return JSonRespone.makeHasContentJSonRespone("2", "抽奖失败,请刷新重新验证。"); 34     } 35  36     if(logger.isErrorEnabled()){ 37       logger.error("微信分享活动:手机号码为:{},中奖信息:{}", mobile, JSON.toJSONString(wchatLotteryDomain)); 38     } 39  40     //写入中间信息 41     return writeXinRecord(mobile, wchatLotteryDomain); 42   } 43  44   //  微信 用户分享 认证之后送话费活动 中奖记录存储路径 45   private static final String wXinFilePath = "/home/wxhb/lottery.txt"; 46   //"/home/wxhb/lottery.txt"; 47   //"D:/list.txt"; 48  49  50   /** 51    * 写入中奖金额 52    * @param mobile 53    * @param wchatLotteryDomain 54    * @return 55   */ 56   private JSonRespone writeXinRecord(String mobile,WchatLotteryDomain wchatLotteryDomain ) { 57     // 记录时间 58     SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); 59     Calendar calendar = Calendar.getInstance(); 60     String date = simpleDateFormat.format(calendar.getTime()); 61     // 记录文件是否存在 62     File file = new File(wXinFilePath); 63     if (!file.exists()) { 64       try { 65         file.createNewFile(); 66       } catch (IOException e) { 67         e.printStackTrace(); 68       } 69     } 70     // 临时记录存储 71     ArrayList<String> arrayList = new ArrayList<>(); 72     // 是否已经存在记录 73     Scanner in = null; 74     try { 75       in = new Scanner(file); 76     } catch (FileNotFoundException e) { 77       e.printStackTrace(); 78     } 79     // 读取记录放置临时数组 80     while (in.hasNextLine()) { 81       arrayList.add(in.nextLine()); 82     } 83     in.close(); 84     // 查询记录是否存在 85     if (arrayList.size() > 0) { 86       for (String str : arrayList) { 87         if (mobile.equals(str.split("-")[0])) { 88           return JSonRespone.makeHasContentJSonRespone("1", "成功", "记录已存在"); 89         } 90       } 91     } 92     // 写入记录 93     BufferedWriter out = null; 94     try { 95       out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file, true))); 96       out.write(mobile + "  " + date + "  " + wchatLotteryDomain.getPrize()); 97       out.newLine(); 98       out.close(); 99     } catch (IOException e) {100       e.printStackTrace();101       return JSonRespone.makeHasContentJSonRespone("0", "失败", e.getMessage());102     }103 104     Map<String, Object> resultMap = new HashMap<String, Object>();105     try {106       //获取抽奖次数107       resultMap.put("luckDrawCounts", appShareService.getLuckDrawCounts(mobile));//抽奖次数108       resultMap.put("wchatLotteryDomain", wchatLotteryDomain);109     } catch (Exception e) {110       logger.debug(e.getMessage());111     }112     return JSonRespone.makeHasContentJSonRespone("0", "成功", resultMap);113   }

 

抽奖页面代码:

这里省略大转盘样式代码,详细参考:http://www.cnblogs.com/mofish/archive/2013/01/24/2875516.html

点击抽奖按钮 最先执行lottery.html 98行代码   ,页面入口已经告诉大家,剩余请大家往下看应该就明白了。

lottery.html

 1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4   <meta charset="UTF-8"> 5   <title>xxx</title> 6   <meta content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=0" name="viewport"/> 7   <link rel="stylesheet" type="text/css" href="css/app.css"/> 8 </head> 9 <body> 10 <div class="page"> 11   <div id="verify-section"> 12     <img src="img/1.png" width="750" height="654"> 13     <div class="field lottery"> 14       <h2>输入您的手机号码,查看您的可抽奖次数。</h2> 15       <p> 16         <input type="tel" id="mobile" class="mobile" placeholder="请输入你的手机号码" maxlength="11"/> 17       </p> 18       <p> 19         <input type="text" id="code" placeholder="验证码" maxlength="6"/> 20         <button id="btn-code" class="btn">获取验证码</button> 21       </p> 22       <h2 class="error">手机号码格式不正确</h2> 23       <p> 24         <button id="btn-verify" class="btn">提交</button> 25       </p> 26     </div> 27   </div> 28   <div id="lottery-section" class="field lottery"> 29     <h2>您的可抽奖次数为:_<span class="lucktime"></span>_次</h2> 30     <p> 31       <button id="btn-list" class="btn">查看好友认证的情况</button> 32     </p> 33  34     <p> 35       <label for="mobile-check">请核对您的充值号码:</label> 36       <input type="tel" id="mobile-check" placeholder="请输入要充值的手机号" maxlength="11"/> 37       <p id="submit-check" style="display: none;">充值号码格式不正确 </p> 38     </p> 39  40     <div class="ly-plate"> 41       <div class="m-rotate"></div> 42       <div class="m-pointer"></div> 43     </div> 44     <p class="lottery-msg"></p> 45  46     <h2 class="submit-msg" style="display: none;">话费将在1个工作日内充值,请注意查收。</h2> 47     <p class="share-more"> 48       <button id="btn-share-more" class="btn">话费还有好多,我要继续推荐</button> 49     </p> 50   </div> 51   <div id="overlay"> 52     <div class="verify-list"> 53       <a href="#" onclick="$('#overlay').hide();"></a> 54       <ul class="list"> 55       </ul> 56     </div> 57   </div> 58 </div> 59 </body> 60 <script src="js/jquery.min.js" type="text/javascript" charset="utf-8"></script> 61 <script src="js/pageResponse.min.js" type="text/javascript" charset="utf-8"></script> 62 <script type="text/javascript" src="js/Rotate.js"></script> 63 <script type="text/javascript" src="js/app.js" charset="utf-8"></script> 64 <script type="text/javascript"> 65   $(function () { 66 //    $("#lottery-section").show(); 67     $("#btn-list").click(function () { 68       $("#overlay").show(); 69     }); 70     $("#btn-share-more").click(function(){ 71       window.location = "index.html"; 72     }); 73     pageResponse({ 74       selectors: 'div.page', 75       mode: 'auto', // auto || contain || cover ,默认模式为auto 76       width: '750', //输入页面的宽度,只支持输入数值,默认宽度为320px 77       height: '654' 78     }); 79  80     //启动转盘 81     var rotateFunc = function (angle, prize, luckDrawCounts) { //angle: 奖项对应的角度 prize:中奖金额 luckDrawCounts:抽奖次数 82       $('.m-rotate').stopRotate(); 83       $('.m-rotate').rotate({ 84         angle: 0, 85         duration: 5000, 86         animateTo: angle + 1440, //angle是图片上各奖项对应的角度,1440是我要让指针旋转4圈。所以最后的结束的角度就是这样子^^ 87         callback: function () { 88           //更改抽奖次数 89           $(".submit-msg").show(); 90           $(".lucktime").html(luckDrawCounts); 91           isLottery = false; 92           $(".lottery-msg").html('您抽中了' + prize + '元手机话费,恭喜您。').css("color", "#fff"); 93         } 94       }); 95     }; 96  97      98     $(".m-pointer").rotate({ 99       bind: {100         click: function () {101           $("#submit-check").hide();102           //判断充值号码103           if (!verifyPhoneNumber($("#mobile-check").val())) {104             $("#submit-check").css("color", "red").show();105             return false;106           }107 108           if (luckDrawCounts != 0 && isLottery == false) {109             var ajaxTimeoutTest = $.ajax({110               url: "/activity/wXinMarkLuckDraw.jspx",111               data: {"id": listIds[0], "mobile": $("#mobile-check").val()},112               type: "POST",113 //              timeout : 5000, //超时时间设置,单位毫秒114               success: function (rs) {115                 if (rs.result == "0") {116                   //生成中奖数据117                   var data = rs.content.wchatLotteryDomain;118                   //抽奖剩余次数119                   var luckDrawCounts = rs.content.luckDrawCounts;120                   if (data.id == 1) {121                     rotateFunc(360, data.prize, luckDrawCounts);122                   }123                   if (data.id == 2) {124                     rotateFunc(300, data.prize, luckDrawCounts);125                   }126                   if (data.id == 3) {127                     rotateFunc(240, data.prize, luckDrawCounts);128                   }129                   if (data.id == 4) {130                     rotateFunc(180, data.prize, luckDrawCounts);131                   }132                   if (data.id == 5) {133                     rotateFunc(120, data.prize, luckDrawCounts);134                   }135                   if (data.id == 6) {136                     rotateFunc(60, data.prize, luckDrawCounts);137                   }138                 }else {139                   isLottery = false;140                   $(".lottery-msg").html(rs.errorMessage).css("color", "red");141                 }142               }143 //              ,complete : function(144 //                if(status=='timeout'){145 //                  ajaxTimeoutTest.abort();146 //                  isLottery = false;147 //                  $(".lottery-msg").html("当前抽奖人数过多请稍后重试!").css("color", "red");148 //                }149 //              }150             });151           }else{152             if (isLottery && luckDrawCounts > 0){153               $(".lottery-msg").html('请提交后再重新抽奖').css("color", "red");154             }else{155               $(".lottery-msg").html('对不起你的抽奖机会用完了').css("color", "red");156             }157           }158         }159       }160     });161   });162 </script>163 </html>

 

为了体验性,我这里的所有请求都是采用Ajax请求。

Java实现抽奖转盘 示例到这里就结束了,比较简单大家一看应该就明白了。这里也想补充说明下:

1.在考虑安全的情况下,抽奖算法实现,最好写在后台,因为这样中奖金额直接在后台去持久化了,无需经过页面传输,页面只是做了单纯的展示,一些非法操作,是没有办法通过改变中奖金额,去刷我们的中奖金额。

举例:如某个用户抽奖中了200元话费,我这里接口入参只需要告诉我 id 和 mobile ,并没有传中奖金额,这里前端就没有办法非法改变中奖金额了。

2.考虑如果用户点击抽奖按钮,但此时由于比较卡(可能受网络限制,请求很慢等等原因)造成用户点击了但是已经离开当前页面了,此时用户应该算已经抽奖了。这时我每次请求都去检查了抽奖次数估,也不会出现重复提交问题。

//修改抽奖次数Integer result = appShareService.markLuckDraw(id);

  if (result == null || result == 0) {
     return JSonRespone.makeHasContentJSonRespone("2", "抽奖失败,请刷新重新验证。");
  }

 

第一次写博客,请的不好请大家见谅。

有需要源码的朋友可以留言,后续有空我会把项目中的代码整理成单独demo.