技术心得记录:基于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

相关文章
|
4月前
|
前端开发 JavaScript 网络协议
深入理解Python Web开发中的前后端分离与WebSocket实时通信技术
【7月更文挑战第18天】前后端分离采用Flask/Django框架,前端JavaScript框架如Vue.js与后端通过AJAX/Fetch通信。WebSocket提供实时双向通信,Python可借助websockets库或Flask-SocketIO实现。最佳实践包括定义清晰的接口规范,确保安全性(HTTPS,认证授权),优化性能,和健壮的错误处理。结合两者,打造高效实时应用。
90 1
|
21天前
|
Web App开发 消息中间件 监控
使用 Java + WebSocket 实现简单实时双人协同 pk 答题:技术干货分享
【10月更文挑战第4天】在现代互联网应用中,实时互动已经成为提升用户体验的重要一环。特别是在在线教育、游戏竞技等领域,实时协同功能显得尤为重要。今天,我们将围绕“使用 Java + WebSocket 实现简单实时双人协同 pk 答题”这一主题,分享相关技术干货,帮助你在工作和学习中更好地理解和应用这一技术。
46 2
|
24天前
|
负载均衡 网络协议 C#
C#实现WebSocket实时消息推送技术详解
C#实现WebSocket实时消息推送技术详解
26 1
|
2月前
|
前端开发 JavaScript 安全
深入理解Python Web开发中的前后端分离与WebSocket实时通信技术
在现代Web开发中,前后端分离已成为主流架构,通过解耦前端(用户界面)与后端(服务逻辑),提升了开发效率和团队协作。前端使用Vue.js、React等框架与后端通过HTTP/HTTPS通信,而WebSocket则实现了低延迟的全双工实时通信。本文结合Python框架如Flask和Django,探讨了前后端分离与WebSocket的最佳实践,包括明确接口规范、安全性考虑、性能优化及错误处理等方面,助力构建高效、实时且安全的Web应用。
49 2
|
2月前
|
前端开发 API Python
WebSocket技术详解:如何在Python Web应用中实现无缝实时通信
在Web开发的广阔领域中,实时通信已成为许多应用的核心需求。传统的HTTP请求-响应模型在实时性方面存在明显不足,而WebSocket作为一种在单个长连接上进行全双工通信的协议,为Web应用的实时通信提供了强有力的支持。本文将深入探讨WebSocket技术,并通过一个Python Web应用的案例分析,展示如何在Python中利用WebSocket实现无缝实时通信。
49 2
|
2月前
|
监控 网络协议 API
.NET WebSocket 技术深入解析,你学会了吗?
【9月更文挑战第4天】WebSocket 作为一种全双工协议,凭借低延迟和高性能特点,成为实时应用的首选技术。.NET 框架提供了强大的 WebSocket 支持,使实时通信变得简单。本文介绍 WebSocket 的基本概念、.NET 中的使用方法及编程模型,并探讨其在实时聊天、监控、在线游戏和协同编辑等场景的应用,同时分享最佳实践,帮助开发者构建高效实时应用。
126 12
|
2月前
|
JavaScript 前端开发 Java
【颠覆传统】Spring框架如何用WebSocket技术重塑实时通信格局?揭秘背后的故事与技术细节!
【9月更文挑战第4天】随着Web应用对实时交互需求的增长,传统的HTTP模型已无法满足现代应用的要求,特别是在需要持续、双向通信的场景下。WebSocket协议由此诞生,提供全双工通信渠道,使服务器与客户端能实时互发消息。作为Java开发中最受欢迎的框架之一,Spring通过其WebSocket模块支持这一协议,简化了WebSocket在Spring应用中的集成。
51 0
|
4月前
|
移动开发 前端开发 网络协议
Python Web实时通信新纪元:基于WebSocket的前后端分离技术探索
【7月更文挑战第16天】WebSocket增强Web实时性,Python借助Flask-SocketIO简化实现。安装`flask`和`flask-socketio`,示例展示服务器端接收连接及消息并广播响应,前端HTML用Socket.IO库连接并监听事件。WebSocket开启双向通信新时代,助力动态Web应用开发。
50 1
|
4月前
|
存储 前端开发 Go
golang怎么搭建Websocket聊天室服务端
连接的添加和移除 添加连接: 当一个新的WebSocket连接建立时,服务器需要将这个连接添加到全局的连接列表中。多个连接可能同时建立,从而导致多个并发操作试图修改连接列表。 移除连接: 当一个WebSocket连接断开时,服务器需要将这个连接从全局的连接列表中移除。如果多个连接同时断开,可能会导致并发修改连接列表。
|
4月前
|
监控 网络协议 Java
Java中的WebSocket实时通信技术详解
Java中的WebSocket实时通信技术详解