2013年9月7日星期六

NetBeans_020:开发JavaEE 7 应用之三:使用WebSocket构建聊天室

开发运行环境:NetBeans7.3.1。

1. ChatServer.java

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.glassfish.movieplex7.chat;

import java.io.IOException;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import javax.websocket.EncodeException;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

/**
 *
 * @author pmma
 */
@ServerEndpoint("/websocket")
public class ChatServer {

    private static final Set peers =
            Collections.synchronizedSet(new HashSet());

    @OnOpen
    public void onOpen(Session peer) {
        peers.add(peer);
    }

    @OnClose
    public void onClose(Session peer) {
        peers.remove(peer);
    }

    @OnMessage
    public void message(String message, Session client) throws
            IOException, EncodeException {
        for (Session peer : peers) {
            peer.getBasicRemote().sendObject(message);
        }
    }
}

说明:
(1)@ServerEndpoint标注表明这个类是一个WebSocket Server endpoint,"/websocket"是被发布的URI。
(2)@OnOpen和@OnClose标注表明该方法将在WebSocket session打开和关闭时被调用。
参数peer即连接的客户端。
(3)@OnMessage标注表明当服务端接收到信息时会调用该方法。
参数message即接收到的消息,参数client指的连接到WebSocket的另一端。
代码:peer.getBasicRemote().sendObject(message);会把消息发送给所有连接到WebSocket的客户端。

2. websocket.js

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */


var wsUri = 'ws://' + document.location.host
        + document.location.pathname.substr(0,
        document.location.pathname.indexOf("/faces"))
        + '/websocket';
console.log(wsUri);
var websocket = new WebSocket(wsUri);
var textField = document.getElementById("textField");

var users = document.getElementById("users");
var chatlog = document.getElementById("chatlog");
var username;
websocket.onopen = function(evt) {
    onOpen(evt);
};
websocket.onmessage = function(evt) {
    onMessage(evt);
};
websocket.onerror = function(evt) {
    onError(evt);
};
websocket.onclose = function(evt) {
    onClose(evt);
};
var output = document.getElementById("output");

function join() {
    username = textField.value;
    websocket.send(username + " joined");
}
function send_message() {
    websocket.send(username + ": " + textField.value);
}
function onOpen() {
    writeToScreen("CONNECTED");
}
function onClose() {
    writeToScreen("DISCONNECTED");
}
function onMessage(evt) {
    writeToScreen("RECEIVED: " + evt.data);
    if (evt.data.indexOf("joined") !== -1) {
        users.innerHTML += evt.data.substring(0, evt.data.indexOf("joined")) + "\n";
    } else {
        chatlog.innerHTML += evt.data + "\n";
    }
}

function onError(evt) {
    writeToScreen('ERROR: ' +
            evt.data);
}
function disconnect() {
    websocket.close();
}
function writeToScreen(message) {
    var pre = document.createElement("p");
    pre.style.wordWrap = "break-word";
    pre.innerHTML = message;
    output.appendChild(pre);
}
说明:
(1)变量wsUri即指向ChatServer.java中定义的WebSocket Server endpoint URI。
(2)new WebSocket(wsUri)初始化WebSocket,初始化后,所有生命周期的事件将被注册,即onOpen,onClose,onMessage,onError方法。
(3)send_message和disconnect方法绑定到页面的按钮上,详见chatroom.xthml。

3. chatroom.xhtml

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:ui="http://xmlns.jcp.org/jsf/facelets">

    <body>

        <ui:composition template="./../WEB-INF/template.xhtml">

            <ui:define name="content">
                <form action="">
                    <table>
                        <tr>
                            <td>
                                Chat Log<br/>
                                <textarea readonly="true" rows="6" cols="50" id="chatlog"></textarea>
                            </td>
                            <td>
                                Users<br/>
                                <textarea readonly="true" rows="6" cols="20" id="users"></textarea>
                            </td>
                        </tr>
                        <tr>
                            <td colspan="2">
                                <input id="textField" name="name" value="Duke" type="text"/>
                                <input onclick="join();" value="Join" type="button"/>
                                <input onclick="send_message();" value="Send" type="button"/><p/>
                                <input onclick="disconnect();" value="Disconnect" type="button"/>
                            </td>
                        </tr>
                    </table>
                </form>
                <div id="output"></div>
                <script language="javascript" type="text/javascript" src="${facesContext.externalContext.requestContextPath}/chat/websocket.js"></script>
            </ui:define>

        </ui:composition>

    </body>
</html>

4. 运行效果
注意,需要使用支持WebSocket的浏览器才可以正确运行。
支持WebSocket的主流浏览器有:Chrome 14.0+,Firefox 11.0+,Safari 6.0+,IE 10.0+。
更多支持WebSocket的浏览器请看这里:http://caniuse.com/websockets。
(1)打开一个浏览器
 (2)点击Join
 (3)再打开一个浏览器
在两个浏览器中,分别点击Join,然后点击Send发送消息,在两个浏览器中都可以看到对方加入和发送的信息。


Project 下载:4.movieplex7(WebSocket).7z

没有评论: