SpringBoot应用WebSocket实现在线聊天
目录
一、简介
二、java服务端
1、引入包
2、配置
3、代码实现
三、H5客户端
1、代码实现
一、简介
WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket通信协议于2011年被IETF定为标准RFC 6455,并由RFC7936补充规范。WebSocket API也被W3C定为标准。
WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
现在,很多网站为了实现推送技术,所用的技术都是轮询。轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发出HTTP请求,然后由服务器返回最新的数据给客户端的浏览器。这种传统的模式带来很明显的缺点,即浏览器需要不断的向服务器发出请求,然而HTTP请求可能包含较长的头部,其中真正有效的数据可能只是很小的一部分,显然这样会浪费很多的带宽等资源。
而比较新的技术去做轮询的效果是Comet。这种技术虽然可以双向通信,但依然需要反复发出请求。而且在Comet中,普遍采用的长链接,也会消耗服务器资源。
在这种情况下,HTML5定义了WebSocket协议,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。
二、java服务端
1.引入包(gradle管理)
compile 'org.springframework.boot:spring-boot-starter-websocket:2.0.4.RELEASE'
2.配置
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;/*** 简介:** @Author: hzj* @Date: 2019/7/8 0008 17:44*/
@Configuration
public class WebSocketConfig {@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}}
3.代码实现
import com.getoncar.common.exception.BaseException;
import com.getoncar.common.exception.CustomException;
import com.getoncar.entity.Agent_Entity;
import com.getoncar.entity.Message_Entity;
import com.getoncar.host.agent.config.websupport.ResponseVo;
import com.getoncar.model.AgentSendDialogueRequest;
import com.getoncar.model.MessageModel;
import com.getoncar.service.MessageAgentService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.EOFException;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;import static com.getoncar.service.MessageAgentService.oneMessageCache;/*** 简介:** @Author: hzj* @Date: 2019/7/9 0009 9:05*/
@Slf4j
@Api(description ="websocket对话中心-hzj")
@RequestMapping(value = "/websocketController")
@ServerEndpoint(value = "/websocket/{userId}")
@Component //此注解千万千万不要忘记,它的主要作用就是将这个监听器纳入到Spring容器中进行管理
@RestController
public class WebSocketController {//静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。public static int onlineCount = 0;//concurrent包的线程安全Set[ConcurrentHashMap],用来存放每个客户端对应的MyWebSocket对象。public static ConcurrentHashMap<String,WebSocketController> webSocketSet = new ConcurrentHashMap<>();//与某个客户端的连接会话,需要通过它来给客户端发送数据public Session session;//接收参数中的用户IDpublic Long userId;//接收用户中的平台类型public Long platformType;public Session getSession() {return session;}public void setSession(Session session) {this.session = session;}private static ExecutorService executorService = Executors.newCachedThreadPool();private static MessageAgentService messageService;@Autowiredpublic void setMessageService(MessageAgentService messageService) {WebSocketController.messageService = messageService;}@ApiOperation(value ="服务器群发消息")@ApiImplicitParams(@ApiImplicitParam(paramType = "query",name = "content",value = "消息内容",dataType = "String"))@GetMapping("/ServerSendInfo")public void ServerSendInfo(String content) throws IOException {sendInfos("这是服务器给你推送的消息:"+content);}/*** 连接建立成功调用的方法* 接收url中的参数*/@OnOpenpublic void onOpen(Session session,@PathParam("userId") Long userId) {log.info("进入websocket连接");if(webSocketSet.containsKey(userId+"")){log.info("重复登陆-"+userId);try {WebSocketController before = webSocketSet.get(userId+"");if(before.getSession().isOpen()){log.info("发送被迫下线通知");before.getSession().getBasicRemote().sendText("你的会话再另一地方登陆,被迫下线");before.getSession().close();//关闭会话}webSocketSet.remove(before);log.info("重复登陆"+userId+"连接"+before.getSession().getId()+"被服务器主动关闭!当前在线人数为" + getOnlineCount());} catch (IOException e) {e.printStackTrace();return;}}int maxSize = 200 * 1024; // 200K// 可以缓冲的传入二进制消息的最大长度session.setMaxBinaryMessageBufferSize(maxSize);// 可以缓冲的传入文本消息的最大长度session.setMaxTextMessageBufferSize(maxSize);this.session = session;this.userId = userId;this.platformType = platformType;webSocketSet.put(userId+"",this); //加入set中addOnlineCount(); //在线数加1log.info("有新连接加入!当前在线人数为" + getOnlineCount() + " userId==== " + userId + " platformType==== " + platformType);
// try {
// sendMessage("连接成功");
// } catch (IOException e) {
// log.error("websocket IO异常");
// }}/*** 连接关闭调用的方法*/@OnClosepublic void onClose(CloseReason reason) {try {webSocketSet.remove(this); //从set中删除webSocketSet.remove(this.userId+""); //从set中删除System.out.println("连接关闭***************"+this.userId);subOnlineCount(); //在线数减1log.info("有一连接"+this.session.getId()+"关闭!当前在线人数为" + getOnlineCount());log.info("连接"+this.session.getId()+"关闭原因:"+reason.getCloseCode()+"-"+reason.toString());}catch (Exception e){log.info("异常情况");e.printStackTrace();}}/*** 收到客户端消息后调用的方法** @param message 客户端发送过来的消息*/@OnMessagepublic void onMessage(String message, Session session) {//{"car_dealer_id": 198,"car_resource_id": 88, "content": "H你好啊","token":"56bd2cbf1e1349f29cdbbbc54ffc1b95"}log.info("来自客户端"+session.getId()+"的消息:" + message);if(message.equals("_0_")){log.info("心跳");System.err.println("心跳");}else {Runnable t = new Runnable() {@Overridepublic void run() {JSONObject json = JSONObject.fromObject(message);AgentSendDialogueRequest asdr = (AgentSendDialogueRequest)JSONObject.toBean(json,AgentSendDialogueRequest.class);Long receiverId = 0L;Agent_Entity agent_entity = messageService.getAgentByAccessToken(asdr.getToken());if(agent_entity != null) {Long agent_id = agent_entity.getId();asdr.setFromAgentId(agent_id);receiverId = (asdr.getCar_dealer_id());//接收者idtry {if (session.isOpen()) { //先确认 session是否已经打开 使用session.isOpen() 为true 则发送消息。sendInfo(receiverId, JSONObject.fromObject(asdr).toString()); //把发送者userId的消息发给-->receiverId接收者id}} catch (EOFException e) {log.info("报错EOFException" + e.getMessage());System.err.println("报错EOFException" + e.getMessage());} catch (IOException e) {log.info("报错IOException" + e.getMessage());e.printStackTrace();}finally {//入库操作}}}};executorService.submit(t);}}/*** @param session* @param error*/@OnErrorpublic void onError(Session session, Throwable error) {log.error("发生错误" + error);error.printStackTrace();}public void sendMessage(String message) throws IOException {synchronized (this.session) {this.session.getBasicRemote().sendText(message);}}/*** 私发** @param message* @throws IOException*/public static void sendInfo(Long userId, String message) throws IOException {for (WebSocketController item : webSocketSet.values()) {try {if (item.userId.equals(userId)) {item.sendMessage(message);}} catch (IOException e) {continue;}}}/*** 群发自定义消息*/public static void sendInfos(String message) throws IOException {log.info(message);for (WebSocketController item : webSocketSet.values()) {try {item.sendMessage(message);} catch (IOException e) {continue;}}}public static synchronized int getOnlineCount() {return onlineCount;}public static synchronized void addOnlineCount() {WebSocketController.onlineCount++;}public static synchronized void subOnlineCount() {WebSocketController.onlineCount--;}}
三、H5客户端
1.代码实现
<!DOCTYPE html>
<html lang="en" >
<head><meta charset="UTF-8"><!--<meta name="viewport" content="width=device-width, initial-scale=1">--><title>PC端聊天窗口</title><script src="jQuery-2.1.4.min.js" type="text/javascript"></script><link href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,600" rel="stylesheet"><link rel="stylesheet" href="webChat/css/reset.min.css"><link rel="stylesheet" href="webChat/css/style.css"></head>
<body>
<!--连接服务器-->
<div style="margin: 10px 10px;"><input type="text" placeholder="请输入账号" id="phone" style="width: 200px;height: 30px;"/><input type="button" id="connect" value="连接服务器" style="width: 200px;height: 30px;background: #FF0B0A"/>
</div>
<div class="wrapper"><div class="container" style="width: 86%;"><div class="left" style="overflow-y: auto;overflow-x: hidden;"><div class="top" style="position: absolute;top: -3%;height: 73px;width: 37%;z-index: 999"><input type="text" placeholder="昵称、车商名、店名、店址查询" id="putSearch" style="width: 206px;padding-left: 6px" /><a href="javascript:;" class="search" onclick="select()"></a></div><ul class="people" id="chatList" style="margin-top: 18%;"></ul></div><div class="right" id="chatLog" style="overflow-y: auto;overflow-x: hidden;"><div class="top"><span>To: <span class="name">Dog Woofson</span></span></div><!--<div class="chat" data-chat="person1" >--><!--<div class="conversation-start">--><!--<span>Today, 6:48 AM</span>--><!--</div>--><!--<div class="bubble you">--><!--Hello,--><!--</div>--><!--<div class="bubble you">--><!--it's me.--><!--</div>--><!--<div class="bubble you">--><!--I was wondering...--><!--</div>--><!--</div>--><!--<div class="chat" data-chat="person2">--><!--<div class="conversation-start">--><!--<span>Today, 5:38 PM</span>--><!--</div>--><!--<div class="bubble you">--><!--Hello, can you hear me?--><!--</div>--><!--<div class="bubble you">--><!--I'm in California dreaming--><!--</div>--><!--<div class="bubble me">--><!--... about who we used to be.--><!--</div>--><!--<div class="bubble me">--><!--Are you serious?--><!--</div>--><!--<div class="bubble you">--><!--When we were younger and free...--><!--</div>--><!--<div class="bubble you">--><!--I've forgotten how it felt before--><!--</div>--><!--</div>--><!--<div class="chat" data-chat="person3">--><!--<div class="conversation-start">--><!--<span>Today, 3:38 AM</span>--><!--</div>--><!--<div class="bubble you">--><!--Hey human!--><!--</div>--><!--<div class="bubble you">--><!--Umm... Someone took a shit in the hallway.--><!--</div>--><!--<div class="bubble me">--><!--... what.--><!--</div>--><!--<div class="bubble me">--><!--Are you serious?--><!--</div>--><!--<div class="bubble you">--><!--I mean...--><!--</div>--><!--<div class="bubble you">--><!--It’s not that bad...--><!--</div>--><!--<div class="bubble you">--><!--But we’re probably gonna need a new carpet.--><!--</div>--><!--</div>--><!--<div class="chat" data-chat="person4">--><!--<div class="conversation-start">--><!--<span>Yesterday, 4:20 PM</span>--><!--</div>--><!--<div class="bubble me">--><!--Hey human!--><!--</div>--><!--<div class="bubble me">--><!--Umm... Someone took a shit in the hallway.--><!--</div>--><!--<div class="bubble you">--><!--... what.--><!--</div>--><!--<div class="bubble you">--><!--Are you serious?--><!--</div>--><!--<div class="bubble me">--><!--I mean...--><!--</div>--><!--<div class="bubble me">--><!--It’s not that bad...--><!--</div>--><!--</div>--><!--<div class="chat" data-chat="person5">--><!--<div class="conversation-start">--><!--<span>Today, 6:28 AM</span>--><!--</div>--><!--<div class="bubble you">--><!--Wasup--><!--</div>--><!--<div class="bubble you">--><!--Wasup--><!--</div>--><!--<div class="bubble you">--><!--Wasup for the third time like is <br />you blind bitch--><!--</div>--><!--</div>--><!--<div class="chat" data-chat="person6">--><!--<div class="conversation-start">--><!--<span>Monday, 1:27 PM</span>--><!--</div>--><!--<div class="bubble you">--><!--So, how's your new phone?--><!--</div>--><!--<div class="bubble you">--><!--You finally have a smartphone :D--><!--</div>--><!--<div class="bubble me">--><!--Drake?--><!--</div>--><!--<div class="bubble me">--><!--Why aren't you answering?--><!--</div>--><!--<div class="bubble you">--><!--howdoyoudoaspace--><!--</div>--><!--</div>--><div class="write"><a href="javascript:;" class="write-link attach"></a><input type="text" id="content" placeholder="请输入发送的消息" /><a href="javascript:;" class="write-link smiley"></a><a href="javascript:;" class="write-link send" id="send"></a></div></div></div>
</div><!--<script src="webChat/js/index.js"></script>--><div style="text-align:center;margin:1px 0; font:normal 14px/24px 'MicroSoft YaHei';color: #dddddd;">
<p>适用浏览器:360、FireFox、Chrome、Opera、傲游、搜狗、世界之窗. 不支持Safari、IE8及以下浏览器。</p>
</div><script>var loginUrl = "//localhost:8080/messageController/getAgentByAccessToken_web";var token = "1";var url = "ws://localhost:8080/websocket/";var selectAllDealerUrl = "//localhost:8080/messageController/selectAllDealer";var chatLogUrl = "//localhost:8080/messageController/InformationListShowTwo";$(document).ready(function() {alert("请先在左上角输入1-180其中一个数字进行连接");});var car_dealer_id_send = "";var oPhone = document.getElementById('phone');var oUl=document.getElementById('content');var oConnect=document.getElementById('connect');var oSend=document.getElementById('send');var oInput=document.getElementById('message');var chatList=document.getElementById('chatList');var chatLog=document.getElementById('chatLog');var ws=null;var agentId = null;var agentType = null;oConnect.onclick=function(){console.log("oPhone="+oPhone.value);if(oPhone.value==""){alert("请先在左上角输入1-180其中一个数字进行连接");return;}//登陆//把聊天列表列表查询出来$.ajax({url:loginUrl, //请求的url地址contentType: "application/json",dataType:"json", //返回格式为jsonasync:true,//请求是否异步,默认为异步,这也是ajax重要特性data:{"token":oPhone.value}, //参数值type:"GET", //请求方式// headers:{"token":token},beforeSend:function(){//请求前的处理chatList.innerHTML += "<h2 class='time' style='font-size: 18px;color:red;'>正在加载聊天列表中...请稍等</h2>";},success:function(data){//请求成功时处理console.log(data.data);if(data.result == "success"){console.log("登陆agent_id="+data.data.agentId+"--nickName="+data.data.nickName+"--name身份="+data.data.contact);agentId = data.data.agentId;//连接webScoket startws=new WebSocket(url+agentId);ws.onopen=function(){oConnect.value = data.data.nickName+"-已连接服务器";token = oPhone.value;console.log(oPhone.value+"连接成功--token="+token+"--连接地址="+(url+agentId));//把聊天列表查询出来selectChatList("");}ws.onmessage=function(result){var jsons = JSON.parse(result.data);console.log("服务器发送的数据="+result.data+"--jsons.content="+jsons.content+"--jsons.fromAgentId="+jsons.fromAgentId);//如果处于当前聊天对象窗口-直接添加新消息到聊天记录if(car_dealer_id_send == jsons.fromAgentId){chatLog.innerHTML += "<div class='bubble you'>"+jsons.content+"</div>";//划到最底部chatLog.scrollTop = chatLog.scrollHeight; //滚动到最下面}else{//如果未处于当前聊天对象窗口-添加红点样式$('#id'+jsons.fromAgentId).addClass("search");document.getElementById('id'+jsons.fromAgentId).class="search";}}ws.onclose=function(){oUl.innerHTML+="<li>客户端已断开连接</li>";};ws.onerror=function(evt){console.log("onerror了,重连地址="+url+agentId);ws=new WebSocket(url+agentId);};//开启心跳 + 断线重联setInt;//连接webSocket end}else{alert("登陆失败,请重新连接");}},complete:function(){//请求完成的处理},error:function(){//请求出错处理}});};function selectChatList(putSearch) {//把聊天列表列表查询出来$.ajax({url:selectAllDealerUrl, //请求的url地址contentType: "application/json",dataType:"json", //返回格式为jsonasync:true,//请求是否异步,默认为异步,这也是ajax重要特性data:{"select":putSearch}, //参数值type:"GET", //请求方式// headers:{"token":token},beforeSend:function(){//请求前的处理chatList.innerHTML="";chatList.innerHTML += "<h2 class='time' style='font-size: 18px;color:red;'>正在加载聊天列表中...请稍等</h2>";},success:function(data){//请求成功时处理chatList.innerHTML="";console.log(data.data);if(data.result == "success"){$.each(data.data,function(i,value){if(value.notify_type=="MESSAGE"){console.log(i+"--"+value.notify_type+"--"+value.car_dealer_id);chatList.innerHTML +=// "<li class='person' data-chat='person"+i+"' onclick='inTwo("+value.car_dealer_id+")'>"+"<li class='person' data-chat='person"+i+"' onclick=\"inTwo(" + value.car_dealer_id + ",'" + value.shop_name + "');\" >"+"<a class='a' id='id"+value.car_dealer_id+"' style='background-color:red;width: 10px;height: 10px;color: #FF0B0A;'></a>"+"<img src='webChat/img/thomas.jpg' alt='' />"+"<span class='name'>"+value.shop_name+"</span>"+"<span class='time'>"+value.sender_type+"</span>"+// "<span class='preview'>"+value.car_dealer_id+"</span>"+"</li>";}})}else{alert("聊天列表加载失败");}},complete:function(){//请求完成的处理},error:function(){//请求出错处理}});}function inTwo(car_dealer_id,shop_name) {car_dealer_id_send = car_dealer_id;console.log("car_dealer_id===="+car_dealer_id+"--shop_name="+shop_name);//去除红点$('#id'+car_dealer_id).removeClass("search");//把聊天记录查询出来$.ajax({url:chatLogUrl, //请求的url地址contentType: "application/json",dataType:"json", //返回格式为jsonasync:true,//请求是否异步,默认为异步,这也是ajax重要特性data:{"notify_type":"MESSAGE","car_dealer_id":car_dealer_id}, //参数值type:"GET", //请求方式headers:{"token":token},beforeSend:function(){//请求前的处理chatLog.innerHTML += "<h1 class='time' style='position:fixed;top:-87px;z-index:999;font-size: 22px;color:red;'>正在加载聊天记录中...请稍等</h1>";},success:function(data){//请求成功时处理chatLog.innerHTML ="";// console.log(data.data.messageModels);if(data.result == "success"){chatLog.innerHTML ="<div class='top' style='position:fixed;top:-47px;z-index:999;width: 62.4%;'><span>正再与: <span class='name' style='color: #FF0B0A;'>"+shop_name+"</span> 聊天</span></div>";$.each(data.data.messageModels,function(i,value){// console.log("消息内容="+value.content);// chatLog.innerHTML += "<div class='bubble you'>"+value.content+"</div>";if(value.sender_type == "DEALER"){chatLog.innerHTML += "<div class='bubble you'>"+value.content+"--"+value.created_at+"</div>";}if(value.sender_type=="AGENT"){chatLog.innerHTML += "<div class='bubble me'>"+value.content+"--"+value.created_at+"</div>";}})chatLog.scrollTop = chatLog.scrollHeight; //滚动到最下面chatLog.innerHTML +="<div class='write' style='position:fixed;bottom:-7%;left: 42%;width: 52%;'>"+"<a href='javascript:;' class='write-link attach'></a>"+"<input type='text' id='content' placeholder='请输入发送的消息' style='background: #eb7350;' />"+// "<a href='javascript:;' class='write-link smiley'></a>"+"<a href='javascript:;' class='write-link send' id='send' onclick='sendOn(car_dealer_id_send)'></a>"+"</div>";}else{alert("聊天记录加载失败");}},complete:function(){//请求完成的处理},error:function(){//请求出错处理}});}function sendOn(car_dealer_id){console.log("sendOn接收者id="+car_dealer_id);var json={"car_dealer_id": car_dealer_id,"car_resource_id": 1,"content": $("#content").val(),"token":token};console.log("点击了发送数据="+$("#content").val()+"---"+oUl.value);if(ws){ws.send(JSON.stringify(json));chatLog.innerHTML += "<div class='bubble me'>"+$("#content").val()+"</div>";chatLog.scrollTop = chatLog.scrollHeight; //滚动到最下面}}//心跳 + 断线重连var times= 1000*50;var setInt=setInterval(function heartbeat(){if(ws.readyState==1){ // 0=正在连接 1=表示连接成功,可以通信了ws.send('_0_');console.log("心跳发送"+ws+"(每"+(times/1000)+"秒一次)");times = 1000*50;}else if(ws.readyState==3){ // 2=连接正在关闭 3=连接已经关闭,或者打开连接失败。times = 2000;console.log("断线重连url="+url+agentId+"(每"+(times/1000)+"秒一次) heartbeat"+ws);ws = new WebSocket(url+agentId);}},times);//搜索function select() {var putSearch = document.getElementById('putSearch');console.log(putSearch.value);selectChatList(putSearch.value);$("#putSearch").val(""); //设置搜索框的值为空}
</script></body>
</html>
HTML、css、js资料下载地址
链接:https://pan.baidu.com/s/1VXYBiz5vKrMmlvWpqYw-4A
提取码:2xtq
开发过程如有疑问可交流讨论 WX:18637815946
SpringBoot应用WebSocket实现在线聊天相关推荐
- SpringBoot与webSocket实现在线聊天室——实现私聊+群聊+聊天记录保存
SpringBoot与webSocket实现在线聊天室--实现私聊+群聊+聊天记录保存 引用参考:原文章地址:https://blog.csdn.net/qq_41463655/article/det ...
- springboot -- 整合websocket 实现在线聊天
项目demo: 链接:https://pan.baidu.com/s/1xZtU-Rqc58m0-v397OW3hQ 提取码:01pt 复制这段内容后打开百度网盘手机App,操作更方便哦 websoc ...
- SpringBoot 使用WebSocket打造在线聊天室(基于注解)
点击上方"好好学java",选择"置顶公众号" 优秀学习资源.干货第一时间送达! 精彩内容 java实战练习项目教程 2018微服务资源springboot.s ...
- SpringBoot集成WebSocket实现在线聊天
文章目录 前言 1.WebSocket引入 2.环境搭配 2.1.工程创建 2.2.依赖导入 2.3.配置类 3.具体实现 3.1.前置知识 3.2.数据封装 3.3.思路分析 3.4.服务构建 3. ...
- Springboot + WebSocket 实现在线聊天
一.后端 1.在Springboot项目的pom.xml中添加依赖 <!--websocket协议--> <dependency><groupId>org.spri ...
- springboot+websocket构建在线聊天室(群聊+单聊)
系列导读: 1.springboot+websocket构建在线聊天室(群聊+单聊) 2.Spring Boot WebSocket:单聊(实现思路) 3.Websocket Stomp+Rabbit ...
- 【SpringBoot框架篇】18.使用Netty加websocket实现在线聊天功能
文章目录 1.简介 2.最终功能实现的效果图 2.1.pc端 2.2.移动端 3.实战应用 3.1.引入依赖 3.2.配置文件 3.3.测试demo 3.3.1.消息内容实体类 3.3.2.处理请求的 ...
- SpringBoot基于websocket的网页聊天
一.入门简介 正常聊天程序需要使用消息组件ActiveMQ或者Kafka等,这里是一个Websocket入门程序. 有人有疑问这个技术有什么作用,为什么要有它? 其实我们虽然有http协议,但是它有一 ...
- WebSocket实现在线聊天
WebSocket实现在线聊天 前两天在公司接到一个需求,使用WebSocket实现微信扫码登陆,当时了解了一下WebSocket,都说WebSocket可以实现在线聊天,所以我自己也写了一个.(发个 ...
最新文章
- ASP.Net4.0中新增23项功能
- linux定时任务配置失效,linux下定时任务和延迟任务
- VTK修炼之道41:频域处理_低通滤波(理想+巴特沃兹)
- python中head_Python pandas.DataFrame.head函数方法的使用
- ActiveMQ的消息存储(八)
- ubuntu 21.04 版本上 安装 sqlcmd
- 阶段1 语言基础+高级_1-3-Java语言高级_07-网络编程_第2节 TCP协议_1_TCP通信的概述(上)...
- 交互设计之层次设计配色篇(表达逻辑——前进色与后退色)
- 小学生python编程教程-画正方形-小学生 Python 入门课
- 不用U盘,给自己的电脑重装一个win10系统
- 苹果MFI认证步骤汇总
- Java 中的Date(获取一天的开始时间和结束时间)
- java生成word,html文件并将内容保存至数据库 (http://blog.163.com/whs3727@126/blog/static/729915772007325112014115/)
- java利用zxing生成二维码
- 【SayGoodBye.java】一封离职告别信
- JavaSE基础知识(附上代码实现)1
- 用matlab编写了一个DSP数据处理小软件
- 大红喜庆版UI猜灯谜又叫猜字谜微信小程序源码下载
- vb中的clng函数
- Matlab播放音频文件(音乐)!
热门文章
- threejs旋转模型动画教程
- 数据库查询+数据库备份+数据库恢复
- 【高德LBS开源组件大赛】地震来了
- macbook 终端命令怎么使用_玩转 Terminal 终端:入门指南及进阶技巧
- python line strip_关于python 的line.strip()方法
- 高度设置php,uedit设置固定高度
- Git——git的简单使用以及连接gitee的远程仓库[经验 y.2]
- apriori java_频繁模式挖掘apriori算法介绍及Java实现
- selenium切换iframe框架案例——翻页爬取网易云音乐歌单作者和名称
- 《开源软件架构》--nginx配置与内部(三)