springboot+websocket客服聊天

news/2025/2/12 20:04:00/

续:spring boot 完整后端接口案例_cc&的博客-CSDN博客

后台代码

1.在pom.xml中添加spring-boot-starter-websocket

      <!--WebSocket--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency>

 2. 添加配置,先在src\main\resources\application.yml中添加:

server:max-http-header-size: 8192

 如果不加的话可能导致无法进行访问。 

3.新建一个配置类,主要一个Bean,用来启动服务是也启动WebSocket服务

 

package com.cc.springServer.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;@Configuration
public class webSocketConfig {//WebSocket@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}}

 注意:这个类必须有@Configuration注解

4.新建一个model来封装进行对话的对象

 

package com.cc.springServer.entity;import javax.websocket.Session;public class SocketUserInfo {//用户sessionIdprivate String sessionId;//用户sessionprivate Session session;//目标用户sessionidprivate String targetSessionId;//用户角色private String userRole;public String getUserRole() {return userRole;}public void setUserRole(String userRole) {this.userRole = userRole;}public String getSessionId() {return sessionId;}public void setSessionId(String sessionId) {this.sessionId = sessionId;}public Session getSession() {return session;}public void setSession(Session session) {this.session = session;}public String getTargetSessionId() {return targetSessionId;}public void setTargetSessionId(String targetSessionId) {this.targetSessionId = targetSessionId;}
}

