关键词:
前言
在网站项目开发中,我们经常会有在线客服的功能,通过网站开启一个聊天室,进行客服解答功能,本节我们使用websocket实现一个简单的网站在线客服聊天功能,效果如下:
正文
- 后端引入websocket的pom依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
- 后端初始化注入websocket的ServerEndpointExporter端点
package com.yundi.atp.platform.websocket;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
/**
* @Author: yanp
* @Description:
* @Date: 2021/9/15 15:27
* @Version: 1.0.0
*/
@Configuration
public class WebSocketConfig
/**
* 注入ServerEndpointExporter,
* 这个bean会自动注册使用了@ServerEndpoint注解声明的Websocket endpoint
*/
@Bean
public ServerEndpointExporter serverEndpointExporter()
return new ServerEndpointExporter();
- 后端创建一个websocket服务器,用于前后端通信,发送消息
package com.yundi.atp.platform.websocket;
import com.alibaba.fastjson.JSON;
import com.yundi.atp.platform.module.test.entity.ChatMsg;
import com.yundi.atp.platform.module.test.service.ChatMsgService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
/**
* @Author: yanp
* @Description: WebSocket服务端
* @Date: 2021/9/15 15:27
* @Version: 1.0.0
*/
@Slf4j
@Component
@ServerEndpoint("/websocket/chat/userName")
public class WebSocketServer
private Session session;
private static CopyOnWriteArraySet<WebSocketServer> webSockets = new CopyOnWriteArraySet<>();
private static Map<String, Session> sessionPool = new ConcurrentHashMap<>();
private static ChatMsgService chatMsgService;
private static String SUPER_ADMIN = "super_admin";
@Autowired
public void setWebSocketServer(ChatMsgService chatMsgService)
WebSocketServer.chatMsgService = chatMsgService;
@OnOpen
public void onOpen(Session session, @PathParam(value = "userName") String userName)
List<String> onlineList = new ArrayList<>();
this.session = session;
webSockets.add(this);
sessionPool.put(userName, session);
log.info("【websocket消息】有新的连接,总数为:" + webSockets.size());
Iterator<Map.Entry<String, Session>> iterator = sessionPool.entrySet().iterator();
while (iterator.hasNext())
onlineList.add(iterator.next().getKey());
onlineList.remove(SUPER_ADMIN);
Map<String, Object> map = new HashMap<>(16);
map.put("key", 1);
map.put("onlineList", onlineList);
map.put("userList", chatMsgService.getUserList());
this.sendOneMessage(SUPER_ADMIN, JSON.toJSONString(map));
@OnClose
public void onClose(@PathParam(value = "userName") String userName)
webSockets.remove(this);
sessionPool.remove(userName);
log.info("【websocket消息】连接断开,总数为:" + webSockets.size());
List<String> onlineList = new ArrayList<>();
Iterator<Map.Entry<String, Session>> iterator = sessionPool.entrySet().iterator();
while (iterator.hasNext())
onlineList.add(iterator.next().getKey());
onlineList.remove(SUPER_ADMIN);
Map<String, Object> map = new HashMap<>(16);
map.put("key", 2);
map.put("onlineList", onlineList);
map.put("userList", chatMsgService.getUserList());
this.sendOneMessage(SUPER_ADMIN, JSON.toJSONString(map));
@OnMessage
public void onMessage(String message)
ChatMsg chatMsg = JSON.parseObject(message, ChatMsg.class);
chatMsgService.save(chatMsg);
Map<String, Object> map = new HashMap<>(16);
map.put("key", 3);
map.put("data", chatMsg);
this.sendOneMessage(chatMsg.getSender(), JSON.toJSONString(map));
this.sendOneMessage(chatMsg.getReceiver(), JSON.toJSONString(map));
/**
* 广播消息
*/
public void sendAllMessage(String message)
for (WebSocketServer webSocket : webSockets)
log.info("【websocket消息】广播消息:" + message);
try
webSocket.session.getAsyncRemote().sendText(message);
catch (Exception e)
e.printStackTrace();
/**
* 单点消息
*
* @param userName
* @param message
*/
public void sendOneMessage(String userName, String message)
log.info("【websocket消息】单点消息:" + message);
Session session = sessionPool.get(userName);
if (session != null)
try
session.getAsyncRemote().sendText(message);
catch (Exception e)
e.printStackTrace();
- 后端聊天室功能控制层接口
package com.yundi.atp.platform.module.test.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.yundi.atp.platform.common.Result;
import com.yundi.atp.platform.module.test.entity.ChatMsg;
import com.yundi.atp.platform.module.test.service.ChatMsgService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
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.RestController;
import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
/**
* <p>
* 前端控制器
* </p>
*
* @author yanp
* @since 2021-09-17
*/
@Api(tags = "聊天室接口")
@RestController
@RequestMapping("/test/chatMsg")
public class ChatMsgController
@Autowired
private ChatMsgService chatMsgService;
@ApiOperation(value = "获取聊天室地址")
@GetMapping(value = "/getWebSocketAddress/username")
public Result getWebSocketAddress(HttpServletRequest request, @PathVariable(value = "username") String username) throws UnknownHostException
String address = "ws://" + InetAddress.getLocalHost().getHostAddress() + ":" + request.getServerPort() + request.getContextPath() + "/websocket/chat/" + username;
return Result.success(address);
@ApiOperation(value = "获取历史聊天记录")
@GetMapping(value = "/getHistoryChat/username")
public Result getWebSocketAddress(@PathVariable(value = "username") String username)
List<ChatMsg> list = chatMsgService.list(new QueryWrapper<ChatMsg>()
.and(wrapper -> wrapper.eq("sender", username).or().eq("receiver", username))
.orderByDesc("create_time"));
List<ChatMsg> collect = list.stream().sorted(Comparator.comparing(ChatMsg::getCreateTime)).collect(Collectors.toList());
return Result.success(collect);
@ApiOperation(value = "获取用户列表")
@GetMapping(value = "/getUserList")
public Result getUserList()
List<String> userList = chatMsgService.getUserList();
return Result.success(userList);
- 后端聊天室功能业务层
package com.yundi.atp.platform.module.test.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yundi.atp.platform.module.test.entity.ChatMsg;
import com.yundi.atp.platform.module.test.mapper.ChatMsgMapper;
import com.yundi.atp.platform.module.test.service.ChatMsgService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* <p>
* 服务实现类
* </p>
*
* @author yanp
* @since 2021-09-17
*/
@Service
public class ChatMsgServiceImpl extends ServiceImpl<ChatMsgMapper, ChatMsg> implements ChatMsgService
@Autowired
private ChatMsgMapper chatMsgMapper;
@Override
public List<String> getUserList()
List<String> userList = chatMsgMapper.getUserList();
return userList;
- 后端聊天室功能持久层
package com.yundi.atp.platform.module.test.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yundi.atp.platform.module.test.entity.ChatMsg;
import java.util.List;
/**
* <p>
* Mapper 接口
* </p>
*
* @author yanp
* @since 2021-09-17
*/
public interface ChatMsgMapper extends BaseMapper<ChatMsg>
/**
* 用户列表
* @return
*/
List<String> getUserList();
- 后端聊天室功能持久层Mapper
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yundi.atp.platform.module.test.mapper.ChatMsgMapper">
<select id="getUserList" resultType="java.lang.String">
SELECT sender FROM `chat_msg` where sender != 'super_admin' GROUP BY sender
</select>
</mapper>
- 前端聊天室功能页面
<template>
<div class="container">
<el-card class="box-card">
<div slot="header">
<el-row type="flex">
<el-col :span="1" style="margin: 15px 10px;">
<img alt="ATP客服" src="@/assets/logo.png" style="width:40px;height:40px;"/>
</el-col>
<el-col :span="3" style="line-height: 74px;margin-left: 10px;">
<span style="display: inline-block;color: white;">ATP客服</span>
</el-col>
<el-col :span="20" v-if="username==='super_admin'">
<h5 style="color: #83ccd2;padding: 0;text-align: right;margin: 50px 20px 0 0;">当前在线人数: online </h5>
</el-col>
<el-col :span="20" v-else>
<h5 style="color: #83ccd2;padding: 0 0 2px 0;text-align: right;margin: 50px 20px 0 0;font-size: 18px;">
username </h5>
</el-col>
</el-row>
</div>
<div class="content" ref="content">
<el-row type="flex">
<el-col :span="6" style="background: #eee;min-height: 600px;" v-if="username==='super_admin'">
<el-tabs v-model="activeName" @tab-click="handleClick" style="position: fixed;width: 190px;margin: 0 2px;">
<el-tab-pane label="在线用户" name="online">
<div v-for="item in friend" :key="item" @click="switchUser(item)" :class="item===active?'mark':''">
<el-badge :is-dot=msgNotify.includes(item) class="item" type="success">
<li style="list-style-type:none;padding: 5px 8px;cursor: pointer;"
class="active">
item
</li>
</el-badge>
<el-divider></el-divider>
</div>
</el-tab-pane>
<el-tab-pane label="全部用户" name="all">
<div v-for="item in userList" :key="item" @click="switchUser(item)" :class="item===active?'mark':''">
<el-badge :is-dot=msgNotify.includes(item) class="item" type="success">
<li style="list-style-type:none;padding: 5px 8px;cursor: pointer;"
:class="friend.includes(item)?'active':''">
item
</li>
</el-badge>
<el-divider></el-divider>
</div>
</el-tab-pane>
</el-tabs>
</el-col>
<el-col :span="18" v-if="username==='super_admin'">
<div v-for="item in chatMsgList">
<el-row type="flex" style="margin-bottom: 20px;" v-if="username===item.sender">
<el-col :span="2">
<img alt="ATP客服" src="@/assets/logo.png" style="width:30px;height:30px;margin: 10px 0px 0px 20px;"/>
</el-col>
<el-col :span="22">
<el-row type="flex" style="margin-top: 10px;margin-left: 5px;opacity: 0.2;">
<el-col :span="7"><span style="padding-left: 20px;"> item.sender </span></el-col>
<el-col :span="7"><span> item.createTime | dataFormat('yyyy-MM-dd HH:mm') </span></el-col>
</el-row>
<el-row>
<el-col :span="14" style="margin-left: 8px;margin-top: 5px;">
<el-card style="padding: 8px 5px;">
item.msg
</el-card>
</el-col>
</el-row>
</el-col>
</el-row>
<el-row type="flex" style="margin-bottom: 20px;" v-else justify="end">
<el-col :span="22">
<el-row type="flex" style="margin-top: 10px;margin-right: 5px;opacity: 0.2;" justify="end">
<el-col :span="6"><span> item.sender </span></el-col>
<el-col :span="7"><span> item.createTime | dataFormat('yyyy-MM-dd HH:mm') </span></el-col>
</el-row>
<el-row type="flex" justify="end" style="margin-right: 8px;margin-top: 5px;">
<el-col :span="14" style="margin-right: 8px;">
<el-card style="padding: 8px 5px;">
item.msg
</el-card>
</el-col>
</el-row>
</el-col>
<el-col :span="2">
<el-avatar shape="square" size="medium" style="float: right;margin: 10px 20px 0px 0px;">客户</el-avatar>
</el-col>
</el-row>
</div>
</el-col>
<el-col :span="24" v-else>
<div v-for="item in chatMsgList">
<el-row type="flex" style="margin-bottom: 20px;" v-if="username===item.sender">
<el-col :span="2">
<el-avatar shape="square" size="medium" style="float: right;margin: 10px 20px 0px 0px;">客户</el-avatar>
</el-col>
<el-col :span="22">
<el-row type="flex" style="margin-top: 10px;opacity: 0.2;margin-left: 20px;">
<el-col :span="7"><span style="padding-left: 5px;"> item.sender </span></el-col>
<el-col :span="7"><span> item.createTime | dataFormat('yyyy-MM-dd HH:mm') </span></el-col>
</el-row>
<el-row>
<el-col :span="14">
<el-card style="padding: 8px 5px;">
item.msg
</el-card>
</el-col>
</el-row>
</el-col>
</el-row>
<el-row type="flex" style="margin-bottom: 20px;" v-else justify="end">
<el-col :span="22">
<el-row type="flex" style="margin-top: 10px;margin-right: 5px;opacity: 0.2;" justify="end">
<el-col :span="6"><span> item.sender </span></el-col>
<el-col :span="7"><span> item.createTime | dataFormat('yyyy-MM-dd HH:mm') </span></el-col>
</el-row>
<el-row type="flex" justify="end" style="margin-top: 5px;">
<el-col :span="14">
<el-card style="padding: 8px 5px;">
item.msg
</el-card>
</el-col>
</el-row>
</el-col>
<el-col :span="2">
<img alt="ATP客服" src="@/assets/logo.png" style="width:30px;height:30px;margin: 10px 0px 0px 20px;"/>
</el-col>
</el-row>
</div>
</el-col>
</el-row>
</div>
<div class="operate" v-if="username==='super_admin'">
<el-input
type="textarea"
:autosize=" minRows: 3, maxRows: 3"
placeholder="您好!这里是ATP客服部,我是客服小美,很高兴为您服务!"
v-model="msg">
</el-input>
<el-button type="success" size="mini" style="float: right;margin-top: 5px;" @click="sendMsg"
:disabled="!(msg && active)">
发送
</el-button>
</div>
<div class="operate" v-else>
<el-input
type="textarea"
:autosize=" minRows: 3, maxRows: 3"
placeholder="您好!这里是ATP客服部,我是客服小美,很高兴为您服务!"
v-model="msg">
</el-input>
<el-button type="success" size="mini" style="float: right;margin-top: 5px;" @click="sendMsg" :disabled="!msg">
发送
</el-button>
</div>
</el-card>
</div>
</template>
<script>
export default
name: "ClientChat",
data()
return
msg: '',
chatMsgList: [],
username: sessionStorage.getItem("username"),
friend: [],
online: 0,
active: '',
receiver: 'super_admin',
userList: [],
activeName: 'online',
msgNotify:[],
,
created()
this.getWebSocketAddress();
,
methods:
//tab切换
handleClick(tab, event)
const _this = this;
if (tab.name === 'online')
if (!_this.active)
if (_this.online > 0)
_this.active = _this.friend[0];
_this.activeName = 'online';
_this.receiver = _this.active;
_this.getHistoryChat(_this.receiver);
else
if (_this.userList.length > 0)
_this.active = _this.userList[0];
_this.activeName = 'all';
_this.receiver = _this.active;
_this.getHistoryChat(_this.receiver);
if (tab.name === 'all')
if (!_this.active)
if (_this.online > 0)
_this.active = _this.friend[0];
_this.activeName = 'online';
_this.receiver = _this.active;
_this.getHistoryChat(_this.receiver);
else
if (_this.userList.length > 0)
_this.active = _this.userList[0];
_this.activeName = 'all';
_this.receiver = _this.active;
_this.getHistoryChat(_this.receiver);
,
//切换用户
switchUser(data)
if (this.active === data)
return;
this.active = data;
this.receiver = data;
//获取历史聊天记录
this.getHistoryChat(this.receiver);
this.msgNotify = this.msgNotify.filter(item => item != this.active);
,
//获取历史聊天记录
getHistoryChat(data)
this.$http.get('/test/chatMsg/getHistoryChat/' + data).then(res =>
if (res.data.code === 1)
this.chatMsgList = res.data.data;
this.flushScroll();
else
this.$message.warning(res.data.msg);
).catch(error =>
this.$message.error(error);
);
,
//获取websocket地址
getWebSocketAddress()
this.$http.get('/test/chatMsg/getWebSocketAddress/' + this.username).then(res =>
if (res.data.code === 1)
if ('WebSocket' in window)
this.websocket = new WebSocket(res.data.data);
this.initWebSocket();
if (this.username != 'super_admin')
this.getHistoryChat(this.username);
else
this.$message.warning('当前浏览器不支持websocket创建!');
else
this.$message.warning(res.data.msg);
).catch(error =>
this.$message.error(error);
);
,
//初始化websocket
initWebSocket()
const _this = this;
_this.websocket.onerror = function (event)
_this.$message.error('服务端连接错误!');
_this.websocket.onopen = function (event)
_this.$message.success("连接成功!");
_this.websocket.onmessage = function (event)
let res = JSON.parse(event.data);
if (res.key === 1)
_this.userList = res.userList;
_this.friend = res.onlineList;
_this.online = _this.friend.length;
if (!_this.active)
if (_this.online > 0)
_this.active = _this.friend[0];
_this.activeName = 'online';
_this.receiver = _this.active;
_this.getHistoryChat(_this.receiver);
else
if (_this.userList.length > 0)
_this.active = _this.userList[0];
_this.activeName = 'all';
_this.receiver = _this.active;
_this.getHistoryChat(_this.receiver);
if (res.key === 2)
_this.userList = res.userList;
_this.friend = res.onlineList;
_this.online = _this.friend.length;
if (!_this.active)
if (_this.online > 0)
_this.active = _this.friend[0];
_this.activeName = 'online';
_this.receiver = _this.active;
_this.getHistoryChat(_this.receiver);
else
if (_this.userList.length > 0)
_this.active = _this.userList[0];
_this.activeName = 'all';
_this.receiver = _this.active;
_this.getHistoryChat(_this.receiver);
if (res.key === 3)
if (_this.username === res.data.sender)
_this.chatMsgList.push(res.data);
_this.flushScroll();
else
if (res.data.sender === 'super_admin')
_this.chatMsgList.push(res.data);
_this.flushScroll();
else
if (res.data.sender === _this.active)
_this.chatMsgList.push(res.data);
_this.flushScroll();
else
//发送其它用户处理
_this.msgNotify.push(res.data.sender);
_this.websocket.onclose = function (event)
_this.$message.warning('服务端已关闭!');
,
//发送消息
sendMsg()
if (this.msg.trim().length === 0)
this.$message.warning('不能发送空消息!');
return;
let chatMsg = ;
chatMsg.msg = this.msg;
chatMsg.sender = this.username;
chatMsg.createTime = new Date();
chatMsg.receiver = this.receiver;
this.websocket.send(JSON.stringify(chatMsg));
this.msg = '';
this.flushScroll();
,
//刷新滚动条
flushScroll()
let content = this.$refs.content;
setTimeout(() =>
content.scrollTop = content.scrollHeight;
, 100);
,
</script>
<style scoped lang="scss">
.container
padding-top: 50px;
.box-card
margin: auto;
width: 800px;
height: 800px;
max-height: 900px;
::v-deep .el-card__header
background: #867ba9 !important;
border-bottom: none;
padding: 0;
::v-deep .el-card__body
padding: 0px !important;
position: relative;
.content
height: 600px;
background: #ddd;
overflow-y: auto;
.el-divider--horizontal
margin: 0;
.active
color: #0080ff;
.mark
background: #deb068;
.item
margin-top: 10px;
margin-right: 10px;
.operate
padding: 5px 15px;
</style>
- 聊天室页面效果
结语
本节内容到这里就结束了,我们下期见。。。
[websocket]开发在线客服系统知识点-websocket返回状态码的含义
在读取一个websocket资源的时候,有时候会报错,就会返回一个状态码这些状态码的含义是如下面列表:0–999保留段,未使用.1000CLOSE_NORMAL正常关闭;无论为何目的而创建,该链接都已成功完成任务.1001CLOSE_GOING_AWAY终端离开,可能因为... 查看详情
(二十)atp应用测试平台——websocket实现微服务版在线客服聊天室实战案例(代码片段)
前言在前面的博客内容中我们介绍了如何使用websocket实现一个网页版的在线客服聊天室,众所周知,由于websocket是一个长连接,要和服务端保持会话连接,所以其本身并不适用于微服务环境,在微服务环境中... 查看详情
使用websocket实现消息推送
WebSocket上联系客服功能在项目中很难避免,一般有下面三种实现方式: 使用http的get方式轮询接入第三方IM系统自己的IM系统 基于socket基于websocket第一种方式,最low的,实现简单,但是浪费用户流量;第二种方式,接入简... 查看详情
使用websocket实现消息推送
WebSocket上联系客服功能在项目中很难避免,一般有下面三种实现方式:使用http的get方式轮询接入第三方IM系统自己的IM系统基于socket基于websocket第一种方式,最low的,实现简单,但是浪费用户流量;第二种方式,接入简单,功能... 查看详情
java怎么实现在线web客服
...服务器,并且只有在有新消息的时候服务器才返回数据。websocket。这个类似socket,是目前最好的实现方式。不过需要高版本的web服务器来支持。具体可以看我刚才回答另一个网友的问题:http://zhidao.baidu.com/question/646422384746932645.ht... 查看详情
ws模块指南+vue在线聊天室(代码片段)
简介ws模块是Node端的一个WebSocket协议的实现,该协议允许客户端(一般是浏览器)持久化和服务端的连接.这种可以持续连接的特性使得WebScoket特别适合用于适合用于游戏或者聊天室等使用场景.ws模块相较于其他基于WebSocket协议的模... 查看详情
用socket.io实现websocket的一个简单例子
http://biyeah.iteye.com/blog/1295196 socket.io的介绍http://www.cnblogs.com/mazg/p/5467960.html websocket在线测试http://www.blue-zero.com/WebSocket/ 查看详情
手写一个的在线聊天系统(原理篇2)(代码片段)
...我们了解Netty的一些基本原理,并且写了一个简单的WebSocket服务端。接下来我们来详细的了解一下WebSocket相关的知识点。一、前提回顾基于Netty实现在线聊天系统(原理篇一)二、目录介绍什么是WebSocket?WebSocket如何建立连... 查看详情
websocket的简单实现
参考技术AWebSocket协议是基于TCP的一种新的网络协议。浏览器通信通常是基于HTTP协议,为什么还需要另一个协议?因为http只能由客户端发起,不能由服务端发起。而WebSocket浏览器和服务器只需要完成一次握手,两者之间就直接可... 查看详情
使用websocket实现消息推送(上)(代码片段)
...get方式轮询接入第三方IM系统自己的IM系统基于socket基于websocket第一种方式,最low的,实现简单,但是浪费用户流量;第二种方式,接入简单,功能强大,但是可能需要一定的成本( 查看详情
基于websocket协议的研究demo
1、日志推送 websocket在线测试WebSocket在线测试工具物联网http://www.websocket-test.com/2、Springboot+vue的聊天:Springboot+websocket+vue的web聊天项目https://gitee.com/xzlmk/spring_boot_vue_chat 3、实时通信 4、基于C#net4.5实现最简单的websocket... 查看详情
websocket基于tomcat实现
参考技术AWebSocket是一种支持双向通讯网络通信协议。意思就是服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息属于服务器推送技术的一种。模拟一个用户分别通过H5,PC端,小程序登录系统,后登录的应... 查看详情
php只能做网站?基于swoole+websocket开发双向通信应用(代码片段)
前言众所周知,PHP用于开发基于HTTP协议的网站应用非常便捷。而HTTP协议是一种单向的通信协议,只能接收客户端的请求,然后响应请求,不能主动向客户端推送信息。因此,一些实时性要求比较高的应用,如实时聊天、直播应... 查看详情
基于saas模式的客服云平台落地实践
...条发展之路,营销之路。市场上现有的客服平台一般都是基于网站实现接客能力,提供客服服务,接客渠道单一、服务大众化,在数据安全、使用成本、行业理解、业务整合等方面都会存在足多问题。微保的获客渠道主要有微信... 查看详情
基于websocket协议的研究demo
1、日志推送 websocket在线测试WebSocket在线测试工具物联网http://www.websocket-test.com/2、Springboot+vue的聊天:Springboot+websocket+vue的web聊天项目https://gitee.com/xzlmk/spring_boot_vue_chat 3、实时通信 4、基于C#net4.5实现最 查看详情
基于websocket实现网页版聊天室(代码片段)
WebSocket,HTML5开始提供的一种在单个TCP连接上进行全双工通讯的协议,其使用简单,应用场景也广泛,不同开发语言都用种类繁多的实现,仅Java体系中,Tomcat,Jetty,Spring等都提供了对WS的API支持。本篇不做理论探究,仅自娱... 查看详情
即插即用开源在线客服系统——ppmessage
...ndroid的应用中。PPMessage的前端后端都是开源的,后端全部基于Python,简洁高效。前端根据不同平台提供原生的SDK。650)this.width=650;"src="https://mmbiz.qpic.cn/m 查看详情
springboot基于websocket进行推送
参考技术A客户端发起http请求,请求Netty服务器进行WebSocket连接,服务器接收后请求后进行注册信道并登记客户端IP地址,如此一来就建立了WebSocket通讯连接。上面的论述可以得出,我们可以比较Http和WebSocket两者之间的关系和区... 查看详情