本文是針對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:23 14 */ 15 public class BigWheelDrawUtil { 16 17 18 /** 19 * 給轉盤的每個角度賦初始值 20 * @return 21 */ 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 * @return 34 */ 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(XMLHttpRequest,status){ //請求完成后最終執行參數 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.