java-websocket即时通讯-聊天室

来源:互联网 发布:微信无法连接网络 编辑:程序博客网 时间:2024/06/08 09:40

效果预览


聊天室截图

web即时通讯的解决方式


  • 轮询:简单粗暴,过多的请求,服务器表示压力很大
  • 长连接:发送请求到服务器,有消息时才返回,长时间占用资源
  • websocket:基于tcp新的协议,双向通信

    废话少说,上代码(部分关键代码)!

html

<style>    #chatroom_container{width:600px;height:500px;margin:70px auto 0px auto;background:#fff;border-radius:4px;overflow:hidden;box-shadow:0px 0px 20px #666;}    #east{float:right;width:130px;height:350px;}    #center{float:left;width:469px;height:350px;box-sizing:border-box;padding:8px;border-right:1px solid #ddd;overflow-y:auto;}    #south{width:100%;height:40px;border-top:1px solid #ddd;position:absolute;left:0;bottom:0;box-sizing:border-box;padding:10px;background:#fff;}    #chat{width:100%;height:100%;box-sizing:border-box;}    #sendButton{position:absolute;bottom:5px;right:6px;}    .record{margin:6px 5px;}    .onlineStaff{margin:3px 4px;padding:3px 4px;cursor:pointer;}    .onlineStaff:hover{background:#f0f0f0;}</style><div id="chatroom_container">    <div id="north">交流平台</div>    <div id="online"></div>    <div id="center">        <div id="console"></div>    </div>    <div id="east"></div>    <div style="clear:both;"></div>    <div id="south">        <textarea id="chat" ></textarea>        <div id="sendButton" onclick="Chat.sendMessage()">发送</div>    </div></div>

js

