我有一個徒弟在一家公司做Java,
小組在做一個抽獎系統,現在給我分配到了抽獎邏輯這方面的實現。
EMMM,拿到分配的時候是懵B的。
老大給的需求圖
給的關鍵表結構DROP TABLE IF EXISTS `dd_annual_meeting_check`;CREATE TABLE `dd_annual_meeting_check` ( `check_id` int(255) NOT NULL AUTO_INCREMENT COMMENT '主鍵', `check_prize_id` varchar(255) NOT NULL COMMENT '抽獎Id', `emp_id` int(10) NOT NULL COMMENT '中獎員工id', `emp_prize_time` varchar(255) NOT NULL COMMENT '中獎時間', `check_receive` varchar(100) NOT NULL COMMENT '核銷 0-已經核銷 1-未核銷', `check_user_id` int(10) DEFAULT NULL COMMENT '核銷工作人員(對於員工id)', `check_time` varchar(255) DEFAULT NULL COMMENT '核銷時間', PRIMARY KEY (`check_id`)) ENGINE=InnoDB AUTO_INCREMENT=158 DEFAULT CHARSET=utf8 COMMENT='中獎池信息表';DROP TABLE IF EXISTS `dd_annual_meeting_prize`;CREATE TABLE `dd_annual_meeting_prize` ( `prize_id` varchar(255) NOT NULL COMMENT '主鍵', `prize_name` varchar(100) NOT NULL COMMENT '抽獎名稱', `prize_num` varchar(100) NOT NULL COMMENT '抽獎總人數', `prize_count` varchar(100) NOT NULL COMMENT '每次中獎人數', `prize_range` varchar(100) DEFAULT NULL COMMENT '抽獎範圍: 0-all 1-未中獎', `prize_state` varchar(100) DEFAULT NULL COMMENT '狀態: 0-待抽 1-抽中 2-已抽', `prize_date` varchar(255) DEFAULT NULL COMMENT '狀態時間', `leader_id` int(10) NOT NULL COMMENT '抽獎領導Id', `giver_id` int(10) DEFAULT NULL COMMENT '加獎人Id', `prize_detial` varchar(100) NOT NULL COMMENT '抽獎詳情', `giver_state` varchar(255) DEFAULT '0' COMMENT '是否加獎 0-否 1-是', PRIMARY KEY (`prize_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='抽獎池信息表';DROP TABLE IF EXISTS `dd_annual_meeting_user`;CREATE TABLE `dd_annual_meeting_user` ( `u_id` int(10) NOT NULL AUTO_INCREMENT, `user_id` varchar(100) NOT NULL COMMENT '員工工號', `user_name` varchar(100) NOT NULL COMMENT '員工姓名', `user_time` varchar(255) DEFAULT NULL COMMENT '掃碼時間', `user_type` varchar(100) DEFAULT NULL COMMENT '身份: 0-普通員工 1-領導 2-工作人員', `user_state` varchar(100) DEFAULT NULL COMMENT '狀態: 1-已領取0-未領取', `state_date` varchar(255) DEFAULT NULL COMMENT '狀態時間', `user_prize` varchar(255) NOT NULL COMMENT '獎票號', PRIMARY KEY (`u_id`)) ENGINE=InnoDB AUTO_INCREMENT=3423 DEFAULT CHARSET=utf8 COMMENT='人員信息表';追加:
-- ---
-- Table structure for dd_annual_meeting_record
-- ---
DROP TABLE IF EXISTS `dd_annual_meeting_record`;
CREATE TABLE `dd_annual_meeting_record` (
`record_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主鍵',
`record_prize_id` int(10) NOT NULL COMMENT '抽獎id',
`record_times` int(10) NOT NULL COMMENT '第幾輪',
`record_over` int(10) NOT NULL COMMENT '剩餘次數',
`record_count` int(10) NOT NULL COMMENT '每次中獎數',
`record_state` varchar(100) NOT NULL COMMENT '進行狀態 0-未開始 1-已結束',
PRIMARY KEY (`record_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ---
-- Records of dd_annual_meeting_record
-- ---
沒有多餘講解,就一句話,「需求是這樣,怎樣實現我不管。」這是老大的座右銘。
可我特麼的是新手啊,難受啊,馬飛!
好吧,其實是說業務流程和其他表結構並沒有最終確定,先做個大概的抽獎邏輯出來,咱就按照表結構和自己的意思做一把思想上的巨人。
先從第一個開始(一二三等獎不能重複獲得)
分析下表結構:
一共三張表,中獎池信息表dd_annual_meeting_check,這個比較容易理解,就是將得到的中獎人的id和獎 項id插入這張表。抽獎池信息表dd_annual_meeting_prize,這張表看來是獲取抽獎信息的來源。人員信息表dd_annual_meeting_user,這個就是用來得到抽獎人集合的表了。
分析下抽獎的過程:
抽獎池信息表裡面信息已經定好了不用我管 ,假設人員信息表有100個人參與活動。
第一次抽獎(一等獎) 從100人中抽5個人來中獎,但是要分5次抽完,每次抽1人。第二次抽獎(二等獎)從95人(中了一次獎的人,不參與抽獎)中抽10個人來中獎,每次抽5人出來,要抽2次。第三次抽獎(二等獎)從85人(中了一次獎的人,不參與抽獎)中抽5個人來中獎,每次抽1人,抽5次。來個圖:
思路圖實現邏輯大致思路:
1.從人員信息表獲得所有參與人員的數量
2.根據頁面數據判斷抽的什麼獎勵
3.從抽獎池信息表中獲得抽獎主鍵id(prize_id),抽獎總人數(prize_num),每次中獎人數(prize_count),抽獎人領導id(leader_id)
4.進行抽獎,從人數中抽出對應的數字,根據數字去人員表中得到對應的人員信息
5.將中獎人信息與獎項信息綁定,添加到中獎池信息表
簡單的分析後,有了大致思路,細節什麼的就在代碼中完成:
一,先弄兩個頁面出來,一個是顯示中獎信息的頁面,另外一個是發送抽獎指令的頁面(因為是領導來點擊抽獎,所以有一個領導信息需要發送過來)。
<html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"/> <title>抽獎頁面</title> <script src="http://how2j.cn/study/jquery.min.js"></script> </head> <body> <div> <div id="showData" name="showData"> <p>獎品列表!!!!!!!!!!!!</p> </div> <input type="hidden" name="poe" id="poe" /></div> <script type="text/javascript">var psel = document.getElementById("poe"); window.onload=function (){ websocket = new WebSocket("ws://127.0.0.1:8080/websocket"); websocket.onmessage = function(msg) { console.log(msg.data); $.ajax({ url:"test2", type:"POST", data:{ msg:msg.data, peo:psel.value }, dataType : "json", success : function (rtn) { console.log("Successfully"); console.log(rtn); if(rtn.list != null){ var inf = '<table class=table>'; inf += "<tr><th>獲獎人id</th><th>獲獎人姓名</th><th>獲獎人獎券號</th></tr>" /*<![CDATA[*/ for(var i=0; i<rtn.list.length;i++){ /*]]>*/ var stu = rtn.list[i]; inf += "<tr><td>"+stu.user_id+"</td><td>"+stu.user_name+"</td><td>"+stu.user_prize+"</td></tr>" } inf += "</table>" $("#showData").html(inf); } if(rtn.poe != null){ psel.value = rtn.poe; } } }); } }</script> </body> </html>//發送消息測試頁面<html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"/> <title>發送消息測試頁面</title> <script th:src="@{js/sockjs.min.js}"></script> <script th:src="@{js/stomp.min.js}"></script> <script src="http://how2j.cn/study/jquery.min.js"th:src="@{js/jquery/2.0.0/jquery.min.js}"></script> </head> <body> <noscript><h2 style="color: #e80b0a;">Sorry,瀏覽器不支持WebSocket</h2></noscript> <div> <div> <button id="disconnect" onclick="send()" onclike="send()">發送</button> <input id="text" type="text"/> </div> </div> <script type="text/javascript"> var websocket=null; window.onload=function (){ if ('WebSocket' in window) { console.log("1"); websocket = new WebSocket("ws://127.0.0.1:8080/websocket"); } else if ('MozWebSocket' in window) { console.log("2"); websocket = new MozWebSocket("ws://127.0.0.1:8080/websocket"); } else { websocket = new SockJS("ws://127.0.0.1:8080/websocket"); } //websocket = new WebSocket("ws://127.0.0.1:8080/websocket"); websocket.onmessage = function(msg) { console.log(msg.data); } } function send() { var message = document.getElementById('text').value; console.log(message); websocket.send(message); }</script> </body> </html>這是之前寫的用websocket來實時傳值的兩個頁面,稍微改了改。
二,寫Controller層代碼
先把兩個頁面的請求寫出來
@Controller@RequestMapping("/hello")public class WsController { //測試頁面 @RequestMapping("/test1") public String test() throws IOException{ return "showlist"; } //消息發送頁面 @RequestMapping("/test3") public String test2() throws IOException{ return "ws2"; } 剩下的就是抽獎邏輯代碼 和資料庫腳本代碼了,細節如何構思的就不說了,腦殼疼,一邊想著怎麼做,然後老大那邊又說這個流程這麼走,不不不,那麼走,嗯嗯嗯,還是這麼走。
//抽獎測試 @Autowired private TestDao testDao; @ResponseBody @RequestMapping("/test2") public Map test(@RequestParam("msg") String msg,@RequestParam("peo") List<Integer> peo) throws IOException { String prize_name = "第一輪抽獎"; //收到頁面傳來數據msg(抽獎人id),prize_name(抽取的獎項)獲得抽獎信息 Map<String,String> priz_info = testDao.findPrizinfo(msg,prize_name); //定義一個最終傳回值的集合 Map m1 = new HashMap(); if(priz_info != null) { //判斷peo數據如果沒人數數據 添加數據 if(peo.isEmpty()) { //n為人員總數 int n = testDao.findAll(); for(int i = 0; i < n;i++) { peo.add(i); } } System.out.println("當前抽獎總人數為:"+peo); //定義一個最終獲獎人id的集合 ArrayList<Integer> dIdList = new ArrayList<Integer>(); //定義一個獲取抽獎結果的集合 Map m2 = new HashMap(); //得到抽獎次數 int count = Integer.parseInt(priz_info.get("prize_num")) / Integer.parseInt(priz_info.get("prize_count")) ; for(int i = 0; i < count;i++) { //進行抽獎並獲得結果集 m2 = luck(peo,Integer.parseInt( priz_info.get("prize_count"))); //得到中獎人id集合 dIdList.addAll((List)m2.get("eidList")); //得到剩餘人數 peo = (List<Integer>) m2.get("idList"); //將每一次抽獎的狀態改變 testDao.update(priz_info.get("prize_id"), i+1); } System.out.println("獲獎id:"+dIdList); System.out.println("最後人數:"+peo); //循環獲得LIST<USER> 中獎人信息 ArrayList<User> infoList = new ArrayList<User>(); for(int i = 0;i < dIdList.size();i++) { infoList.add(testDao.findById(dIdList.get(i))); } //為返回值傳入參數 //獲獎信息 m1.put("list", infoList); //未中獎人 m1.put("poe", peo); } return m1;} //抽獎 傳參 1.總人數 3,幾人中獎 Map luck(List<Integer> idList,int n) { //取得中獎人id ArrayList<Integer> a = makeRandom(0,idList.size(), n); System.out.println("中獎的數字為"+a); //獲獎id臨時存儲集合 ArrayList<Integer> eidList = new ArrayList<Integer>(); //排序 Object[] b = a.toArray(); Arrays.sort(b); //定義一個中獎人數據集合 List t = new ArrayList(); for(int i = 0; i < b.length;i++) { eidList.add(idList.get((int) b[i])); System.out.println("中獎的id為"+idList.get((int) b[i])); t.add(idList.get((int) b[i])); } //總人數中移除中獎人數據 idList.removeAll(t); //寫到Map集合回傳 Map m = new HashMap(); //剩餘id m.put("idList", idList); //獲獎id m.put("eidList", eidList); return m; } //從x-y 取num個隨機數 ArrayList<Integer> makeRandom(int x, int y, int num) { //創建一個integer的動態數組 ArrayList<Integer> a = new ArrayList<Integer>(); int index = 0; //往數組裡面逐一加取到不重複的元素 while(index < num) { //產生x-y的隨機數 Random r = new Random(); int temp = r.nextInt(y-x)+x ; //設置是否重複的標記變量為false boolean flag = false; for(int i =0; i<index;i++) { if(temp == a.get(i)) { flag = true; break; } } if(flag==false) { a.add(temp); index++; } } return a; }}Dao
@Mapperpublic interface TestDao { //查詢抽獎人數 @Select("select count(*) from dd_annual_meeting_user where user_state = 1") int findAll(); //查詢中獎人信息 @Select("select * from dd_annual_meeting_user where user_state = 1 limit ${id},1") User findById(@Param("id") int id); //修改中獎人與獎池練聯繫(暫時不寫) @Insert("INSERT INTO dd_annual_meeting_check VALUES ( #{check_prize_id}, #{emp_id},curdate(),'1')") void inset(@Param("check_prize_id") String check_prize_id,@Param("emp_id") int emp_id); //獲取抽獎信息 @Select("select prize_id,prize_num,prize_count from dd_annual_meeting_prize where leader_id=#{msg} and prize_name=#{prize_name} and prize_state=0") Map findPrizinfo(@Param("msg") String msg, @Param("prize_name") String prize_name); //更改抽獎狀態 @Update("update dd_annual_meeting_record set record_state=1 where record_prize_id = #{prize_id} and record_times = #{record_times}") void update(@Param("prize_id") Object prize_id, @Param("record_times") int record_times);}現在來測試效果:
點擊前
這邊自己在資料庫中添加了數據,傳1後會進行抽獎
第一次點擊
第二次點擊
點了兩次 共抽了10人出來,並沒有重複。
講真,全程靠著表結構自己想邏輯,真的皮,有些欄位都不確定是來幹什麼的,去問同組做這個的人,她說她不清楚,我服了,然後知道了個大概的流程,把這個簡單的邏輯弄完給她看了看,她說差不多了,好吧,我不管了,後面都做完了我再修改細節。現在可以摸魚了,摸個兩三天再交差。
最後,我這邊整理了一套Java架構進階的技術知識體系,方便大家系統學習
以上視頻資料是我結合自己和身邊朋友的面試經歷而整理的,希望對面試的朋友或者在找工作的程式設計師們有所幫助。大家對技術感興趣的朋友也可以來Java資源分享群:(805685193),資料會不定期更新。獲取Dubbo、Redis、設計模式、Netty、zookeeper、Spring cloud、分布式、高並發等架構技術視頻教程資料,架構思維導圖,和BATJ面試題及答案。