基于WebSocket实现的用户与用户聊天
一、WebSocket的概述
WebSocket协议支持(在受控环境中运行不受信任的代码的)客户端与(选择加入该代码的通信的)远程主机之间进行全双工通信。用于此的安全模型是Web浏览器常用的基于原始的安全模式。 协议包括一个开放的握手以及随后的TCP层上的消息帧。 该技术的目标是为基于浏览器的、需要和服务器进行双向通信的(服务器不能依赖于打开多个HTTP连接(例如,使用XMLHttpRequest或<iframe>和长轮询))应用程序提供一种通信机制。
(摘抄自百度百科)
二、websocket的使用
在这一次的远航政务项目中,有一个需要员工之间进行聊天的功能,由于第一次接触浪费了很多做项目的时间,所以在这里记录下来,避免以后遇到这样的问题又要重新搜百度。
首先贴前端代码:
var websocket = null;
var loginid=sessionStorage.getItem('employeeId');
var loginname=sessionStorage.getItem('employeeName');
//判断当前浏览器是否支持WebSocket
if ('WebSocket' in window) {
websocket = new WebSocket("ws://localhost:8080/websocket/"+loginid+"/"+loginname);
} else {
alert('Not support websocket')
}
//连接发生错误的回调方法
websocket.onerror = function() {
setMessageInnerHTML("error");
};
//连接成功建立的回调方法
websocket.onopen = function(event) {
setMessageInnerHTML("open");
}
//接收到消息的回调方法
websocket.onmessage = function(event) {
setMessageInnerHTML(event.data);
console.log(event.data);
}
//连接关闭的回调方法
websocket.onclose = function() {
setMessageInnerHTML("close");
}
//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = function() {
websocket.close();
}
function setMessageInnerHTML(innerHTML) {
var uid = document.getElementById('hh').value;
document.getElementById('message'+uid).innerHTML += innerHTML + '<br/>';
}
//关闭连接
function closeWebSocket() {
websocket.close();
}
//发送消息
function send() {
var message = document.getElementById('textarea').value;
var uid = document.getElementById('hh').value;
if(uid==null || uid==""){
alert("请选择一个人聊天把");
return;
}
var sss = message+"|"+uid;
websocket.send(sss); //发送信息
document.getElementById('textarea').value="";
}
贴后端代码:
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import org.springframework.stereotype.Component;
@ServerEndpoint(value = "/websocket/{loginid}/{loginname}")
@Component
public class Myweb {
// 静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
private static int onlineCount = 0;
// concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
private static ConcurrentHashMap<String, Myweb> webSocketSetas = new ConcurrentHashMap<String, Myweb>();
// 与某个客户端的连接会话,需要通过它来给客户端发送数据
private Session session;
private String userinfo;
/**
* 连接建立成功调用的方法
*/
@OnOpen
public void onOpen(@PathParam("loginid")String loginid,@PathParam("loginname")String loginname, Session session) {
this.session = session;
userinfo = loginid;
System.out.println(userinfo);
System.out.println(loginname);
webSocketSetas.put(loginid, this);
addOnlineCount(); // 在线数加1
System.out.println("有新连接加入!当前在线人数为" + getOnlineCount());
try {
// sendMessage(CommonConstant.CURRENT_WANGING_NUMBER.toString());
sendMessage("建立成功");
} catch (IOException e) {
System.out.println("IO异常");
}
}
/**
* 连接关闭调用的方法
*/
@OnClose
public void onClose() {
webSocketSetas.remove(userinfo); // 从set中删除
subOnlineCount(); // 在线数减1
System.out.println("有一连接关闭!当前在线人数为" + getOnlineCount());
}
/**
* 收到客户端消息后调用的方法
*
* @param message 客户端发送过来的消息
*/
@SuppressWarnings("unused")
@OnMessage
public void onMessage(@PathParam("loginname")String loginname,String message) {
System.out.println("来自客户端的消息:" + message);
String[] ss = message.split("|");
String id = ss[ss.length-1];
System.out.println(id);
System.out.println(ss[0]+"=============");
String sss = "";
for (int i = 2; i <= ss.length; i++) {
sss += ss[i - 1];
}
if ("|".equals(id) || id==null) {
sendAll(loginname,message);
} else {
sendToUser(loginname,message);
}
}
// 给指定的人发送消息
public void sendToUser(String loginname,String message) {
String[] ss = message.split("|");
String sendUserno = ss[ss.length - 1];
String sendMessage = "";
System.out.println(message);
for (int i = 2; i < ss.length; i++) {
sendMessage += ss[i - 2];
}
String sendUsernomessage="<div class=\"atalk\"><img style='width:30px;height:30px;' src='images/user_img/0.jpg'/> <span id=\"asay\">"+sendMessage+"</span> </div>";
String userinfomessage="<div class=\"btalk\"> <span id=\"bsay\">"+sendMessage+"</span> <img style='width:30px;height:30px;' src='images/user_img/0.jpg'/></div>";
try {
if (webSocketSetas.get(sendUserno) != null) {
webSocketSetas.get(userinfo).sendMessage(userinfomessage);
webSocketSetas.get(sendUserno).sendMessage(sendUsernomessage);
} else {
System.out.println("当前用户不在线");
}
} catch (IOException e) {
e.printStackTrace();
}
}
private void sendAll(String loginname,String message) {
String[] ss = message.split("|");
String sendMessage = "";
for (int i = 1; i < ss.length; i++) {
sendMessage += ss[i - 1];
}
String sendUsernomessage="<div class=\"atalk\"><img style='width:30px;height:30px;' src='images/user_img/0.jpg'/> <span id=\"asay\"> "+sendMessage+"</span> </div>";
String userinfomessage="<div class=\"btalk\"> <span id=\"bsay\">"+sendMessage+"</span> <img style='width:30px;height:30px;' src='images/user_img/0.jpg'/></div>";
//遍历HashMap
for (String key : webSocketSetas.keySet()) {
try {
//判断接收用户是否是当前发消息的用户
if (userinfo.equals(key)) {
webSocketSetas.get(userinfo).sendMessage(userinfomessage);
System.out.println("key = " + key);
}else {
webSocketSetas.get(key).sendMessage(sendUsernomessage);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 发生错误时调用
*
* @OnError public void onError(Session session, Throwable error) {
* System.out.println("发生错误"); error.printStackTrace(); }
*/
public void sendMessage(String message) throws IOException {
this.session.getBasicRemote().sendText(message);
// this.session.getAsyncRemote().sendText(message);
}
public static synchronized int getOnlineCount() {
return onlineCount;
}
public static synchronized void addOnlineCount() {
Myweb.onlineCount++;
}
public static synchronized void subOnlineCount() {
Myweb.onlineCount--;
}