技术心得记录:基于webSocket的聊天室

简介: 技术心得记录:基于webSocket的聊天室

前言


不知大家在平时的需求中有没有遇到需要实时处理信息的情况,如站内信,订阅,聊天之类的。在这之前我们通常想到的方法一般都是采用轮训的方式每隔一定的时间向服务器发送请求从而获得最新的数据,但这样会浪费掉很多的资源并且也不是实时的,于是随着HTML5的推出带来了websocket可以根本的解决以上问题实现真正的实时传输。


websocket是什么?


至于websocket是什么、有什么用这样的问题一Google一大把,这里我就简要的说些websocket再本次实例中的作用吧。


由于在本次实例中需要实现的是一个聊天室,一个实时的聊天室。如下图:


采用websocket之后可以让前端和和后端像C/S模式一样实时通信,不再需要每次单独发送请求。由于是基于H5的所以对于老的浏览器如IE7、IE8之类的就没办法了,不过H5是大势所趋这点不用担心。


后端


既然推出了websocket,作为现在主流的Java肯定也有相应的支持,所以在JavaEE7之后也对websocket做出了规范,所以本次的代码理论上是要运行在Java1.7+和Tomcat7.0+之上的。


看过我前面几篇文章的朋友应该都知道本次实例也是运行在之前的SSM之上的,所以这里就不再赘述了。


首先第一步需要加入websocket的依赖:


1 package com.css.tax.mobilebs.util;


2


3 import java.io.IOException;


4 import java.io.UnsupportedEncodingException;


5 import java.util.Date;


6 import java.util.HashMap;


7 import java.util.Iterator;


8 import java.util.Map;


9 import java.util.concurrent.CopyOnWriteArraySet;


10


11 import javax.websocket.OnClose;


12 import javax.websocket.OnError;


13 import javax.websocket.OnMessage;


14 import javax.websocket.OnOpen;


15 import javax.websocket.Session;


16 import javax.websocket.server.PathParam;


17 import javax.websocket.server.ServerEndpoint;


18


19 import org.g4studio.common.dao.Reader;


20 import org.g4studio.common.service.impl.BaseServiceImpl;


21 import org.g4studio.common.util.SpringBeanLoader;


22 import org.g4studio.common.web.BaseAction;


23 import org.g4studio.core.metatype.Dto;


24 import org.g4studio.core.metatype.impl.BaseDto;


25 import org.junit.Test;


26


27 import com.css.tax.mobilebs.Vo.CurrentUserVo;

//代码效果参考: http://www.jhylw.com.cn/130439823.html


28 import com.css.tax.mobilebs.serviceI.WebSocketService;


29 import com.css.tax.mobilebs.serviceI.ZjzzService;


30


31 /


32 @ServerEndpoint 注解是一个类层次的注解,它的功能主要是将目前的类定义成一个websocket服务器端,


33 注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端


34 */


35 @ServerEndpoint("/websocket/{user}/{id}/{ptbz}")


