先看一下页面效果,有点简单粗暴!哈哈哈哈哈,别介意.

本文参考:SpringBoot2.0集成WebSocket,实现后台向前端推送信息

新建一个springboot项目

引入相关依赖

  <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency> <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.0</version>
</dependency> <!--com.alibaba/fastjson-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency> <!--websocket依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency> <!--thymeleaf-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

Java代码

WebSocketConfig

@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter(){
return new ServerEndpointExporter();
}
}

PageController

@RestController
public class PageController {
@GetMapping("chat")
public ModelAndView toChat(){
return new ModelAndView("/chat");
}
}

WebSocketServer

@ServerEndpoint("/chat/{userName}")
@Component
@Slf4j
public class WebSocketServer { /**静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。*/
private static int onlineCount = 0;
/**concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。*/
private static ConcurrentHashMap<String,WebSocketServer> webSocketMap = new ConcurrentHashMap<>();
/**与某个客户端的连接会话,需要通过它来给客户端发送数据*/
private Session session; /**接收userId*/
private String userName=""; /**
* @Description: 连接建立成功调用的方法
* @params: [session, userId]
* @return: void
* @Author: wangxianlin
* @Date: 2020/5/9 9:13 PM
*/
@OnOpen
public void onOpen(Session session,@PathParam("userName") String userName) {
this.session = session;
this.userName=userName;
if(webSocketMap.containsKey(userName)){
webSocketMap.remove(userName);
webSocketMap.put(userName,this);
//加入set中
}else{
webSocketMap.put(userName,this);
//加入set中
addOnlineCount();
//在线数加1
} log.info("用户连接:"+userName+",当前在线人数为:" + getOnlineCount()); try {
sendMessage("{\"msg\":\"连接成功\"}");
} catch (IOException e) {
log.error("用户:"+userName+",网络异常!!!!!!");
}
} /**
* @Description: 连接关闭调用的方法
* @params: []
* @return: void
* @Author: wangxianlin
* @Date: 2020/5/9 9:13 PM
*/
@OnClose
public void onClose() {
if(webSocketMap.containsKey(userName)){
webSocketMap.remove(userName);
//从set中删除
subOnlineCount();
}
log.info("用户退出:"+userName+",当前在线人数为:" + getOnlineCount());
} /**
* @Description: 收到客户端消息后调用的方法
* @params: [message, session]
* @return: void
* @Author: wangxianlin
* @Date: 2020/5/9 9:13 PM
*/
@OnMessage
public void onMessage(String message, Session session) {
log.info("用户消息:"+userName+",报文:"+message);
//可以群发消息
//消息保存到数据库、redis
if(StringUtils.isNotBlank(message)){
try {
//解析发送的报文
JSONObject jsonObject = JSON.parseObject(message);
//追加发送人(防止串改)
jsonObject.put("sender",this.userName);
String receiver=jsonObject.getString("receiver");
//传送给对应toUserId用户的websocket
if(StringUtils.isNotBlank(receiver)&&webSocketMap.containsKey(receiver)){
webSocketMap.get(receiver).sendMessage(jsonObject.toJSONString());
}else{
log.error("请求的receiver:"+receiver+"不在该服务器上");
//否则不在这个服务器上,发送到mysql或者redis
}
}catch (Exception e){
e.printStackTrace();
}
}
} /**
*
* @param session
* @param error
*/
@OnError
public void onError(Session session, Throwable error) {
log.error("用户错误:"+this.userName+",原因:"+error.getMessage());
error.printStackTrace();
} /**
* 实现服务器主动推送
*/
public void sendMessage(String message) throws IOException {
this.session.getBasicRemote().sendText(message);
} /**
* @Description: 发送消息
* @params: [message, userId]
* @return: void
* @Author: wangxianlin
* @Date: 2020/5/9 9:09 PM
*/
public static void sendInfo(String message,@PathParam("userId") String userId) throws IOException {
log.info("发送消息到:"+userId+",报文:"+message);
if(StringUtils.isNotBlank(userId)&&webSocketMap.containsKey(userId)){
webSocketMap.get(userId).sendMessage(message);
}else{
log.error("用户"+userId+",不在线!");
}
} /**
* @Description: 获取在线人数
* @params: []
* @return: int
* @Author: wangxianlin
* @Date: 2020/5/9 9:09 PM
*/
public static synchronized int getOnlineCount() {
return onlineCount;
} /**
* @Description: 在线人数+1
* @params: []
* @return: void
* @Author: wangxianlin
* @Date: 2020/5/9 9:09 PM
*/
public static synchronized void addOnlineCount() {
WebSocketServer.onlineCount++;
} /**
* @Description: 在线人数-1
* @params: []
* @return: void
* @Author: wangxianlin
* @Date: 2020/5/9 9:09 PM
*/
public static synchronized void subOnlineCount() {
WebSocketServer.onlineCount--;
}
}

