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

本文参考: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. mariabackup -prepare step on increment backup failed

    问题描述:使用mariabackup对maridb10.6.4进行物理备份,进行增量恢复的时候报错.截止到目前,还是mariadb的一个bug,还没有修复.在增备的过程中如果出现新库的建立,数据库就会 ...

  2. MQ高级

    1.消息可靠性 消息从发送,到消费者接收,会经理多个过程: 其中的每一步都可能导致消息丢失,常见的丢失原因包括: 发送时丢失: 生产者发送的消息未送达exchange 消息到达exchange后未到达 ...

  3. .NET Web入门到高级路线(新版本)

    .NET Web入门到高级路线 C# 基础语法 .NET Core 基础知识 ASP.NET Core基础知识概述 Blazor ASP.NET Core 官方文档 ORM FreeSql Entit ...

  4. 笔记:C++学习之旅---面向对象程序的设计1

    笔记:C++学习之旅---面向对象程序的设计1 面向对象的主要特征 1.抽象 2.封装 3.继承 4.多态 抽象:将程序的每一部分都看作一个抽象的对象,即程序有一组抽象的对象组成的更复杂点,这些对象根 ...

  5. java中的 \r——字符串消失了

    at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65) 使用Integer.parseInt( ...

  6. Node.js躬行记(28)——Cypress自动化测试实践

    最近在研究如何提升项目质量,提炼了许多个用于自测的测试用例,但是每次修改后,都手工测试,成本太高,于是就想到了自动化测试. 在一年前已将 Cypress 集成到管理后台的项目中,不过没有投入到实践中. ...

  7. 2022-09-15:Range模块是跟踪数字范围的模块。 设计一个数据结构来跟踪表示为 半开区间 的范围并查询它们。 半开区间 [left, right) 表示所有 left <= x < righ

    2022-09-15:Range模块是跟踪数字范围的模块. 设计一个数据结构来跟踪表示为 半开区间 的范围并查询它们. 半开区间 [left, right) 表示所有 left <= x < ...

  8. Django4全栈进阶之路13 template模板

    在 Django 中,模板(Template)用于生成动态的 HTML 页面.通常情况下,Django 项目包含多个视图函数,每个视图函数都负责渲染不同的 HTML 页面.使用模板可以让我们将 HTM ...

  9. vue全家桶进阶之路3:Node.js

    Node.js发布于2009年5月,由Ryan Dahl开发,是一个基于Chrome V8引擎的JavaScript运行环境,使用了一个事件驱动.非阻塞式I/O模型, 让JavaScript 运行在服 ...

  10. AssertionError: Expected a `Response`, `HttpResponse` or `HttpStreamingResponse` to be returned from

    函数里面return response问题: 1.没有 2.写错 3.位置错 例如: return Response('确认成功')