基于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">  //判断当前浏览器是否支持WebSocketif('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() {//判断当前浏览器是否支持WebSocketif('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*/@OnOpenpublic 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);//在线数加1addOnlineCount();           this.userId = userId;System.out.println("有新连接加入!当前在线人数为" + getOnlineCount());}/*** 关闭时执行*/@OnClosepublic void onClose(){//删除当前用户的MyWebSocket对象和session对象,并且人数减1removeCurrentUser();System.out.println("有一连接关闭!当前在线人数为" + getOnlineCount());}/*** 收到消息时执行*/@OnMessagepublic 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(){//删除当前用户的WebSocketfor(Map<String, MyWebSocket> item: mapSocket){             for (String string : item.keySet()) {if(userId.equals(string)){mapSocket.remove(item);}}}//删除当前用户的sessionfor(Map<String, Session> item: mapSession){             for (String string : item.keySet()) {if(userId.equals(string)){mapSession.remove(item);}}}//在线数量减1subOnlineCount();}/*** 连接错误时执行*/@OnErrorpublic 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的网页端即时通讯相关推荐

  1. websocket 发送图片_基于WebSocket的web端IM即时通讯应用的开发

    基于WebSocket的web端IM即时通讯应用的开发 功能列表: 1.Web端的IM即时通讯应用 2.支持上线.下线.实时在线提醒 3.单聊.群聊的建立 4.普通文字.表情.图片的传输(子定义富文本 ...

  2. Web端即时通讯技术盘点:短轮询、Comet、Websocket、SSE

    摘要 Web端即时通讯技术因受限于浏览器的设计限制,一直以来实现起来并不容易,主流的Web端即时通讯 方案大致有4种:传统Ajax短轮询.Comet技术.WebSocket技术.SSE(Server- ...

  3. Web端即时通讯实践干货:如何让WebSocket断网重连更快速?

    本文作者网易智慧企业web前端开发工程师马莹莹.为了提升内容质量,收录时有修订和改动. 1.引言 在一个完善的即时通讯IM应用中,WebSocket是极其关键的一环,它为基于Web的即时通讯应用提供了 ...

  4. Android 模块 -- 基于XMPP协议的手机多方多端即时通讯方案

    目   录 基于XMPP协议的手机多方多端即时通讯方案................................................................. 1 目   录 ...

  5. 基于XMPP协议的手机多方多端即时通讯方案

    原文地址为: 基于XMPP协议的手机多方多端即时通讯方案 基于XMPP协议的手机多方多端即时通讯方案 目   录 基于XMPP协议的手机多方多端即时通讯方案...................... ...

  6. 新手入门:史上最全Web端即时通讯技术原理详解

    前言 有关IM(InstantMessaging)聊天应用(如:微信,QQ).消息推送技术(如:现今移动端APP标配的消息推送模块)等即时通讯应用场景下,大多数都是桌面应用程序或者native应用较为 ...

  7. 二维码登录原理+Web端即时通讯技术

    前言 上周在写项目过程中遇到需要实现二维码的登录功能,将这个过程细节记录下来 二维码的登录过程,主要难点在于用户扫码了浏览器展示的二维码,但是浏览器本身是无法知道的,需要服务端告知信息. 涉及到 we ...

  8. WEB端即时通讯技术

    一:传统WEB通讯的原理 浏览器本身作为一个瘦客户端,不具备直接通过系统调用来达到和处于异地的另外一个客户端浏览器通信的功能.这和我们桌面应用的工作方式是不同的,通常桌面应用通过socket可以和远程 ...

  9. 新手入门贴:史上最全Web端即时通讯技术原理详解

    前言 有关IM(InstantMessaging)聊天应用(如:微信,QQ).消息推送技术(如:现今移动端APP标配的消息推送模块)等即时通讯应用场景下,大多数都是桌面应用程序或者native应用较为 ...

最新文章

  1. Nginx内存池--pool代码抽取(链表套路)
  2. grep 显示前后几行
  3. C++11遍历map
  4. thinkphp5如何使用ajax(变化的核心,也就是ajax作用的核心是什么)
  5. isinstance和issubclass
  6. [html] html的img标签为什么要添加alt属性呢?
  7. AI算法连载14:统计之模型选择
  8. 不学无数——SpringBoot入门VI
  9. Vue+Vue Router+Webpack打包网站基础页面
  10. 装饰者模式 (decorator pattern)
  11. c语言利用fun求最小值,2015年计算机二级《C语言》精选练习题及答案(1)
  12. DOS命令窗口基本操作
  13. 小学数学四年级上册计算机教案,四年级信息技术人教版上册教案
  14. access/sql server笔记(20160818)
  15. 盘古石考核取证复现检材1(??)
  16. 粉丝福利!Matlab自动配色神器ColorForFans
  17. 微信小程序(uni-app)
  18. 双系统 修改grub启动菜单字体大小
  19. Red5 Client 调用 Red5 Server
  20. hibernate进行sum查询

热门文章

  1. [附源码]计算机毕业设计JAVA干果在线销售系统设计
  2. tensosflow.keras.Sequential 的 evaluate() 函数总结
  3. VXLAN中EVPN技术详解(二)——EVPN与VXLAN分布式网关
  4. Linux系统及应用(实验报告)---文件管理与常用命令
  5. APP与后台通信数据格式的演进:从文本协议到二进制协议
  6. 水果店圈子:在小区开水果店怎样运营,水果店没有生意怎么改善
  7. 【Java基础教程】详解Java三种流程控制语句
  8. IP地址最简单的解释
  9. 程序员成长的烦恼(奋斗的小鸟)_PDF 电子书
  10. 【UE4】从零开始制作战斗机(中:飞机操控逻辑)