前端HTMl

<div class="layui-container">
<div class="layui-row">
<div class="layui-col-md12">
<fieldset class="layui-elem-field layui-field-title" style="margin-top: 25px;">
<legend style="margin-left: 40%;">简单粗暴的聊天界面</legend>
</fieldset>
<div class="grid-demo grid-demo-bg2" style="text-align: center">
<form class="layui-form">
<div class="layui-form-item">
<label class="layui-form-label">接收者</label>
<div class="layui-input-block">
<input type="text" id="receiver" lay-verify="title" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">发送者</label>
<div class="layui-input-block">
<input type="text" id="sender" autocomplete="off" class="layui-input">
</div>
</div> <div class="layui-form-item layui-form-text">
<label class="layui-form-label">消息</label>
<div class="layui-input-block">
<textarea placeholder="请输入内容" class="layui-textarea" id="msg"></textarea>
</div>
</div>
<div class="layui-col-md12" style="margin-left: 4%">
<div class="layui-tab layui-tab-card" style="height: 200px;overflow: auto">
<fieldset class="layui-elem-field layui-field-title">
<legend>消息记录</legend>
</fieldset>
<div id="msgDiv"> </div>
</div>
</div> <div class="layui-form-item">
<div class="layui-input-block">
<button type="button" class="layui-btn layui-btn-primary" onclick="establishConnection()">
建立连接
</button>
<button type="button" class="layui-btn layui-btn-primary" onclick="sendMessage()">发送消息
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
<script type="text/javascript" th:src="@{/javascript/jquery-2.1.4.js}"></script>
<!--layui-->
<script type="text/javascript" th:src="@{/plugins/layui/layui.js}"></script>

JavaScript代码

var socket;
if (typeof(WebSocket) == "undefined") {
console.log("您的浏览器不支持WebSocket");
} else { /***建立连接*/
function establishConnection() {
var userName = $("#sender").val();
if (userName == '' || userName == null) {
alert("请输入发送者");
return;
}
//实现化WebSocket对象,指定要连接的服务器地址与端口 建立连接
var socketUrl = "" + window.location.protocol + "//" + window.location.host + "/chat/" + userName;
socketUrl = socketUrl.replace("https", "ws").replace("http", "ws");
if (socket != null) {
socket.close();
socket = null;
}
socket = new WebSocket(socketUrl);
//打开事件
socket.onopen = function () {
console.log("开始建立链接....")
};
//关闭事件
socket.onclose = function () {
console.log("websocket已关闭");
};
//发生了错误事件
socket.onerror = function () {
console.log("websocket发生了错误");
};
/**
* 接收消息
* @param msg
*/
socket.onmessage = function (msg) {
msg = JSON.parse(msg.data);
if (msg.msg != '连接成功') {
$("#msgDiv").append('<p class="user">用户名:' + msg.sender + '</p><p class="chat">' + msg.msg + '</p>');
}
};
} /**
* 发送消息
*/
function sendMessage() {
var msg = $("#msg").val();
if (msg == '' || msg == null) {
alert("消息内容不能为空");
return;
}
var receiver = $("#receiver").val();
if (receiver == '' || receiver == null) {
alert("接收人不能为空");
return;
}
var msgObj = {
receiver: receiver,
msg: msg
};
socket.send(JSON.stringify(msgObj));
}
}

