基于WebSocket的网页端即时通讯
来源:互联网 发布:淘宝推广工具 编辑:程序博客网 时间:2024/05/29 15:12
基于WebSocket的网页端即时通讯
最近项目中需要用到一些即时通讯的相关技术,查阅了一些资料后发现有些示例不是让人很满意,所以博主写了一个demo,就怕以后会忘掉,也方便博友查看。
由于博主用的是SSM(springMVC+spring+MyBatis)框架,所以肯定要首选spring自带的WebSocket了。
我们先看一下最终实现的效果。
1、这里两个用户用的接口分别是:http://localhost:8090/myProject/demo/webSocketTest/user001
表示user001用户,http://localhost:8090/myProject/demo/webSocketTest/user002表示user002用户。下面的controller里会讲到模拟登录。
2、当user002用户断开连接时,再想user002用户发送消息时显示user002用户不在线!
3、当user002用户再次连接时,两个用户又可以进行通讯了。
代码实现
1、初始页面的controller
package com.jh.controller;import org.springframework.stereotype.Controller;import org.springframework.ui.Model;import org.springframework.web.bind.annotation.PathVariable;import org.springframework.web.bind.annotation.RequestMapping;/** * webSocketDemo * @author JiHao * */@Controller@RequestMapping(value = "/demo")public class MyWebSocketController { /** * @param userId 模拟登录,登录的用户名称 */ @RequestMapping(value = "/webSocketTest/{userId}") public String test(@PathVariable("userId") String userId, Model model) throws Exception { //把登录名称传给jsp页面 model.addAttribute("userId", userId); return "demo/test"; }}
2、初始页面的jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><%String path = request.getContextPath();String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html> <head> <base href="<%=basePath%>"> <title>My JSP 'index.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> <script type="text/javascript"> //判断当前浏览器是否支持WebSocket if('WebSocket' in window){ websocket = new WebSocket("ws://localhost:8090/myProject/websocketTest/" + '${userId}'); console.log("link success"); }else{ alert('Not support websocket'); } //连接发生错误的回调方法 websocket.onerror = function(){ setMessageInnerHTML("error"); }; //连接成功建立的回调方法 websocket.onopen = function(event){ setMessageInnerHTML("open"); }; //接收到消息的回调方法 websocket.onmessage = function(event){ console.log(event.data); setMessageInnerHTML(event.data); }; //连接关闭的回调方法 websocket.onclose = function(){ setMessageInnerHTML("close"); }; //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。 window.onbeforeunload = function(){ websocket.close(); }; //将消息显示在网页上 function setMessageInnerHTML(innerHTML){ document.getElementById('returnMessage').innerHTML += innerHTML + '<br/>'; } //关闭连接 function closeWebSocket(){ websocket.close(); document.getElementById('send').disabled = true; document.getElementById('close').disabled = true; document.getElementById('connect').disabled = false; } //发送消息 function send(){ //接收者名称 var toName = document.getElementById('toName').value; if('' == toName){ alert("请填写接收者"); return; } //发送的消息 var message = document.getElementById('message').value; if('' == message){ alert("请填写发送信息"); return; } websocket.send(toName+"-f,t-"+message); } function connect() { //判断当前浏览器是否支持WebSocket if('WebSocket' in window){ websocket = new WebSocket("ws://localhost:8090/myProject/websocketTest/" + '${userId}'); console.log("link success"); document.getElementById('send').disabled = false; document.getElementById('close').disabled = false; document.getElementById('connect').disabled = true; }else{ alert('Not support websocket'); } //连接发生错误的回调方法 websocket.onerror = function(){ setMessageInnerHTML("error"); }; //连接成功建立的回调方法 websocket.onopen = function(event){ setMessageInnerHTML("open"); }; //接收到消息的回调方法 websocket.onmessage = function(event){ console.log(event.data); setMessageInnerHTML(event.data); }; //连接关闭的回调方法 websocket.onclose = function(){ setMessageInnerHTML("close"); }; //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。 window.onbeforeunload = function(){ websocket.close(); }; } </script> </head> <body> webSocket Demo---- ${userId} <br /> 发送给谁:<input id="toName" type="text" /><br> 发送内容:<input id="message" type="text" /><br> <button id="send" onclick="send()"> Send </button> <button id="close" onclick="closeWebSocket()"> Close </button> <button id="connect" onclick="connect();" disabled="disabled">Connect</button> <div id="returnMessage"></div> </body></html>
这里我把自己写的jsp代码全都复制了过来,仅供参考。
浏览器加载时调用的几个重要的WebSocket API示例
if(‘WebSocket’ in window){
websocket = new WebSocket(“ws://localhost:8090/myProject/websocketTest/” + ‘${userId}’);
console.log(“link success”);
}else{
alert(‘Not support websocket’);
}
websocket.onopen = function(){setMessageInnerHTML(“open”);};
websocket.onmessage = function(evt){setMessageInnerHTML(event.data);};
websocket.onclose = function(){setMessageInnerHTML(“close”);};
websocket.onerror = function(){setMessageInnerHTML(“error”);};
window.onbeforeunload = function(){websocket.close();};
浏览器中用到的几个重要的方法
1、function send(){} 发送消息的方法
2、function closeWebSocket(){} 关闭连接的方法
3、function connect(){} 重新建立连接的方法
3、创建@ServerEndpoint注解类
package com.jh.util.websocket;import java.io.IOException;import java.util.HashMap;import java.util.Map;import java.util.concurrent.CopyOnWriteArraySet;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;/** * MyWebSocket * @author JiHao * */@ServerEndpoint(value = "/websocketTest/{userId}")public class MyWebSocket { //静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。 private static int onlineCount = 0; //concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。但为了实现服务端与单一客户端通信,用Map来存放,其中Key可以为用户标识 private static CopyOnWriteArraySet<Map<String, MyWebSocket>> mapSocket = new CopyOnWriteArraySet<Map<String, MyWebSocket>>(); private static CopyOnWriteArraySet<Map<String, Session>> mapSession = new CopyOnWriteArraySet<Map<String, Session>>(); //当前用户 private String userId; /** * 连接时执行 * @param userId 当前用户名称 * @param session 当前用户session * @throws Exception */ @OnOpen public void onOpen(@PathParam("userId") String userId,Session session) throws Exception { //存放当前用户的MyWebSocket对象 Map<String, MyWebSocket> wsSocket = new HashMap<String, MyWebSocket>(); //用map建立用户和当前用户的MyWebSocket对象关系 wsSocket.put(userId, this); mapSocket.add(wsSocket); //存放当前用户的session对象 Map<String, Session> wsSession = new HashMap<String, Session>(); //用map建立用户和当前用户的session对象关系 wsSession.put(userId, session); mapSession.add(wsSession); //在线数加1 addOnlineCount(); this.userId = userId; System.out.println("有新连接加入!当前在线人数为" + getOnlineCount()); } /** * 关闭时执行 */ @OnClose public void onClose(){ //删除当前用户的MyWebSocket对象和session对象,并且人数减1 removeCurrentUser(); System.out.println("有一连接关闭!当前在线人数为" + getOnlineCount()); } /** * 收到消息时执行 */ @OnMessage public void onMessage(String message, Session session) throws IOException { System.out.println("来自客户端的消息:" + message); String[] messages = message.split("-f,t-"); //接收者名称 String toName = messages[0].trim(); //发送给接收者的信息 String toMessage = 1 >= messages.length ? "" : messages[1]; //用户判断接收者是否存在 boolean flag = false; //发消息 for(Map<String, MyWebSocket> item: mapSocket){ try { for (String key : item.keySet()) { if(toName.equals(key)){ flag = true; MyWebSocket myWebSocket = item.get(key); myWebSocket.sendMessage(key, toMessage); } } } catch (IOException e) { e.printStackTrace(); continue; } } if(!flag){ session.getBasicRemote().sendText(toName + "用户不在线!"); //回复用户 }// //这里注释掉的内容是群发消息// for(Map<String, MyWebSocket> item: mapSocket){ // try {// for (String key : item.keySet()) {// MyWebSocket myWebSocket = item.get(key);// myWebSocket.sendMessage(key, toMessage);// }// } catch (IOException e) {// e.printStackTrace();// continue;// }// } } /** * 发送消息。 * @param message * @throws IOException */ public void sendMessage(String toName, String toMessage) throws IOException{ for(Map<String, Session> item: mapSession){ try { for (String string : item.keySet()) { if(toName.equals(string)){ Session toSession = item.get(string); toSession.getBasicRemote().sendText(toMessage); } } } catch (IOException e) { e.printStackTrace(); continue; } } } /** * 删除当前用户的MyWebSocket对象和session对象,并且人数减1 */ public void removeCurrentUser(){ //删除当前用户的WebSocket for(Map<String, MyWebSocket> item: mapSocket){ for (String string : item.keySet()) { if(userId.equals(string)){ mapSocket.remove(item); } } } //删除当前用户的session for(Map<String, Session> item: mapSession){ for (String string : item.keySet()) { if(userId.equals(string)){ mapSession.remove(item); } } } //在线数量减1 subOnlineCount(); } /** * 连接错误时执行 */ @OnError public void onError(Session session, Throwable error){ System.out.println("用户id为:{}的连接发送错误" + this.userId); error.printStackTrace(); } public static synchronized int getOnlineCount() { return onlineCount; } public static synchronized void addOnlineCount() { MyWebSocket.onlineCount++; } public static synchronized void subOnlineCount() { MyWebSocket.onlineCount--; }}
这些代码可以复制直接使用,博主已经调试过了,代码里也做了相应的注释,博友可以仔细查看。
@ServerEndpoint注解类中主要使用的几个注解方法的监听函数
1、@OnOpen 当网络连接建立时触发该事件
2、@OnMessage 接收到服务器发来的消息的时触发的事件,也是通信中最重要的一个监听事件。
3、@OnClose 当websocket被关闭时触发该事件
4、@OnError 当websocket当网络发生错误时触发该事件
博主的这篇demo博文写的比较简单,如果有博友看的不是很清楚的,这里提供一个参考地址:
https://www.cnblogs.com/davidwang456/p/4786636.html
- 基于WebSocket的网页端即时通讯技术
- 基于WebSocket的网页端即时通讯
- 基于websocket协议的即时通讯webapp(摘自本人毕业论文)
- Websocket全讲解。跨平台的通讯协议 !!基于websocket的高并发即时通讯服务器开发
- 基于websocket技术的网页弹幕实现
- JavaWeb网页聊天室(WebSocket即时通讯)
- 基于Spring+SpringMVC+MyBatis+Websocket的网页聊天尝试
- WebSocket集成XMPP网页即时通讯3:二进制文件收发
- WebSocket集成XMPP网页即时通讯2:Openfire网关集成
- 基于XMPP的即时通讯
- SpringBoot中WebSocket的应用:即时通讯
- 基于Tomcat的WebSocket
- 基于Tomcat的WebSocket
- 基于Tomcat的WebSocket
- 基于Tomcat的WebSocket
- 基于Tomcat的WebSocket
- 基于tomcat7的websocket
- 基于xmpp的android即时通讯
- Java将字符串按指定长度分割
- Linux上配置Jupyter Notebook远程访问
- Java多线程:notify/notifyAll/wait/sleep在多线程中的区别于使用
- spring -IOC和DI
- java如何处理linux名字乱码批量重命名问题
- 基于WebSocket的网页端即时通讯
- laravel databas
- (转)Android 使用极光/友盟推送,APP进程杀死后为什么收不到推送
- servlet session管理之一 重写
- as gradle和gradle插件的配置
- Uva10795 新汉诺塔问题(转化模型,经典题)
- php快速高效验证邮箱,长度限制
- Python编程笔记
- mybatis 里面使用<if test=""> 判断,当后台传的值是数字字符串时,怎么处理