 5.新建一个Controller类来管理Socket会话,它主要完成如下场景业务:

1.用户连接上线:如果是一个客服上线,就保存一个客服信息,同时去查找有没有再排队中的用户,如果有就给他们俩建立会话关系;如果是一个用户上线,先建立保存用户信息,再去查找有没有空闲客服,如果有就建立会话关系,如果没有就告诉他系统繁忙,让他进入等待状态。
2.用户下线:如果是客户下线,就删除客服信息,为了方便,我直接让用户刷新页面重新匹配客服,其实这样做不是很好;如果是用户下线,就删除用户信息,让空闲下来的客服和排队中的用户建立会话关系。
3.发送消息:如果是用户发的消息,就将消息推送给相应客服;如果是客服发的消息,就推送给相应用户。

package com.cc.springServer.controller;import com.alibaba.fastjson.JSON;
import com.cc.springServer.entity.SocketUserInfo;
import org.springframework.stereotype.Component;import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;//参数role判断用户角色0是客服,1是用户
@ServerEndpoint(value = "/websocket/{role}")
@Component
public class webSocketController {//用本地线程保存sessionprivate static ThreadLocal<Session> sessions = new ThreadLocal<Session>();//保存所有连接上的用户的sessionprivate static Map<String, SocketUserInfo> userSessionMap = new ConcurrentHashMap<>();//保存在线客服的sessionprivate static Map<String, SocketUserInfo> serverSessionMap = new ConcurrentHashMap<>();//连接@OnOpenpublic void onOpen(Session session, @PathParam(value="role") Integer role) {//默认返回错误状态Map<String, String> resultMap = new HashMap<>();resultMap.put("state", "error");//保证各个线程里的变量相对独立于其他线程内的变量sessions.set(session);//客服上线if (role.equals(0)) {//创建一个在线客服信息SocketUserInfo serverInfo = new SocketUserInfo();serverInfo.setSessionId(session.getId());serverInfo.setSession(session);serverInfo.setUserRole("客服");//告诉客服连接成功resultMap.put("state", "success");//去查询是否有排队中的用户//如果存在排队的用户,就将用户和客服绑定if (findLineUser() != null){SocketUserInfo userInfo = userSessionMap.get(findLineUser());//将用户绑定到客服serverInfo.setTargetSessionId(userInfo.getSessionId());//将客服绑定到用户userInfo.setTargetSessionId(serverInfo.getSessionId());userSessionMap.put(userInfo.getSessionId(), userInfo);System.out.println("客户"+ serverInfo.getSessionId() + "正在为用户" + userInfo.getSessionId()+"服务");Map<String, String> result = new HashMap<>();//客服显示用户信息result.put("msg", "正在为用户"+userInfo.getSessionId()+"服务!");sendMsg(serverInfo.getSession(), JSON.toJSONString(result));//告诉用户有客服为他服务result.put("msg", "客服"+serverInfo.getSessionId()+"正在为您服务!");sendMsg(userInfo.getSession(), JSON.toJSONString(result));}//将在线客服信息保存到map中serverSessionMap.put(session.getId(), serverInfo);System.out.println("客服:" + serverInfo.getSessionId() + "连接上服务器,当前在线客服共计:" + serverSessionMap.size());}if (role.equals(1)) {//创建一个在线用户信息SocketUserInfo userInfo = new SocketUserInfo();userInfo.setSessionId(session.getId());userInfo.setSession(session);userInfo.setUserRole("用户");//告诉用户连接成功resultMap.put("state", "success");//去查询是否有在线的客服//有空闲客服就将用户和客服绑定if (findFreeServer() != null){SocketUserInfo serverInfo = serverSessionMap.get(findFreeServer());//将用户绑定到客服serverInfo.setTargetSessionId(userInfo.getSessionId());serverSessionMap.put(serverInfo.getSessionId(), serverInfo);//将客服绑定到用户userInfo.setTargetSessionId(serverInfo.getSessionId());System.out.println("客户"+ serverInfo.getSessionId() + "正在为" + userInfo.getSessionId()+"服务");Map<String, String> result = new HashMap<>();//客服显示用户信息result.put("msg", "正在为用户"+userInfo.getSessionId()+"服务!");sendMsg(serverInfo.getSession(), JSON.toJSONString(result));result.put("msg", "客服"+serverInfo.getSessionId()+"正在为您服务!");sendMsg(userInfo.getSession(), JSON.toJSONString(result));} else {//告诉用户系统繁忙resultMap.put("msg", "系统繁忙!");}//将在线用户信息保存到map中userSessionMap.put(session.getId(), userInfo);System.out.println("用户编号:" + userInfo.getSessionId() + "连接上服务器,当前在线用户共计:" + userSessionMap.size());}//返回连接信息String result = JSON.toJSONString(resultMap);System.out.println(result);sendMsg(session, result);}//关闭连接@OnClosepublic void onClose(Session session) {SocketUserInfo serverInfo = serverSessionMap.get(session.getId());//客服下线if (serverInfo != null) {//将客户从map中移除serverSessionMap.remove(session.getId());//查看是否有服务服务对象if (null != serverInfo.getTargetSessionId()){//给用户说系统错误Map<String, String> result = new HashMap<>();result.put("msg", "系统错误,请刷新重试!");sendMsg(userSessionMap.get(serverInfo.getTargetSessionId()).getSession(), JSON.toJSONString(result));}System.out.println("客服编号:" + serverInfo.getSessionId() + "退出了连接,当前在线客服共计:" + serverSessionMap.size());} else {//用户下线//将用户从map中移除userSessionMap.remove(session.getId());//从客服中解绑for (SocketUserInfo serverSocketInfo: serverSessionMap.values()) {//查找绑定的客服,即客服绑定的用户不为空,并且绑定的用户id和现在下线的用户id一样if (serverSocketInfo.getTargetSessionId() != null && serverSocketInfo.getTargetSessionId().equals(session.getId())){//解绑serverSocketInfo.setTargetSessionId(null);serverSessionMap.put(serverSocketInfo.getSessionId(), serverSocketInfo);System.out.println("用户编号:" + session.getId() + "断开了与客服" + serverSocketInfo.getSessionId() + "的连接");//客服解绑以后,可能还会有在线排队的用户,就让这个客服去String lineUser = findLineUser();if (lineUser != null){//将用户绑定到客服serverSocketInfo.setTargetSessionId(lineUser);serverSessionMap.put(serverSocketInfo.getSessionId(), serverSocketInfo);//将客服绑定到用户userSessionMap.get(lineUser).setTargetSessionId(serverSocketInfo.getSessionId());System.out.println("客户"+ serverSocketInfo.getSessionId() + "正在为" + lineUser+"服务");Map<String, String> result = new HashMap<>();//客服显示用户信息result.put("msg", "正在为用户"+lineUser+"服务!");sendMsg(serverSocketInfo.getSession(), JSON.toJSONString(result));//用户显示客户信息result.put("msg", "客服"+serverSocketInfo.getSessionId()+"正在为您服务!");sendMsg(userSessionMap.get(lineUser).getSession(), JSON.toJSONString(result));}}}System.out.println("用户编号:" + session.getId() + "退出了连接,当前在线用户共计:" + userSessionMap.size());}}//用户和客户端互相传递消息@OnMessagepublic void onMessage(String message, Session session) {//消息Map<String, String> result = new HashMap<>();SocketUserInfo serverInfo = serverSessionMap.get(session.getId());//客服消息if (serverInfo != null) {System.out.println("客服"+ session.getId()+"发送消息:\""+ message +"\"给用户"+serverSessionMap.get(session.getId()).getTargetSessionId());result.put("msg", "客服"+session.getId()+":"+message);//将消息发送给用户//要判断是否绑定到有用户如果有就将消息传递到用户if (null != serverSessionMap.get(session.getId()).getTargetSessionId()){sendMsg(userSessionMap.get(serverSessionMap.get(session.getId()).getTargetSessionId()).getSession(), JSON.toJSONString(result));} else {//如果没有就将消息给自己,嘻嘻嘻sendMsg(session, JSON.toJSONString(result));}} else {//用户消息System.out.println("用户"+ session.getId()+"发送消息:\""+ message +"\"给客户"+userSessionMap.get(session.getId()).getTargetSessionId());result.put("msg", "用户"+session.getId()+":"+message);//将消息发送给客服//判断是否绑定了客服,如果有就发送消息if (null != userSessionMap.get(session.getId()).getTargetSessionId()){sendMsg(serverSessionMap.get(userSessionMap.get(session.getId()).getTargetSessionId()).getSession(), JSON.toJSONString(result));} else{//同上sendMsg(session,JSON.toJSONString(result));}}}//异常@OnErrorpublic void onError(Session session, Throwable throwable) {System.out.println("发生异常!");throwable.printStackTrace();}//统一的发送消息方法private synchronized void sendMsg(Session session, String msg) {try {session.getBasicRemote().sendText(msg);} catch (IOException e) {e.printStackTrace();}}//查询排队用户private synchronized String findLineUser(){//判断是否有用户if (userSessionMap.size() > 0){//遍历所有用户,查找一个排队的用户for (SocketUserInfo UserInfo: userSessionMap.values()) {if (null == UserInfo.getTargetSessionId()){return UserInfo.getSessionId();}}}return null;}//查询在线空闲客服private  synchronized String findFreeServer(){//判断是否有客服if (serverSessionMap.size() > 0){//遍历所有客服,查找一个空闲的客服for (SocketUserInfo serverInfo: serverSessionMap.values()) {if (null == serverInfo.getTargetSessionId()){return serverInfo.getSessionId();}}}return null;}
}

后台代码到这来就完成了。


前端代码

1) 客户端


