基于webSocket实现的一对一在线聊天系统

来源:互联网 发布:java 接口变量 编辑:程序博客网 时间:2024/04/30 08:40

简单介绍一下websocket(来自网络):随着互联网的发展,传统的HTTP协议已经很难满足Web应用日益复杂的需求了。近年来,随着HTML5的诞生,WebSocket协议被提出,它实现了浏览器与服务器的全双工通信,扩展了浏览器与服务端的通信功能,使服务端也能主动向客户端发送数据。

环境:
tomcat7.0.70(tomcat需要在7.0.27以上才能支持)
jdk1.8.0_92
eclipse

重要的类和注解:
CopyOnWriteArraySet 多对多聊天
ConcurrentHashMap 一对一聊天
Session(websocket包下的)
@ServerEndpoint()
@OnOpen
@OnClose
@OnMessage
@OnError
@PathParam

后台代码实现:
package com.bz.chat;import java.io.IOException;import java.util.HashMap;import java.util.Map;import java.util.concurrent.ConcurrentHashMap;import javax.servlet.ServletException;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;import javax.servlet.http.HttpServlet;import javax.websocket.OnClose;import javax.websocket.OnError;import javax.websocket.OnMessage;import javax.websocket.OnOpen;import javax.websocket.Session;import javax.websocket.server.PathParam;import javax.websocket.server.ServerEndpoint;import net.sf.json.JSONObject;//该注解用来指定一个URI,客户端可以通过这个URI来连接到WebSocket。类似Servlet的注解mapping。无需在web.xml中配置。//chatDemo:表示访问的具体url。{sendUser}:表示在url上的参数@ServerEndpoint("/chatDemo/{sendUser}")public class Chat{// 用户在线数private static int onLineCount = 0;// 当前的websocket对象private static ConcurrentHashMap<Integer, Chat> webSocketMap = new ConcurrentHashMap<Integer, Chat>();// 当前会话,属于websocket的sessionprivate Session session;// 聊天信息private Integer sendUser;// 当前用户private Integer toUser;// 接收人private String message;// 聊天信息/** * 连接建立成功调用的方法 * @param session 可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据 * @PathParam("sendUser") 表示可以在访问的时候带上参数,参数:sendUser为  @ServerEndpoint("/chatDemo/{sendUser}") * @throws IOException */@OnOpenpublic void onOpen(@PathParam("sendUser") Integer sendUser,Session session) throws IOException {this.sendUser = sendUser;this.session = session;addOnlineCount();System.out.println("有新连接加入!当前在线人数为" + getOnlineCount() + " 当前session是" + session.hashCode());webSocketMap.put(sendUser, this);//当前用户的websocket// 刷新在线人数for (Chat chat : webSocketMap.values()) {//使用if判断是要统计人数还是发送消息chat.sendMessage("count",getOnlineCount() + "");}}/** * 连接关闭所调用的方法 *  * @return * @throws IOException  */@OnClosepublic void onClose() throws IOException {// 在线数减1subOnlineCount();for (Chat chat : webSocketMap.values()) {//说明当前的session已经被关闭if(chat.session != this.session){chat.sendMessage("count", getOnlineCount() + "");}}webSocketMap.remove(sendUser);System.out.println("有一连接关闭!当前在线人数为" + getOnlineCount());}/** * 收到客户端的消息后所调用的方法 *  * @param message  客户端发送过来的消息 * @param session  可选的参数,同上 * @throws IOException */@OnMessagepublic void onMessage(String jsonMsg, Session session) throws IOException {JSONObject jsonOject = JSONObject.fromObject(jsonMsg);sendUser = Integer.parseInt(jsonOject.getString("sendUser"));toUser = Integer.parseInt(jsonOject.getString("toUser"));message = jsonOject.getString("message");message = "来自:" + sendUser + "用户发给" + toUser + "用户的信息:" + message + " \r\n";// 得到接收人Chat user = webSocketMap.get(toUser);if (user == null) {//如果接收人不存在则保持到数据库System.out.println("信息已保存到数据库");return;}user.sendMessage("send",message);}/** * 发成错误所调用的方法 * @param session * @param error */@OnErrorpublic void onError(Session session, Throwable error) {System.out.println("发生错误");error.printStackTrace();}/** * 这个方法与上面几个方法不一样。没有用注解,是根据自己需要添加的方法。 * @param type 根据类型判断是要进行在线人数统计还是发送消息  count:人数统计  send:发送消息 * @param message * @param receive * @throws IOException */public void sendMessage(String type,String message) throws IOException {if(type.equals("count")){this.session.getBasicRemote().sendText("count:" + message);//在jsp判断是否包含count}else{this.session.getBasicRemote().sendText(message);//提供阻塞式的消息发送方式// this.session.getAsyncRemote().sendText(message);//提供非阻塞式的消息传输方式。}}// 获得当前在线人数public static synchronized int getOnlineCount() {return onLineCount;}// 新用户public static synchronized void addOnlineCount() {Chat.onLineCount++;}// 移除退出用户public static synchronized void subOnlineCount() {Chat.onLineCount--;}}