36 public class WebSocket extends BaseAction{


37 // 静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。


38 private static int onlineCount = 0;


39 // concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。若要实现服务端与单一客户端通信的话,可以使用Map来存放,其中Key可以为用户标识


40 private static CopyOnWriteArraySet

= new CopyOnWriteArraySet

41 private static CopyOnWriteArraySet

42 private WebSocketService zjzzWebSocketService = (WebSocketService)super.getService("zjzzWebSocketService");


43 // 与某个客户端的连接会话,需要通过它来给客户端发送数据


44 private Session session;


45 private Map webSocketMap = new HashMap();


46 private CurrentUserVo currentUserVo = new CurrentUserVo();


47


48 /


49 连接建立成功调用的方法


50


51 @param session


52 可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据


53 /


54 @OnOpen


55 public void onOpen(@PathParam("user") String user,


56 @PathParam("id") String id, @PathParam("ptbz") String ptbz,


57 Session session) {


58 String charset = getEncoding(user);


59 try {


60 byte【】 b = user.getBytes(charset);


61 user = new String(b, "utf-8");


62 } catch (UnsupportedEncodingException e) {


63 e.printStackTrace();


64 }


65 this.session = session;


66 currentUserVo.setFbrmc(user);


67 currentUserVo.setFbr(id);


68 currentUserVo.setPtbz(ptbz);


69 currentUserVo.setTwr_dm(id);


70 currentUserVo.setPtbz(ptbz);


71 webSocketMap.put(id, this);


72 if("pt".equals(ptbz)) {


73 currentUserVo.setZjmc(user);


74 currentUserVo.setZjry_dm(id);


75 currentUserVo.setKhdfwr(id);


76 webSocketSetPt.add(webSocketMap);


77 }else{


78 currentUserVo.setNsrmc(user);


79 webSocketSet.add(webSocketMap); // 加入set中


80 }


81 addOnlineCount(); // 在线数加


82 System.out.println("有新连接加入!当前在线人数为" + getOnlineCount());


83 }


84


85 /**


86 连接关闭调用的方法


87 /


88 @OnClose


89 public void onClose() {


90 if("pt".equals(this.currentUserVo.getPtbz())) {


91 webSocketSetPt.remove(this.webSocketMap);


92 }else{


93 webSocketSet.remove(this.webSocketMap); // 从set中删除


94 }


95 subOnlineCount(); // 在线数减


96 System.out.println("有一连接关闭!当前在线人数为" + getOnlineCount());


97 }


98


99 /**


100 收到客户端消息后调用的方法


101


102 @param message


103 客户端发送过来的消息


104 @param session


105 可选的参数


106 /


107 @OnMessage


108 public void onMessage(String message,Session session) {


109 boolean boo = false;


110


111 System.out.println("来自" + currentUserVo.getFbrmc() + "的消息:" + message+",发向"+currentUserVo.getJsr_dm());


112 //判断是否为未读消息


113 int a = message.indexOf("&&&");


114 System.out.println(a);


115 if(a!=-1) {//为未读消息


116 String【】 msgStr = message.split("&&&");


117 String userMes = msgStr【0】;


118 String【】 user = userMes.split("@");


119 String uuid = "";


120 String wdjsr = "";


121 String fbrmc = "";


122 String fbr = "";


123 String zjzzuuid = "";


124 if(user.length>0) {


125 wdjsr = user【0】;


126 uuid = user【1】;


127 fbrmc = user【2】;


128 fbr = user【3】;


129 zjzzuuid = user【4】;


130 }


131 message = msgStr【1】;


132 CopyOnWriteArraySet

133 if("pt".equals(this.currentUserVo.getPtbz())) {


134 websocketSet = webSocketSetPt;


135 }else{


136 websocketSet = webSocketSet;


137 }


138 if(!"everybody".equals(wdjsr)) {


139 //消息有指定平台用户


140 for (Map itemMap : websocketSet) {


141 WebSocket socket = itemMap.get(wdjsr);


142 if(socket!=null) {


143 try {


144 if("pt".equals(this.currentUserVo.getPtbz())) {


145 socket.sendMessage(fbr+"@@"+fbrmc + "@^&" + message);


146 socket.currentUserVo.setKhdfwr(this.currentUserVo.getFbr());


147 }else{


148 socket.sendMessage(fbrmc + "@^&" + message);


149 socket.currentUserVo.setKhdfwr(fbr);


150 }


151 socket.currentUserVo.setJsr_dm(fbr);//设置该对话的接收人代码


152 socket.currentUserVo.setJsr(fbrmc);


153 socket.currentUserVo.setZjzzuuid(zjzzuuid);


154 boo = true;


155 Dto reDto = new BaseDto();


156 reDto.put("uuid", uuid);


157 reDto.put("ckbz", "Y");


158 reDto.put("xgr_dm", "111");


159 reDto.put("xgsj", SystemUtils.dateFormat(new Date()));


160 zjzzWebSocketService.updateLtxxDatas(reDto);


161 } catch (IOException e) {


162 e.printStackTrace();


163 }


164 }


165 }


166 }else{


167 //未读消息没有指定平台用户


168 if("pt".equals(this.currentUserVo.getPtbz())) {


169 Object【】 objArr = webSocketSetPt.toArray();


170 int index = (int) (Math.random() * objArr.length);


171 Map map = (Map) objArr【index】;


172 for (WebSocket socket : map.values()) {


173 if(socket!=null) {


174 try {


175 boo = true;


176 socket.sendMessage(fbr+"@@"+fbrmc + "@^&" + message);


177 socket.currentUserVo.setZjzzuuid(zjzzuuid);


178 socket.currentUserVo.setJsr_dm(fbr);


179 socket.currentUserVo.setJsr(fbrmc);


180 socket.currentUserVo.setKhdfwr(socket.currentUserVo.getFbr());


181 //修改未读对话记录


182 Dto reDto = new BaseDto();


183 reDto.put("uuid", uuid);


184 reDto.put("jsr", this.currentUserVo.getFbr());


185 reDto.put("ckbz", "Y");


186 reDto.put("khdfwr", this.currentUserVo.getKhdfwr());


187 reDto.put("xgr_dm", "111");


188 reDto.put("xgsj", SystemUtils.dateFormat(new Date()));


189 zjzzWebSocketService.updateWdWzdDatas(reDto);


190 } catch (IOException e) {


191 e.printStackTrace();


192 continue;


193 }


194 }


195 }


196 }


197 }


198 }else{


199 String【】 xxArr = message.split("@@");


200 String bz = "";


201 String zjzzuuid = "";


202 String fsmessage = "";


203 String jsr = "";


204 if(!"pt".equals(t

相关文章
|
2月前
|
前端开发 JavaScript 网络协议
深入理解Python Web开发中的前后端分离与WebSocket实时通信技术
【7月更文挑战第18天】前后端分离采用Flask/Django框架,前端JavaScript框架如Vue.js与后端通过AJAX/Fetch通信。WebSocket提供实时双向通信,Python可借助websockets库或Flask-SocketIO实现。最佳实践包括定义清晰的接口规范,确保安全性(HTTPS,认证授权),优化性能,和健壮的错误处理。结合两者,打造高效实时应用。
69 1
|
3月前
|
NoSQL Redis Python
技术经验分享:Django实现websocket
技术经验分享:Django实现websocket
24 0
|
3月前
|
JavaScript 网络协议 前端开发
【Nodejs】WebSocket 全面解析+实战演练——(Nodejs实现简易聊天室)
【Nodejs】WebSocket 全面解析+实战演练——(Nodejs实现简易聊天室)
327 0
|
15天前
|
监控 网络协议 API
.NET WebSocket 技术深入解析,你学会了吗?
【9月更文挑战第4天】WebSocket 作为一种全双工协议,凭借低延迟和高性能特点,成为实时应用的首选技术。.NET 框架提供了强大的 WebSocket 支持,使实时通信变得简单。本文介绍 WebSocket 的基本概念、.NET 中的使用方法及编程模型,并探讨其在实时聊天、监控、在线游戏和协同编辑等场景的应用,同时分享最佳实践,帮助开发者构建高效实时应用。
58 12
|
18天前
|
JavaScript 前端开发 Java
【颠覆传统】Spring框架如何用WebSocket技术重塑实时通信格局?揭秘背后的故事与技术细节!
【9月更文挑战第4天】随着Web应用对实时交互需求的增长,传统的HTTP模型已无法满足现代应用的要求,特别是在需要持续、双向通信的场景下。WebSocket协议由此诞生,提供全双工通信渠道,使服务器与客户端能实时互发消息。作为Java开发中最受欢迎的框架之一,Spring通过其WebSocket模块支持这一协议,简化了WebSocket在Spring应用中的集成。
35 0
|
2月前
|
移动开发 前端开发 网络协议
Python Web实时通信新纪元:基于WebSocket的前后端分离技术探索
【7月更文挑战第16天】WebSocket增强Web实时性,Python借助Flask-SocketIO简化实现。安装`flask`和`flask-socketio`,示例展示服务器端接收连接及消息并广播响应,前端HTML用Socket.IO库连接并监听事件。WebSocket开启双向通信新时代,助力动态Web应用开发。
43 1
|
2月前
|
存储 前端开发 Go
golang怎么搭建Websocket聊天室服务端
连接的添加和移除 添加连接: 当一个新的WebSocket连接建立时,服务器需要将这个连接添加到全局的连接列表中。多个连接可能同时建立,从而导致多个并发操作试图修改连接列表。 移除连接: 当一个WebSocket连接断开时,服务器需要将这个连接从全局的连接列表中移除。如果多个连接同时断开,可能会导致并发修改连接列表。
|
2月前
|
监控 网络协议 Java
Java中的WebSocket实时通信技术详解
Java中的WebSocket实时通信技术详解
|
3月前
|
监控 网络协议 JavaScript
WebSocket技术详解与应用指南
WebSocket是全双工TCP协议,解决HTTP的单向通信问题,允许服务器主动推送信息。本文档介绍了WebSocket的基本概念、工作原理(基于HTTP握手,通过帧进行数据通信)、应用场景(实时聊天、在线游戏、数据监控等)和实现方法(客户端使用JavaScript API,服务器端有多种编程语言库支持)。学习WebSocket能提升Web应用的实时性和交互性。
411 1
|
4月前
|
存储 JavaScript Java
基于 WebSocket 打造聊天室
基于 WebSocket 打造聊天室