<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>辕门-在线咨询</title><script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
</head>
<body><p id="message"></p><form id="clientChat"><input type="text" style="display: none;" id="userName"  /><input type="text" style="display: none;" id="targetUserName" /><input type="text" id="sendMsg"></input><button type="button" onclick="send()">发送</button></form>
</body>
<script>
var websocket = null;var userId = null;//判断当前浏览器是否支持WebSocket
if('WebSocket' in window){websocket = new WebSocket("ws://127.0.0.1:9999/websocket/1");
} else {alert("Don't support websocket!")
}//连接发生错误的回调方法
websocket.onerror = function(){alert("Connect error!");
};//连接成功建立的回调方法
websocket.onopen = function(event){setMessageInnerHTML("连接已建立!");
}//接收到消息的回调方法
websocket.onmessage = function(event){var result = event.datavar ob = JSON.parse(result)//判断用户状态if(ob.state != undefined && ob.state != "success"){setMessageInnerHTML("非法连接!");websocket.close();}//判断是否有消息if(ob.msg != undefined){setMessageInnerHTML(ob.msg);}
}//连接关闭的回调方法
websocket.onclose = function(){setMessageInnerHTML("close");
}//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = function(){websocket.close();
}//将消息显示在网页上
function setMessageInnerHTML(innerHTML){document.getElementById('message').innerHTML += innerHTML + '<br/>';
}//关闭连接
function closeWebSocket(){websocket.close();
}//发送消息
function send(){var sendMsg = $("#sendMsg").val();setMessageInnerHTML("我 :" + sendMsg)websocket.send(sendMsg);$("#sendMsg").val("");
}
</script>
</html>

 

2)服务端

