幾年前做的一個小demo,代碼比較老,先上下html顯示效果圖
因為代碼中注釋比較詳細,所以就直接上代碼了
html代碼,也就是上圖展示的效果頁面

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <script type="text/javascript" src="../js/jquery-1.12.3.min.js" ></script> <script type="text/javascript" src="../js/json2.js" ></script> <script type="text/javascript" src="../js/rule.js" ></script> <style type="text/css"> #background{ position: relative; margin: 20px auto; /*background: #EAC000;*/ } .chessman{ border-radius: 15px; width: 30px; height: 30px; margin: 0 auto; } .white{ background-color:white ; } .black{ background-color: black; } .grid,.b_grid{ float: left; } .message{ width: 320px; height: 100px; margin: 0 auto; } #messageContent{ width: 320px; height: 80px; } </style> </head> <body> <div id="background"> <!--<div id="back_grid"></div>--> <div id="chess"></div> </div> <div class="message"> <textarea id="messageContent" disabled="disabled" readonly="readonly"></textarea> <div><input id="message"/> <button onclick="WuZiQi.sendMessage()">發送</button></div> </div> </body> </html>
接下來是頁面rule.js功能代碼

var bout = false;//是否允許落子 var color = "";//自己落子顏色 var websocket = null; var row = 15; var col = 15; var widthAndHeight = 30;//格子寬度高度 var WuZiQi = { isEnd:function(xy,chessmanColor){//判斷是否結束游戲 var id = parseInt(xy); //豎的計算 var num = 1; num = WuZiQi.shujia(num,id,chessmanColor); num = WuZiQi.shujian(num,id,chessmanColor); if(num>=5){ if(chessmanColor==color){ confirm("游戲結束!你贏了!"); }else{ confirm("游戲結束!你輸了!"); } return ; } num = 1; num = WuZiQi.hengjia(num,id,chessmanColor); num = WuZiQi.hengjian(num,id,chessmanColor); if(num>=5){ if(chessmanColor==color){ confirm("游戲結束!你贏了!"); }else{ confirm("游戲結束!你輸了!"); } return ; } ; num = 1; num = WuZiQi.zuoxiejia(num,id,chessmanColor); num = WuZiQi.zuoxiejian(num,id,chessmanColor); if(num>=5){ if(chessmanColor==color){ confirm("游戲結束!你贏了!"); }else{ confirm("游戲結束!你輸了!"); } return ; } num = 1; num = WuZiQi.youxiejia(num,id,chessmanColor); num = WuZiQi.youxiejian(num,id,chessmanColor); if(num>=5){ if(chessmanColor==color){ confirm("游戲結束!你贏了!"); }else{ confirm("游戲結束!你輸了!"); } return ; } },youxiejia:function(num,id,color){ var yu = id%row; id = id+(row-1); if(id<(row*col)&&(id%row)<yu){ var flag = WuZiQi.checkColor(id,color); if(flag){ num++; return WuZiQi.youxiejia(num,id,color); }else{ return num; } }else{ return num; } },youxiejian:function(num,id,color){ var yu = id%row; id = id-(row-1); if(id>=0&&(id%row)>yu){ var flag = WuZiQi.checkColor(id,color); if(flag){ num++; return WuZiQi.youxiejian(num,id,color); }else{ return num; } }else{ return num; } },zuoxiejia:function(num,id,color){ var yu = id%row; id = id+(row+1); if(id<(row*col)&&(id%row)>yu){ var flag = WuZiQi.checkColor(id,color); if(flag){ num++; return WuZiQi.zuoxiejia(num,id,color); }else{ return num; } }else{ return num; } },zuoxiejian:function(num,id,color){ var yu = id%row; id = id-(row+1); if(id>=0&&(id%row)<yu){ var flag = WuZiQi.checkColor(id,color); if(flag){ num++; return WuZiQi.zuoxiejian(num,id,color); }else{ return num; } }else{ return num; } }, hengjia:function(num,id,color){ var yu = id%row; id = id+1; if(id<(row*col)&&(id%row)>yu){ var flag = WuZiQi.checkColor(id,color); if(flag){ num++; return WuZiQi.hengjia(num,id,color); }else{ return num; } }else{ return num; } }, hengjian:function(num,id,color){ var yu = id%row; id = id-1; if(id>=0&(id%row)<yu){ var flag = WuZiQi.checkColor(id,color); if(flag){ num++; return WuZiQi.hengjian(num,id,color); }else{ return num; } }else{ return num; } }, shujia:function(num,id,color){ id = id+row; if(id<(row*col)){ var flag = WuZiQi.checkColor(id,color); if(flag){ num++; return WuZiQi.shujia(num,id,color); }else{ return num; } }else{ return num; } }, shujian:function(num,id,color){ id = id-row; if(id>=0){ var flag = WuZiQi.checkColor(id,color); if(flag){ num++; return WuZiQi.shujian(num,id,color); }else{ return num; } }else{ return num; } }, checkColor:function(xy,color){ if($("#"+xy).children("div").hasClass(color)){ return true; }else { return false; } }, playchess:function(e){ if(bout&&color!=""){ if($(e).children("div").length>0){ alert("這里已經有子了!請在其它地方落子!"); return; } var result = {}; result.xy = $(e).attr("id"); result.color = color; result.message = "系統:您已落子,請等待對手落子!"; result.bout = false; if(websocket!=null){ websocket.send(JSON.stringify(result)); }else{ $("#messageContent").append("系統:已斷開連接"); $("#messageContent").append("\n"); } }else{ if(color==""){ $("#messageContent").append("系統:游戲還沒有開始!"); $("#messageContent").append("\n"); $("#messageContent").scrollTop($("#messageContent")[0].scrollHeight - $("#messageContent").height()); }else{ $("#messageContent").append("系統:請等待你的對手落子!"); $("#messageContent").append("\n"); $("#messageContent").scrollTop($("#messageContent")[0].scrollHeight - $("#messageContent").height()); } } }, //發送消息 sendMessage:function(){ var message = $("#message").val(); if(message!=""){ var result = {}; result.message = message; websocket.send(JSON.stringify(result)); $("#message").val(""); }else{ $("#messageContent").append("系統:請不要發送空信息!"); $("#messageContent").append("\n"); $("#messageContent").scrollTop($("#messageContent")[0].scrollHeight - $("#messageContent").height()); } } }; $(function(){ //根據棋盤格子數得到棋盤大小 $("#background").css({width:(row*widthAndHeight)+"px",height:(col*widthAndHeight)+"px"}); //用canvas畫棋盤 var canvas = document.createElement("canvas"); // $(canvas).attr({width:((row-1)*widthAndHeight)+"px",height:(col-1)*widthAndHeight+"px"}); // $(canvas).css({"position":"relative","top":(widthAndHeight/2)+"px","left":(widthAndHeight/2)+"px","z-index":9999}); $(canvas).attr({width:(row*widthAndHeight)+"px",height:col*widthAndHeight+"px"}); $(canvas).css({position:"relative","z-index":9999}); var cot = canvas.getContext("2d"); cot.fillStyle = "#EAC000"; cot.fillRect(0,0,row*widthAndHeight,col*widthAndHeight); cot.lineWidth = 1; var offset = widthAndHeight/2; for(var i=0;i<row;i++){//面板大小和棋盤一致,但格子線條比棋盤的行列少1 cot.moveTo((widthAndHeight*i)+offset,0+offset); cot.lineTo((widthAndHeight*i)+offset,(col*widthAndHeight)-offset); } for(var j=0;j<col;j++){ cot.moveTo(0+offset,(widthAndHeight*j)+offset); cot.lineTo((widthAndHeight*row)-offset,(j*widthAndHeight)+offset); } cot.stroke(); $("#background").prepend(canvas); //生成格子橫線 // var b_str=""; // for(var i=0;i<(row-1);i++){ // for(var j=0;j<(col-1);j++){ // b_str+="<div class='b_grid'></div>"; // } // } // $("#back_grid").append(b_str); // $("#back_grid").css({width:((row-1)*widthAndHeight)+"px",height:(col-1)*widthAndHeight+"px",position: "absolute",top:(widthAndHeight/2)+"px",left:(widthAndHeight/2)+"px",border:"solid 1px black"}); // //減去線的寬度 // $(".b_grid").css({width:(widthAndHeight-2)+"px",height:(widthAndHeight-2)+"px",border:"solid 1px black"}); //生成落子格子 var str=""; var index = 0; for(var i=0;i<row;i++){ for(var j=0;j<col;j++){ str+="<div class='grid' id=\""+index+"\"></div>"; index++; } } $("#chess").empty(); $("#chess").append(str); $("#chess").css({width:(row*widthAndHeight)+"px",height:(col*widthAndHeight)+"px",position: "absolute",top:"0px",left:"0px","z-index":99999}); $(".grid").on("click",function(){ WuZiQi.playchess(this); }); $(".grid").css({width:widthAndHeight+"px",height:widthAndHeight+"px"}); //判斷當前瀏覽器是否支持WebSocket if('WebSocket' in window){ websocket = new WebSocket("ws://"+window.location.host+"/WuZiQi/wuziqisocket"); } else{ alert('Not support websocket'); } //連接發生錯誤的回調方法 websocket.onerror = function(){ }; //連接成功建立的回調方法 websocket.onopen = function(event){ }; //接收到消息的回調方法(包含了聊天,落子,開始游戲) websocket.onmessage = function(){ var result = JSON.parse(event.data); if(result.message!=""){ $("#messageContent").append(result.message); $("#messageContent").append("\n"); //將多行文本滾動總是在最下方 $("#messageContent").scrollTop($("#messageContent")[0].scrollHeight - $("#messageContent").height()); } if(result.xy!=""&&result.color!=""){ $("#"+result.xy).html("<div class=\"chessman "+result.color+"\"></div>"); bout = result.bout;//落子后才改狀態 WuZiQi.isEnd(result.xy,result.color); }else if(result.xy==""&&result.bout){//沒有坐標且bout為true,則為對局首次開始落子 bout = result.bout; } if(result.xy==""&&result.color!=""){//沒有坐標,但有顏色,則為首次賦予棋子顏色 color = result.color; } }; //連接關閉的回調方法 websocket.onclose = function(){ }; //監聽窗口關閉事件,當窗口關閉時,主動去關閉websocket連接,防止連接還沒斷開就關閉窗口,server端會拋異常。 window.onbeforeunload = function(){ websocket.close(); }; //關閉連接 function closeWebSocket(){ websocket.close(); } });
java封裝用來傳輸信息的對象代碼