【SpringBoot】WebSocket在线聊天的更多相关文章

  1. 微服务-springboot+websocket在线聊天室

    一.引入依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId> ...

  2. Swoole跟thinkphp5结合开发WebSocket在线聊天通讯系统

    ThinkPHP使用Swoole需要安装 think-swoole Composer包,前提系统已经安装好了Swoole PECL 拓展* tp5的项目根目录下执行composer命令安装think- ...

  3. html5 websocket 示例,websocket在线聊天,php websocket实例

    WebSocket在线测试工具 http://ws.douqq.com/ 1.连接格式为 ws://IP/域名:端口(示例ws://119.29.3.36:5354) 2.对于内网的测试环境,只需填入 ...

  4. Spring Websocket实现简易在线聊天功能

    针对Spring Websocket的实现,我参照了其他博主的文章https://www.cnblogs.com/leechenxiang/p/5306372.html 下面直接给出实现: 一.引入相 ...

  5. Swoole 实现在线聊天

    Swoole 跟 thinkphp5 结合开发 WebSocket 在线聊天通讯系统 ThinkPHP 使用 Swoole 需要安装 think-swoole Composer 包,前提系统已经安装 ...

  6. SpringBoot+Vue+WebSocket 实现在线聊天

    一.前言 本文将基于 SpringBoot + Vue + WebSocket 实现一个简单的在线聊天功能 页面如下: 在线体验地址:http://www.zhengqingya.com:8101 二 ...

  7. 基于WebSocket和SpringBoot的群聊天室

    引入 普通请求-响应方式:例如Servlet中HttpServletRequest和HttpServletResponse相互配合先接受请求.解析数据,再发出响应,处理完成后连接便断开了,没有数据的实 ...

  8. 在线聊天室的实现(1)--websocket协议和javascript版的api

    前言: 大家刚学socket编程的时候, 往往以聊天室作为学习DEMO, 实现简单且上手容易. 该Demo被不同语言实现和演绎, 网上相关资料亦不胜枚举. 以至于很多技术书籍在讲解网络相关的编程时, ...

  9. 使用websocket实现在线聊天功能

    很早以前为了快速达到效果,使用轮询实现了在线聊天功能,后来无意接触了socket,关于socket我的理解是进程间通信,首先要有服务器跟客户端,服务的启动监听某ip端口定位该进程,客户端开启socke ...

  10. 使用WebSocket实现简单的在线聊天室

    前言:我自已在网上找好了好多 WebSocket 制作 在线聊天室的案列,发现大佬们写得太高深了 我这种新手看不懂,所以就自已尝试写了一个在线简易聊天室 (我只用了js 可以用jq ) 话不多说,直接 ...

随机推荐

  1. group_concat_max_len设置过小致group_concat()排列不全

    问题描述:group_concat_max_len默认值1024导致group_concat函数排列显示不足 group_concat_max_len长度显示跟group_concat排列长度息息相关 ...

  2. APISIX 是怎么保护用户的敏感数据不被泄露的?

    本文以 APISIX 作为例子,为大家介绍了如何借助 Global Data Encryption 功能来保护敏感数据,确保不会有任何敏感数据进行明文存储,这样即使 etcd 中所有存储的数据都被盗取 ...

  3. Django笔记二十六之数据库函数之数学公式函数

    本文首发于公众号:Hunter后端 原文链接:Django笔记二十六之数据库函数之数学公式函数 这一篇来介绍一下公式函数,主要是数学公式. 其中 sin,cos 这种大多数情况下用不上的就不介绍了,主 ...

  4. nuxt下运行项目时内存溢出(out of memory)的一种情况

    话不多说直接上代码: 如图,点红点的三行引入了一个组件,内容是同意注册协议的弹窗.但是在run dev的时候提示说内存溢出了(out of memory)...经过多方排查,定位到这个组件,警察叔叔就 ...

  5. 2022-08-01:以下go语言代码输出什么?A:panic;B:5;C:6;D:编译错误。 package main import ( “fmt“ ) func main() {

    2022-08-01:以下go语言代码输出什么?A:panic:B:5:C:6:D:编译错误. package main import ( "fmt" ) func main() ...

  6. 2021-01-21:java中,HashMap的读流程是什么?

    福哥答案2020-01-21: jdk1.7读流程:1.key是否为空值null,如果为空,直接遍历table[0]链表,寻找key==null键.调用的是getForNullKey()方法.如下:1 ...

  7. 2022-05-16:A -> B,表示A认为B是红人, A -> B -> C,表示A认为B是红人,B认为C是红人,规定“认为”关系有传递性,所以A也认为C是红人, 给定一张有向图,方式是给定M个有

    2022-05-16:A -> B,表示A认为B是红人, A -> B -> C,表示A认为B是红人,B认为C是红人,规定"认为"关系有传递性,所以A也认为C是红 ...

  8. 2022-02-28:k8s安装adminer,yaml如何写?

    2022-02-28:k8s安装adminer,yaml如何写? 答案2022-02-28: yaml如下: apiVersion: apps/v1 kind: Deployment metadata ...

  9. 2021-09-19:数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且有效的括号组合。

    2021-09-19:数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且有效的括号组合. 福大大 答案2021-09-19: 递归. 参数1:左括号-右括号的数量. 参数2:左 ...

  10. 【GiraKoo】could not find UI helper 'git-credential-manager-ui'

    环境 Windows 11 git version 2.39.0.windows.1 TortoiseGit 现象 使用TortoiseGit执行git pull命令时,提示could not fin ...