<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>辕门-IM</title><script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
</head>
<body><p id="message"></p><form id="clientChat"><input type="text" style="display: none;" id="userName"  /><input type="text" style="display: none;" id="targetUserName" /><input type="text" id="sendMsg"></input><button type="button" onclick="send()">发送</button></form>
</body>
<script>
var websocket = null;var userId = null;//判断当前浏览器是否支持WebSocket
if('WebSocket' in window){websocket = new WebSocket("ws://127.0.0.1:9999/websocket/0");
} else {alert("Don't support websocket!")
}//连接发生错误的回调方法
websocket.onerror = function(){alert("Connect error!");
};//连接成功建立的回调方法
websocket.onopen = function(event){setMessageInnerHTML("连接已建立!");
}//接收到消息的回调方法
websocket.onmessage = function(event){var result = event.datavar ob = JSON.parse(result)//判断用户状态if(ob.state != undefined && ob.state != "success"){setMessageInnerHTML("非法连接!");websocket.close();}//判断是否有消息if(ob.msg != undefined){setMessageInnerHTML(ob.msg);}
}//连接关闭的回调方法
websocket.onclose = function(){setMessageInnerHTML("close");
}//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = function(){websocket.close();
}//将消息显示在网页上
function setMessageInnerHTML(innerHTML){document.getElementById('message').innerHTML += innerHTML + '<br/>';
}//关闭连接
function closeWebSocket(){websocket.close();
}//发送消息
function send(){var sendMsg = $("#sendMsg").val();setMessageInnerHTML("我 :" + sendMsg)websocket.send(sendMsg);$("#sendMsg").val("");
}
</script>
</html>

 

 

 


http://www.ppmy.cn/news/291533.html

相关文章

《红豆——我的母亲》

《红豆》 “这红豆&#xff0c;不是一般的红豆&#xff0c;是王维诗里的红豆&#xff01;” 校园的绿坪上&#xff0c;有一棵长着红果子的树&#xff0c;前两年的光阴里&#xff0c;未曾多加留意&#xff0c;每次都是脚步匆匆&#xff0c;一瞥而过&#xff0c;似乎没有什么可…

Windows操作系统渗透测试

Windows操作系统渗透测试 任务环境说明&#xff1a;服务器场景名&#xff1a;Server02服务器场景操作系统&#xff1a;未知&#xff08;关闭链接&#xff09; 1.通过本地PC中渗透测试平台Kali对服务器场景进行系统服务及版本扫描渗透测试&#xff0c;并将该操作显示结果中808…

win10下RTX3060配置CUDA,并安装带有GPU支持的tensorflow

踩过了好多坑之后我只能说网上的大部分教程都太老了&#xff0c;不适合RTX30系显卡&#xff0c;其实正确的方法比那些老方法简单的多&#xff0c;重要的是你显卡是新的&#xff0c;软件版本也一定要新 一、安装CUDA与CUDNN 1首先确保你已经安装了新版的nvidia图形驱动程序。其…

RTX2060+win10+Tensorflow GPU+CUDA 9.2+CUDNN7.2+python 3.65

RTX2060win10Tensorflow GPUCUDA 9.2CUDNN7.2python 3.65 前言&#xff08;先别安装Tensorflow,以免后面还要换版本&#xff09;开始&#xff01;1、Anaconda3下载与安装2、vs 2015 社区版下载与安装3、CUDA9.2下载与安装4、CUDNN7.2下载与安装 开始最终要的环节&#xff01;&a…

win10+Tensorflow + cuda +RTX 3090/3080 +cudnn 安装

最近RTX3080 / 3090发售&#xff0c;深度学习计算能力提升巨大&#xff0c;本人第一时间入手进行测试&#xff0c;确实氢弹级别&#xff01; 使用中&#xff0c;最新的cuda11&#xff0c;cudnn&#xff0c;显卡驱动&#xff0c;tensorflow版本都需要一一对应&#xff0c;而tens…

Win10 + GTX1650显卡 安装 Cuda-10.1 + CuDNN-7.6 + Tensorflow-gpu-1.15.0 一步到位

之前一直使用tensorflow的cpu版本&#xff0c;即便是简单的模型训练增加迭代次数到50次还是有点慢的&#xff0c;所以用gpu版本加速 废话不多说&#xff0c;流程先列出来&#xff0c;有个大致认识&#xff1a;anaconda----Visual Studio 2019----CudaCuDNN----配置环境变量----…

WIN10 + GTX1660Ti配置TensorFlow GPU版本

安装准备&#xff1a; 操作系统: Windows 10Python版本: 3.7.3安装Anaconda3-2019.03-Windows-x86_64自带python3.7.3下载地址&#xff1a;https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/参考链接&#xff1a;https://blog.csdn.net/junchengberry/article/details/8…

nvidia 3060 + cuda + cudnn + tf

参考&#xff1a; https://eipi10.cn/deep-learning/2019/11/28/centos_cuda_cudnn/ 1.环境版本&#xff1a; CentOS Linux release 7.8.2003 (Core) Tensorflow-gpu 2.5 nvidia 3060 cuda 11.2.2 cudnn-11.3 2.环境检查&#xff1a; lscpi | grep -i nvidia # 要有nvidia 设…