前端页面实现:
<%@ page language="java" contentType="text/html; charset=UTF-8"    pageEncoding="UTF-8"%><%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>webScocket一对一聊天</title><script type="text/javascript">    var websocket = null;function login(){if('WebSocket' in window){ var sendUser = document.getElementById("sendUser").value; document.getElementById("sendUser").disabled = true;websocket = new WebSocket("ws://localhost:8080/websocket/chatDemo/" + sendUser);        }else{              alert('Not support websocket')        }//连接发生错误的回调方法          websocket.onerror = function(){          document.getElementById('status').innerHTML="error";          };                     //连接成功建立的回调方法          websocket.onopen = function(event){         document.getElementById('status').innerHTML="连接服务器成功";          }                     //接收到消息的回调方法          websocket.onmessage = function(event){          //判断分割是统计人数还是显示消息          if(event.data.indexOf("count")>-1){          var msg = event.data;          var data = msg.split(":");          document.getElementById('count').innerHTML=data[1];          }else{          setMessageInnerHTML(event.data);          }          }                     //连接关闭的回调方法          websocket.onclose = function(){          document.getElementById('status').innerHTML="连接被成功关闭";          }                    //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。          window.onbeforeunload = function(){              websocket.close();          }}      //将消息显示在网页上      function setMessageInnerHTML(innerHTML){          document.getElementById('showMsg').innerHTML += innerHTML;      }             //关闭连接      function closeWebSocket(){          websocket.close();      }             //发送消息      function send(){     var sendUser = document.getElementById("sendUser").value;     var toUser = document.getElementById("toUser").value;     var message = document.getElementById("message").value;         var jsonMsg = {"sendUser":sendUser,"toUser":toUser,"message":message}         websocket.send(JSON.stringify(jsonMsg));                  document.getElementById('showMsg').innerHTML += message;      }</script></head><body>账 号:<input type="text" name="sendUser" id="sendUser"/> <input type="button" id="login" value="登录" onclick="login()"/> <input type="button" onclick="closeWebSocket()"  value="退出"/> 在线人数:<font id="count"></font>   连接状态:<font id="status"></font><br/>接收人:<input type="text" name="toUser" id="toUser"/><br/>消息框:<br/> <textarea rows="5" cols="5" id="showMsg" name="showMsg" disabled="disabled" style="width: 302px; height: 111px; "></textarea><br/>   <textarea rows="5" cols="5" id="message" name="sendMsg" style="width: 302px; height: 111px; "></textarea><br/><input type="button" value="发送" onclick="send()"/> <input type="button" value="关闭" onclick="closeWebSocket()"/></body></html>

演示:

0 0