一、入门简介

正常聊天程序需要使用消息组件ActiveMQ或者Kafka等,这里是一个Websocket入门程序。

有人有疑问这个技术有什么作用,为什么要有它?
其实我们虽然有http协议,但是它有一个缺陷就是不能主动向客户端发送消息,而我们的基于Tcp协议的Websocket能够做到,所以这在多台机器之间通信提供了大大的方便。

二、入门案例

本案例使用Springboot+WebSocket+Thymeleaf

1.1pom.xml

<!-- websocket --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency><!-- StringUtils --><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId></dependency>

1.2WebSocketConfig

package cn.xdl.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;/*** 开启WebSocket支持* @author liurui**/
@Configuration
public class WebSocketConfig {@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}
}

1.3CheckCenterController连接测试和核心类WebServer

package cn.xdl.controller;import java.io.IOException;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;import cn.xdl.utils.result.AllResult;/*** 调用WebSocketServer* @author liurui**/
@Controller
@RequestMapping("/checkcenter")
public class CheckCenterController {//页面请求@GetMapping("/socket/{cid}")public ModelAndView socket(@PathVariable String cid) {ModelAndView mav=new ModelAndView("/socket");mav.addObject("cid", cid);return mav;}//推送数据接口@ResponseBody@RequestMapping("/socket/push/{cid}")public AllResult pushToWeb(@PathVariable String cid,String message) {  try {WebSocketServer.sendInfo(message,cid);} catch (IOException e) {e.printStackTrace();return AllResult.build(500,cid+"#"+e.getMessage());}  return AllResult.ok(cid);}
}package cn.xdl.controller;import java.io.IOException;
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;import org.springframework.stereotype.Component;import lombok.extern.slf4j.Slf4j;/*** 连接配置* @author liurui**/@ServerEndpoint("/websocket/{sid}")@Component@Slf4jpublic class WebSocketServer {//静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。private static int onlineCount = 0;//concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。private static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<WebSocketServer>();//与某个客户端的连接会话,需要通过它来给客户端发送数据private Session session;//接收sidprivate String sid="";/*** 连接建立成功调用的方法*/@OnOpenpublic void onOpen(Session session,@PathParam("sid") String sid) {this.session = session;webSocketSet.add(this);     //加入set中addOnlineCount();           //在线数加1log.info("有新窗口开始监听:"+sid+",当前在线人数为" + getOnlineCount());this.sid=sid;try {sendMessage("连接成功");} catch (IOException e) {log.error("websocket IO异常");}}/*** 连接关闭调用的方法*/@OnClosepublic void onClose() {webSocketSet.remove(this);  //从set中删除subOnlineCount();           //在线数减1log.info("有一连接关闭!当前在线人数为" + getOnlineCount());}/*** 收到客户端消息后调用的方法** @param message 客户端发送过来的消息*/@OnMessagepublic void onMessage(String message, Session session) {log.info("收到来自窗口"+sid+"的信息:"+message);//群发消息for (WebSocketServer item : webSocketSet) {try {item.sendMessage(message);} catch (IOException e) {e.printStackTrace();}}}/*** * @param session* @param error*/@OnErrorpublic void onError(Session session, Throwable error) {log.error("发生错误");error.printStackTrace();}/*** 实现服务器主动推送*/public void sendMessage(String message) throws IOException {this.session.getBasicRemote().sendText(message);}/*** 群发自定义消息* */public static void sendInfo(String message,@PathParam("sid") String sid) throws IOException {log.info("推送消息到窗口"+sid+",推送内容:"+message);for (WebSocketServer item : webSocketSet) {try {//这里可以设定只推送给这个sid的,为null则全部推送if(sid==null) {item.sendMessage(message);}else if(item.sid.equals(sid)){item.sendMessage(message);}} catch (IOException e) {continue;}}}public static synchronized int getOnlineCount() {return onlineCount;}public static synchronized void addOnlineCount() {WebSocketServer.onlineCount++;}public static synchronized void subOnlineCount() {WebSocketServer.onlineCount--;}}

1.4测试socket.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>websocket</title>
<script type="text/javascript" src="http://nim.prec-robot.com/jzrobot/liurui/js/jquery.js"></script>
</head>
<body><h3>websocket测试页面</h3><input type="hidden" name="cid" th:value="${cid}" id="cid"><input type="button" value="测试" onclick="push()"><script>var cid = $("#cid").val();console.info("cid===="+cid);var socket;  if(typeof(WebSocket) == "undefined") {  console.log("您的浏览器不支持WebSocket");  }else{  console.log("您的浏览器支持WebSocket");  //实现化WebSocket对象,指定要连接的服务器地址与端口  建立连接  //等同于socket = new WebSocket("ws://localhost:8083/checkcentersys/websocket/20");  socket = new WebSocket(("http://localhost:8888/hello-boot/websocket/"+cid).replace("http","ws"));  //打开事件  socket.onopen = function() {  console.log("Socket 已打开");  //socket.send("这是来自客户端的消息" + location.href + new Date());  };  //获得消息事件  socket.onmessage = function(msg) {  console.log(msg.data); //发现消息进入    开始处理前端触发逻辑};  //关闭事件  socket.onclose = function() {  console.log("Socket已关闭");  };  //发生了错误事件  socket.onerror = function() {  alert("Socket发生了错误");  //此时可以尝试刷新页面}  //离开页面时,关闭socket//jquery1.8中已经被废弃,3.0中已经移除// $(window).unload(function(){  //     socket.close();  //});  }function push(){var socket = new WebSocket(("http://localhost:8888/hello-boot/websocket/push/"+cid).replace("http","ws"));}</script>
</body>
</html>

1.5聊天ImController

package cn.xdl.controller;import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;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;import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;import cn.xdl.utils.result.AllResult;
import lombok.extern.slf4j.Slf4j;/*** websocket通信* @author liurui**/
@ServerEndpoint("/im/{userId}")
@Component
@Slf4j
public class ImController {//静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。private static int onlineCount = 0;//旧:concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。//private static CopyOnWriteArraySet<ImController> webSocketSet = new CopyOnWriteArraySet<ImController>();//与某个客户端的连接会话,需要通过它来给客户端发送数据private Session session;//新:使用map对象,便于根据userId来获取对应的WebSocketprivate static ConcurrentHashMap<String,ImController> websocketList = new ConcurrentHashMap<>();//接收sidprivate String userId="";/*** 连接建立成功调用的方法*/@OnOpenpublic void onOpen(Session session,@PathParam("userId") String userId) {this.session = session;websocketList.put(userId,this);log.info("websocketList->"+JSON.toJSONString(websocketList));//webSocketSet.add(this);     //加入set中addOnlineCount();           //在线数加1log.info("有新窗口开始监听:"+userId+",当前在线人数为" + getOnlineCount());this.userId=userId;try {sendMessage(JSON.toJSONString(AllResult.ok("连接成功")));} catch (IOException e) {log.error("websocket IO异常");}}/*** 连接关闭调用的方法*/@OnClosepublic void onClose() {if(websocketList.get(this.userId)!=null){websocketList.remove(this.userId);//webSocketSet.remove(this);  //从set中删除subOnlineCount();           //在线数减1log.info("有一连接关闭!当前在线人数为" + getOnlineCount());}}/*** 收到客户端消息后调用的方法** @param message 客户端发送过来的消息*/@OnMessagepublic void onMessage(String message, Session session) {log.info("收到来自窗口"+userId+"的信息:"+message);if(StringUtils.isNotBlank(message)){JSONArray list=JSONArray.parseArray(message);for (int i = 0; i < list.size(); i++) {try {//解析发送的报文JSONObject object = list.getJSONObject(i);String toUserId=object.getString("toUserId");String contentText=object.getString("contentText");object.put("fromUserId",this.userId);//传送给对应用户的websocketif(StringUtils.isNotBlank(toUserId)&&StringUtils.isNotBlank(contentText)){ImController socketx=websocketList.get(toUserId);//需要进行转换,userIdif(socketx!=null){log.debug("服务端发送给客户端信息--object:{}",object);socketx.sendMessage(JSON.toJSONString(AllResult.ok(object)));//此处可以放置相关业务代码,例如存储到数据库}}}catch (Exception e){e.printStackTrace();}}}}/**** @param session* @param error*/@OnErrorpublic void onError(Session session, Throwable error) {log.error("发生错误");error.printStackTrace();}/*** 实现服务器主动推送*/public void sendMessage(String message) throws IOException {this.session.getBasicRemote().sendText(message);}/*** 群发自定义消息* *//*public static void sendInfo(String message,@PathParam("userId") String userId) throws IOException {log.info("推送消息到窗口"+userId+",推送内容:"+message);for (ImController item : webSocketSet) {try {//这里可以设定只推送给这个sid的,为null则全部推送if(userId==null) {item.sendMessage(message);}else if(item.userId.equals(userId)){item.sendMessage(message);}} catch (IOException e) {continue;}}}*/public static synchronized int getOnlineCount() {return onlineCount;}public static synchronized void addOnlineCount() {ImController.onlineCount++;}public static synchronized void subOnlineCount() {ImController.onlineCount--;}
}

1.6聊天socket_im.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<style>.chat_div{width:500px;height:500px;border:1px solid red;text-align:center;}.chat_send_div{float:left;width:196px;height:498px;border:1px solid blue;}.chat_receive_div{float:right;width:290px;height:498px;border:1px solid green;}
</style>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
<script>var socket;function openSocket() {if(typeof(WebSocket) == "undefined") {console.log("您的浏览器不支持WebSocket");}else{console.log("您的浏览器支持WebSocket");//实现化WebSocket对象,指定要连接的服务器地址与端口  建立连接//等同于socket = new WebSocket("ws://localhost:8888/xxxx/im/25");//var socketUrl="${request.contextPath}/im/"+$("#userId").val();var socketUrl="http://localhost:8888/hello-boot/im/"+$("#userId").val();socketUrl=socketUrl.replace("https","ws").replace("http","ws");console.log(socketUrl)socket = new WebSocket(socketUrl);//打开事件socket.onopen = function() {console.log("websocket已打开");//socket.send("这是来自客户端的消息" + location.href + new Date());};//获得消息事件socket.onmessage = function(msg) {console.log(msg);//发现消息进入    开始处理前端触发逻辑contentText//$.parseJSON(msg);var data = msg.data;var result = $.parseJSON(data);var str = '';if(result.data=="连接成功"){console.info("test----if----"+data);str +='<h3 style="color:blue;">';str +='server:'+result.data;str +='</h3>';$(".chat_receive_div").append(str);}else{console.info("test---else-----"+result.data.contentText);str +='<h3 style="color:blue;">';str +='server:'+result.data.contentText;str +='</h3>';$(".chat_receive_div").append(str);}};//关闭事件socket.onclose = function() {console.log("websocket已关闭");};//发生了错误事件socket.onerror = function() {console.log("websocket发生了错误");}}}function sendMessage() {if(typeof(WebSocket) == "undefined") {console.log("您的浏览器不支持WebSocket");}else {var str = '';console.log("您的浏览器支持WebSocket");console.log('[{"toUserId":"'+$("#toUserId").val()+'","contentText":"'+$("#contentText").val()+'"}]');socket.send('[{"toUserId":"'+$("#toUserId").val()+'","contentText":"'+$("#contentText").val()+'"}]');str +='<h3 style="color:gold;">';str +=$("#toUserId").val()+':'+$("#contentText").val();str +='</h3>';$(".chat_send_div").append(str);}}
</script>
<body><p>【userId】:<div><input id="userId" name="userId" type="text" value="25"></div><p>【toUserId】:<div><input id="toUserId" name="toUserId" type="text" value="26"></div><p>【toUserId】:<div><input id="contentText" name="contentText" type="text" value="嗷嗷嗷"></div><p>【操作】:<div><a onclick="openSocket()">开启socket</a></div><p>【操作】:<div><a onclick="sendMessage()">发送消息</a></div><div class="chat_div"><div class="chat_send_div"><h3>发送消息</h3></div><div class="chat_receive_div"><h3>接受消息</h3></div></div>
</body>
</html>

本程序实现SpringBoot基于websocket的网页聊天。
需要源码没积分可以留言。
有积分可以:https://download.csdn.net/download/liurui50/11214229

SpringBoot基于websocket的网页聊天相关推荐

  1. 基于WebSocket实现网页聊天室

    背景 在浏览器中通过http仅能实现单向的通信,comet可以一定程度上模拟双向通信,但效率较低,并需要服务器有较好的支持; flash中的socket和xmlsocket可以实现真正的双向通信,通过 ...

  2. 使用WebSocket实现网页聊天室

    使用WebSocket实现网页聊天室 一.文章导读 服务器推送你还在使用轮询吗?本文将带你领略WebSocket的魅力,轻松实现服务器推送功能.本文将以下面两方面让你理解WebSocket并应用到具体 ...

  3. 如何使用WebSocket实现网页聊天室?

    一.文章导读 服务器推送你还在使用轮询吗?本文将带你领略WebSocket的魅力,轻松实现服务器推送功能.本文将以下面两方面让你理解WebSocket并应用到具体的开发中 WebSocket概述 使用 ...

  4. 基于websocket的网页实时消息推送与在线聊天(上篇)

    文章目录 @[toc] 基于websocket的网页实时消息推送与在线聊天(上篇) "使用dwebsocket在django中实现websocket" websocket原理图 d ...

  5. workerman-chat(PHP开发的基于Websocket协议的聊天室框架)(thinkphp也是支持socket聊天的)...

    workerman-chat(PHP开发的基于Websocket协议的聊天室框架)(thinkphp也是支持socket聊天的) 一.总结 1.下面链接里面还有一个来聊的php聊天室源码可以学习 2. ...

  6. 基于flask的网页聊天室(四)

    基于flask的网页聊天室(四) 前言 接前天的内容,今天完成了消息的处理 具体内容 上次使用了flask_login做用户登录,但是直接访问login_requare装饰的函数会报401错误,这里可 ...

  7. SpringBoot与webSocket实现在线聊天室——实现私聊+群聊+聊天记录保存

    SpringBoot与webSocket实现在线聊天室--实现私聊+群聊+聊天记录保存 引用参考:原文章地址:https://blog.csdn.net/qq_41463655/article/det ...

  8. 基于flask的网页聊天室(一)

    基于flask的网页聊天室(一) 基于flask的网页聊天室(一) 基本目标 基于flask实现的web聊天室,具有基本的登录注册,多人发送消息,接受消息 扩展目标 除基本目标外添加当前在线人数,消息 ...

  9. php即时聊天的框架_workerman-chat(PHP开发的基于Websocket协议的聊天室框架)(thinkphp也是支持socket聊天的)...

    workerman-chat(PHP开发的基于Websocket协议的聊天室框架)(thinkphp也是支持socket聊天的) 一.总结 1.下面链接里面还有一个来聊的php聊天室源码可以学习 2. ...

最新文章

  1. 字符串转 Json 数组
  2. Java 8 一行代码解决了空指针问题,太厉害了!
  3. Django项目之小博客
  4. WinForm编程细节
  5. 工具使用——印象(汇总)
  6. 所有的物理引擎演示程序
  7. hdu 2986 Ballot evaluation (Simulation)
  8. 学习笔记:DHCP服务器的配置
  9. 关于多维数组编码与解码的问题
  10. Zen Cart对空间或主机的要求
  11. MySql的完整卸载(总共四个步骤)
  12. 阿里云服务器的80端口被封了么?
  13. 【网络安全】GitHub项目监控,teemo子域名查询
  14. 10月24日,咱们自己的节日来了!
  15. html5画智利国旗,智利国旗与得州州旗,你能分的清么?
  16. 解决华为安全键盘收回, 软键盘位置没收回的问题
  17. QuickCam Gev 2.0 开发
  18. C语言数据结构-实验一 C语言回顾及算法分析
  19. 使用CSS3动画做出光芒万丈的效果
  20. 2022-2028全球与中国体育在线直播视频流市场现状及未来发展趋势

热门文章

  1. TSP问题——启发式算法求解
  2. c语言记录键盘敲击次数,【转】你知道一天敲键盘的敲击次数能达到多少么
  3. Chatbot 架构
  4. 源码多多-Discuz x2.5 论坛防灌水机制分析和设置方法
  5. C#的循环控制语句(break,continue)语句
  6. 汇总-13台虚拟机搭建一个高可用负载均衡集群架构
  7. 握手,交流从掌心开始
  8. 我的helloworld
  9. 解决3D云渲染不支持FloorGenerator+MultiTexture插件
  10. 计算机科学最权威的期刊和会议[转]