package com.weguard.websocket; /** * * @author xuhan * */ public class Result { /** * 落子坐標 */ private String xy; /** * 發送消息 */ private String message; /** * 是否允許落子 */ private boolean bout; /** * 落子顏色 */ private String color; public String getXy() { return xy; } public void setXy(String xy) { this.xy = xy; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public boolean isBout() { return bout; } public void setBout(boolean bout) { this.bout = bout; } public String getColor() { return color; } public void setColor(String color) { this.color = color; } }
最后是WebSocket的代碼

package com.weguard.websocket; import java.io.IOException; import java.util.HashMap; import javax.websocket.OnClose; import javax.websocket.OnError; import javax.websocket.OnMessage; import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; import net.sf.json.JSONObject; //該注解用來指定一個URI,客戶端可以通過這個URI來連接到WebSocket。類似Servlet的注解mapping。無需在web.xml中配置。 @ServerEndpoint(value="/wuziqisocket") public class WebSocket { //concurrent包的線程安全Set,用來存放每個客戶端對應的MyWebSocket對象。若要實現服務端與單一客戶端通信的話,可以使用Map來存放,其中Key可以為用戶標識 private static HashMap<String,WebSocket> webSocketMap = new HashMap<String,WebSocket>(); //與某個客戶端的連接會話,需要通過它來給客戶端發送數據 private Session session; //連上來的頁面序號,用來配對對戰,1與2一組,3與4一組,依次類推,奇數為黑先走,偶數為白,后走 private static int index = 0; //同上,用來從hashMap中獲取websocket,(我也忘記當時為啥要另外用一個mykey了,而不是直接用index來獲取) private int mykey = 0; /** * 連接建立成功調用的方法 * @param session 可選的參數。session為與某個客戶端的連接會話,需要通過它來給客戶端發送數據 * @throws IOException */ @OnOpen public void onOpen( Session session){ this.session = session; index++; try { Result result = new Result(); if(index%2==0){ WebSocket socket1 = webSocketMap.get((index-1)+""); if(socket1!=null){ result.setBout(true); result.setMessage("系統:游戲開始,請您先落子!"); result.setColor("black"); JSONObject json1 = JSONObject.fromObject(result); socket1.sendMessage(json1.toString()); //對先落子的對象發送數據結束 result.setMessage("系統:游戲開始,請等待對手落子!"); result.setBout(false); result.setColor("white"); this.sendMessage(JSONObject.fromObject(result).toString()); //對后出手的發送消息結束 }else{//偶數時沒有查詢到與之對應的對手,則其變為奇數,成為等待匹配的人 index--; result.setMessage("系統:等待玩家匹配!"); this.sendMessage(JSONObject.fromObject(result).toString()); } }else{ result.setMessage("系統:等待玩家匹配!"); this.sendMessage(JSONObject.fromObject(result).toString()); } this.mykey = index; webSocketMap.put(mykey+"", this); //加入map中 System.out.println(webSocketMap.size()); } catch (Exception e) { e.printStackTrace(); } } /** * 連接關閉調用的方法 * @throws IOException */ @OnClose public void onClose(){ webSocketMap.remove(mykey+""); //從set中刪除 try { WebSocket socket = null; if(mykey%2==0){ socket = webSocketMap.get((mykey-1)+""); }else{ socket = webSocketMap.get((mykey+1)+""); } if(socket!=null){ Result result = new Result(); result.setMessage("你的對手已離開!"); socket.sendMessage(JSONObject.fromObject(result).toString()); } } catch (Exception e) { e.printStackTrace(); } } /** * 收到客戶端消息后調用的方法 * @param message 客戶端發送過來的消息 * @param session 可選的參數 */ @OnMessage public void onMessage(String message) { System.out.println(message); JSONObject json = JSONObject.fromObject(message); Result result = (Result) JSONObject.toBean(json,Result.class); try { WebSocket socket = null; if(mykey%2==0){ socket = webSocketMap.get((mykey-1)+""); }else{ socket = webSocketMap.get((mykey+1)+""); } if(socket!=null){ if(result.getXy()!=null&&!"".equals(result.getXy())){//有坐標表示為落子,反之則為發送信息 this.sendMessage(message); result.setBout(true);//對手的bout改為true,表示接下來可以落子 result.setMessage("系統:對方已落子,正在等待您落子!"); socket.sendMessage(JSONObject.fromObject(result).toString()); }else{//沒有坐標表示為單純的聊天 Result newResult = new Result(); newResult.setMessage("自己:"+result.getMessage()); this.sendMessage(JSONObject.fromObject(newResult).toString()); newResult.setMessage("對方:"+result.getMessage()); socket.sendMessage(JSONObject.fromObject(newResult).toString()); } } } catch (Exception e) { e.printStackTrace(); } } /** * 發生錯誤時調用 * @param session * @param error */ @OnError public void onError(Session session, Throwable error){ System.out.println("連接斷開"); // error.printStackTrace(); } /** * 這個方法與上面幾個方法不一樣。沒有用注解,是根據自己需要添加的方法。 * @param message * @throws IOException */ public void sendMessage(String message) throws IOException{ this.session.getBasicRemote().sendText(message); //this.session.getAsyncRemote().sendText(message); } }
只需要上面的4個代碼,當然jquery,json2這些依然還是需要的,同學們新建一個