Message =>JSON => Move
客户端发给服务器总是Move server.send(JSON.stringify({row: row, column: column})); 服务端(Move move = TicTacToeServer.mapper.readValue(message, Move.class);)
服务端发给客户端总是Message session.getBasicRemote() .sendText(TicTacToeServer.mapper.writeValueAsString(message));
【javascript客户端】
1.创建websocket连接
// ws[s]://localhost/ticTacToe/${gameId}/${username}?action=${action}
server = new WebSocket('ws://' + window.location.host +
'<c:url value="/ticTacToe/${gameId}/${username}">'+
'<c:param name="action" value="${action}" /></c:url>');
//view = f(state)
server.onopen = function (event) {
modalWaitingBody
.text('Waiting on your opponent to join the game.');
modalWaiting.modal({keyboard: false, show: true});
};
【Server】
public void onOpen(Session session, @PathParam("gameId") long gameId,
@PathParam("username") String username)
{
TicTacToeGame ticTacToeGame = TicTacToeGame.getActiveGame(gameId);
//动作
List<String> actions = session.getRequestParameterMap().get("action");
if(actions != null && actions.size() == 1)
{
String action = actions.get(0);
if("start".equalsIgnoreCase(action))
{
Game game = new Game();//新建一个游戏
game.gameId = gameId;//路径参数
game.player1 = session;//一个玩家就是一个session
TicTacToeServer.games.put(gameId, game);//往内存数据库
}
else if("join".equalsIgnoreCase(action))
{
Game game = TicTacToeServer.games.get(gameId);//获得同一个游戏准备加入
game.player2 = session;//一个玩家就是一个session
game.ticTacToeGame = TicTacToeGame.startGame(gameId, username);//游戏里面p1在等,开始游戏
this.sendJsonMessage(game.player1, game,
new GameStartedMessage(game.ticTacToeGame));//服务器往客户端玩家发送消息
this.sendJsonMessage(game.player2, game,
new GameStartedMessage(game.ticTacToeGame));
}
}
}
2.【通信】客户端send 出去
move = function (row, column) {
if (!myTurn) {
modalErrorBody.text('It is not your turn yet!');
modalError.modal('show');
return;
}
if (server != null) {
//转换Object字面量 为json
server.send(JSON.stringify({row: row, column: column}));
$('#r' + row + 'c' + column).unbind('click')
.removeClass('game-cell-selectable')
.addClass('game-cell-player game-cell-taken');
toggleTurn(false);
} else {
modalErrorBody.text('Not connected to came server.');
modalError.modal('show');
}
};
【Server】发给客户端
@OnMessage
public void onMessage(Session session, String message,
@PathParam("gameId") long gameId)
{
Game game = TicTacToeServer.games.get(gameId);
boolean isPlayer1 = session == game.player1; try
{
//经过ObjectMapper 反序列化客户端的Message成服务端的Move
Move move = TicTacToeServer.mapper.readValue(message, Move.class);
game.ticTacToeGame.move(
isPlayer1 ? TicTacToeGame.Player.PLAYER1 :
TicTacToeGame.Player.PLAYER2,
move.getRow(),
move.getColumn()
);
//发回给客户端 json 消息
this.sendJsonMessage((isPlayer1 ? game.player2 : game.player1), game,
new OpponentMadeMoveMessage(move));
if(game.ticTacToeGame.isOver())
{
if(game.ticTacToeGame.isDraw())
{
this.sendJsonMessage(game.player1, game,
new GameIsDrawMessage());
this.sendJsonMessage(game.player2, game,
new GameIsDrawMessage());
}
else
{
boolean wasPlayer1 = game.ticTacToeGame.getWinner() ==
TicTacToeGame.Player.PLAYER1;
this.sendJsonMessage(game.player1, game,
new GameOverMessage(wasPlayer1));
this.sendJsonMessage(game.player2, game,
new GameOverMessage(!wasPlayer1));
}
game.player1.close();
game.player2.close();
}
}
catch(IOException e)
{
this.handleException(e, game);
}
}
接收服务器发的消息
server.onmessage = function (event) {
var message = JSON.parse(event.data);
if (message.action == 'gameStarted') {
if (message.game.player1 == username)
opponentUsername = message.game.player2;
else
opponentUsername = message.game.player1;
opponent.text(opponentUsername);
toggleTurn(message.game.nextMoveBy == username);
modalWaiting.modal('hide');
} else if (message.action == 'opponentMadeMove') {
$('#r' + message.move.row + 'c' + message.move.column)
.unbind('click')
.removeClass('game-cell-selectable')
.addClass('game-cell-opponent game-cell-taken');
toggleTurn(true);
} else if (message.action == 'gameOver') {
toggleTurn(false, 'Game Over!');
if (message.winner) {
modalGameOverBody.text('Congratulations, you won!');
} else {
modalGameOverBody.text('User "' + opponentUsername +
'" won the game.');
}
modalGameOver.modal('show');
} else if (message.action == 'gameIsDraw') {
toggleTurn(false, 'The game is a draw. ' +
'There is no winner.');
modalGameOverBody.text('The game ended in a draw. ' +
'Nobody wins!');
modalGameOver.modal('show');
} else if (message.action == 'gameForfeited') {
toggleTurn(false, 'Your opponent forfeited!');
modalGameOverBody.text('User "' + opponentUsername +
'" forfeited the game. You win!');
modalGameOver.modal('show');
}
};
【与websocket无关提供请求参数】【TicTacToeServlet(url、post变量、)和list.jsp(菜单)】
Servlet => list.jsp 发送attribute pendingGames(相当于qq游戏房间)
【list.jsp=>Servlet】关键代码
post({action: 'join', username: username, gameId: gameId});
var post = function(fields) {
//构造隐藏表单,仅为了doPost方法
var form = $('<form id="mapForm" method="post"></form>')
.attr({ action: url, style: 'display: none;' });
for(var key in fields) {
//字面量传进来 转化成隐藏域
if(fields.hasOwnProperty(key))
form.append($('<input type="hidden">').attr({
name: key, value: fields[key]
}));
}
$('body').append(form);
form.submit();
};