var Chat = {};Chat.socket = null;Chat.connect = (function(host){    if ('WebSocket' in window) {        Chat.socket = new WebSocket(host);    } else if ('MozWebSocket' in window) {        Chat.socket = new MozWebSocket(host);    } else {        Console.log('Error: WebSocket is not supported by this browser.');        return;    }    //websocket连接打开时    Chat.socket.onopen = function () {        document.getElementById('chat').onkeydown = function(event) {            if (event.keyCode == 13) {                Chat.sendMessage();                event.returnValue = false;                event.preventDefault();            }        };    };    //websocket连接关闭时    Chat.socket.onclose = function () {        document.getElementById('chat').onkeydown = null;    };    //websocket连接有消息时    Chat.socket.onmessage = function (message) {        var data = eval('(' + message.data + ')');        //data即为后台发送的数据,在此根据数据内容进行判断属于Chat.info | Chat.self | Chat.other    }});//初始化Chat.initialize = function() {    if (window.location.protocol == 'http:') {        Chat.connect('ws://' + window.location.host + '/websocket/chat');    } else {        Chat.connect('wss://' + window.location.host + '/websocket/chat');    }};//发送的方法Chat.sendMessage = (function() {    var message = document.getElementById('chat').value;    if (message != '') {        var data = {            'from':'',            'to':'',            'groupId':'',            'type':'',            'message':message        }//from,to,type为后期私聊,群里        var msg = JSON.stringify(data);        Chat.socket.send(msg);        document.getElementById('chat').value = '';    }});var Console = {};//聊天主窗体//负责展现系统提示,例如 小明进入Console.info = (function(message) {    var h = '<div style="text-align:center;color:#aca;margin:5px auto;">'+ message +'</div>';    $('#center').append(h);});//负责展现自己发送的消息,显示在右边Console.self=(function(data){    var h = '';    //将data解析为html片段    $('#center').append(h);});//负责展现其他人发送的消息,显示在左边Console.other=(function(data){    var h = '';    //将data解析为html片段    $('#center').append(h);});Chat.initialize();

java后台

  • 核心处理类ChatWebSocket.java,负责websocket连接/关闭/收发消息的整个过程
  • 消息类WebSocketMessage.java,发送消息的载体
  • 消息处理类ServerEncoder.java,将消息进行编码转json设置
  • 配置类GetHttpSessionConfigurator.java,获取httpSession

ChatWebSocket.java

websocket连接/关闭/收发消息的整个过程

@ServerEndpoint(value = "/websocket/chat", configurator = GetHttpSessionConfigurator.class, encoders = ServerEncoder.class)public class ChatWebSocket {    //存储所有的websocket连接    private static final Map<String, ChatWebSocket> CONNECTIONS = new LinkedHashMap<String, ChatWebSocket>();    private User user;    private Session session;    /**    * 当websocket握手成功时触发    * 该方法参数是可选的,session指的是websocket的session,不是httpSession.    * 获取httpSession需要通过EndpointConfig类,而EndpointConfig类是由@ServerEndpoin()中的configurator进行设置    */    @OnOpen    public void start(Session session, EndpointConfig config){        this.session = session;                    HttpSession httpSession = (HttpSession) config.getUserProperties().get(HttpSession.class.getName());        WebSocketMessage webSocketMessage = new WebSocketMessage();        if(httpSession == null){            webSocketMessage.setMessage("您未登录系统");            ChatWebSocket.sendToOne(this,webSocketMessage);            try {                this.session.close();            } catch (IOException e) {                e.printStackTrace();            }        }else{            //获取httpSession中登录的用户            User user = (User) httpSession.getAttribute("currentUser");            if(user == null){                webSocketMessage.setMessage("登录错误,未知用户");                ChatWebSocket.sendToOne(this,webSocketMessage);                try {                    this.session.close();                } catch (IOException e) {                    e.printStackTrace();                }            }else{                this.user = user;                CONNECTIONS.put(this.user.getId(), this);                webSocketMessage.setUserId(this.user.getId());                ChatWebSocket.sendToOne(this,webSocketMessage);                String msg = this.user.getName() + " 进入";                ChatWebSocket.broadcastOnline(msg);            }        }    }    //当websocket握手关闭时触发    @OnClose    public void end(){        CONNECTIONS.remove(this.user.getId());        String msg = this.user.getName() + " 离开";        ChatWebSocket.broadcastOnline(msg);    }    //当收到消息时    @OnMessage    public void incoming(String message){        WebSocketMessage webSocketMessage = new WebSocketMessage();        webSocketMessage.setUserId(this.user.getId());        webSocketMessage.setUserName(this.user.getName());        webSocketMessage.setMessage(message);        webSocketMessage.setSendDate(new Date());        ChatWebSocket.broadcast(webSocketMessage);    }    //发送至单独用户    private static void sendToOne(ChatWebSocket chatWebSocket,            WebSocketMessage webSocketMessage) {        chatWebSocket.session.getAsyncRemote().sendObject(webSocketMessage);    }    //广播    private static void broadcast(WebSocketMessage webSocketMessage) {        Set<String> keys = CONNECTIONS.keySet();        for (String key : keys) {            ChatWebSocket chatWebSocket = CONNECTIONS.get(key);            synchronized (chatWebSocket) {                ChatWebSocket.sendToOne(chatWebSocket, webSocketMessage);            }        }    }    //广播在线用户    private static void broadcastOnline(String msg) {        Set<String> keys = CONNECTIONS.keySet();        WebSocketMessage webSocketMessage = new WebSocketMessage();        webSocketMessage.setType(WebSocketMessage.WEBSOCKETMESSAGE_TYPE_ALL);        webSocketMessage.setMessage(msg);        List<UserAO> userList = new ArrayList<UserAO>();        for (String key : keys) {            ChatWebSocket chatWebSocket = CONNECTIONS.get(key);            userList.add(chatWebSocket.user);        }        webSocketMessage.getAttributes().put("user", userList);        for (String key : keys) {            ChatWebSocket chatWebSocket = CONNECTIONS.get(key);            synchronized (chatWebSocket) {                ChatWebSocket.sendToOne(chatWebSocket, webSocketMessage);            }        }    }}

WebSocketMessage.java

发送消息的载体

public class WebSocketMessage {    private String userId;    private String userName;    private string from;    private string to;    private string groupId;    ...    private String message;    private Date sendDate;    private String type;    private Map<String,Object> attributes = new HashMap<String, Object>();    public WebSocketMessage(){        super();    }    public WebSocketMessage(String userName,String message,Date sendDate) {        this.userName = userName;        this.sendDate = sendDate;        this.message = message;    }    //getter and setter ...}

ServerEncoder.java

将消息进行编码转json设置

public class ServerEncoder implements Encoder.Text<WebSocketMessage> {    @Override    public void init(EndpointConfig paramEndpointConfig) {        // TODO Auto-generated method stub    }    @Override    public void destroy() {        // TODO Auto-generated method stub    }    @Override    public String encode(WebSocketMessage paramT) throws EncodeException {        //将WebSocketMessage转为json        return JsonMapper.buildNormalMapper().toJson(paramT);    }}

GetHttpSessionConfigurator

获取httpSession

public class GetHttpSessionConfigurator extends Configurator {    @Override    public void modifyHandshake(ServerEndpointConfig sec,            HandshakeRequest request, HandshakeResponse response) {        HttpSession httpSession=(HttpSession) request.getHttpSession();        if(httpSession!=null){            sec.getUserProperties().put(HttpSession.class.getName(),httpSession);        }            }}

以上只是部分关键代码,简单的实现了即时通讯,若需要私聊,群聊,分组等功能,则需改造WebSocketMessage.java和前端js中Chat.socket.onmessage()