基于springboot与websocket实现简易聊天室

这篇具有很好参考价值的文章主要介绍了基于springboot与websocket实现简易聊天室。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.聊天室前端界面

创建一个简单聊天室的HTML和JavaScript代码,匹配相应的css样式,这个聊天室将使用WebSocket技术,允许用户实时发送和接收消息。

1.1 html和js代码

通过new WebSocket(url)建立一个新的websocket连接。websocket连接建立之后使用websocket.onopen,websocket.onclose,websocket.onerror等方法实时监测websocket连接使用情况,并在前端界面实时打印出连接情况,确保用户可以正确无误的使用聊天室。

<!doctype html>
<html>
<head>
    <meta charset="utf-8"></meta>
    <title>聊天室</title>
	<link rel="stylesheet" href="/static/css/index.css" />
</head>
<body>
<div class="main">
    <div class="m-head">
        <div class="head-img"><img src="/static/image/1d0d104e.jpg" height="50px" width="50px" /><span id="user_id">1</span></div>
        <div class="head-title">聊天室频道:test, 聊天中。。。<img src="/static/image/chat.png" height="40px" width="40px" /></div>
    </div>
    <div id="message_id" class="chat_content"></div>
    <form class="send-main" id="send-main">
        <input id="push_content" type="text" placeholder="请输入聊天内容" />
        <button onclick="sendMessage()" class="my-button">发送</button>
        <button onclick="closeWebsocket()" class="my-button close">关闭</button>
    </form>
</div>
</body>
<script type="text/javascript">
    var num = location.href.indexOf("id=");
    var id = 'default';
    if (num > 0) {
        id = decodeURI(location.href.substr(num + 3));
    }
    document.getElementById('push_content').focus();
    var websocket = null;
    //当前浏览前是否支持websocket
    if ("WebSocket" in window) {
        var url = "ws://127.0.0.1:9876/ws_test/" + id;
        document.getElementById('user_id').innerHTML = id;
        websocket = new WebSocket(url);
    } else {
        alert("浏览器不支持websocket");
    }

    websocket.onopen = function(event) {
        document.getElementById('message_id').innerHTML += "<p class='chat_msg_center'>您已进入群聊<br/>";
    }

    websocket.onclose = function(event) {
        document.getElementById('message_id').innerHTML += "<p class='chat_msg_center'>您已退出群聊<br/>";
    }

    websocket.onmessage = function(event) {
        setMessage(event.data);
    }

    websocket.onerror = function(event) {
        document.getElementById('message_id').innerHTML += "<p class='chat_msg_center'>网络异常<br/>";
    }

    //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
    window.onbeforeunload = function() {
        closeWebsocket();
    }

    //关闭websocket
    function closeWebsocket() {
        //3代表已经关闭
        if (3 != websocket.readyState) {
            websocket.close();
        } else {
            document.getElementById('message_id').innerHTML += "<p class='chat_msg_center'>已经退出<br/>";
        }
    }

    //将消息显示在网页上
    function setMessage(message) {
        let msgs = message.split("_^Ag5F_");
        if (msgs[0] == "C1L2I3E4N5T") {
            if (id == msgs[1]) {
                document.getElementById('message_id').innerHTML += "<p class='chat_msg_right'>" + msgs[2] + '<b> :我</b><br/>';
            } else {
                document.getElementById('message_id').innerHTML += "<p class='chat_msg_left'><b>" + msgs[1] + ':</b>' + msgs[2] +
                    '<br/>';
            }
        } else if (msgs[0] == "S1Y2S1T3E4M") {
            document.getElementById('message_id').innerHTML += "<p class='chat_msg_center'>" + msgs[1] + '<br/>';
        }
        let div = document.getElementById('message_id');
        div.scrollTop = div.scrollHeight;
    }

    //发送消息
    function sendMessage() {
        //1代表正在连接
        if (1 == websocket.readyState) {
            var message = document.getElementById('push_content').value;
            //setMessage(message);
            websocket.send(message);
        } else {
            alert("websocket未连接");
        }
        document.getElementById('push_content').value = "";
        document.getElementById('push_content').focus();
    }

    document.getElementById("send-main").onsubmit = function() {
        return false;
    };
</script>
</html>

1.2 前端相应的css样式代码

p,div{
	margin: 0px;
}
.main{
	width: 850px;
	height: 600px;
	margin: auto;
	background: #fff;
	border: 1px solid rgba(153, 153, 153, 1);
	box-shadow: 0px 5px 5px #666;
	margin-top: 20px;
}
.m-head{
	width: 100%;
	height: 60px;
	background-color: #1a92ed;
	color: #FFFFFF;
	font-size: 1.5rem;
	line-height: 60px;
}
.head-img{
	height: 50px;
	padding: 2px 5px;
	float: left;
	color: #FFFFFF;
}
.head-img img{
	border-radius: 30px;
	border: 3px solid #FFFFFF;
	float: left;
}
.head-img span{
	height: 50px;
	font-size: 18px;
	padding-top: 15px;
	float: left;
	display: block;
    line-height: 50px;
}
.head-img:hover{
	cursor: pointer;
}
.head-title{
	width: 450px;
	height: 60px;
	display: block;
	margin: auto;
}
.head-title img{
	padding: 10px 40px 10px 0px;
	float: right;
}
.send-main{
	border-top: 2px solid #CCCCCC;
	padding: 10px;
	position: absolute;
	top: 550px;
}
#push_content{
    outline-style: none ;
    border: 1px solid #ccc; 
    border-radius: 3px;
    padding: 13px 14px;
    width: 674px;
    font-size: 14px;
    font-weight: 600;
    font-family: "仿宋";
}
#push_content:focus{
    border-color: #66afe9;
    outline: 0;
    -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);
    box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)
}
.my-button{
	outline-style: none ;
	border: 1px solid #ccc; 
	border-radius: 3px;
	padding: 12px 14px;
	font-size: 14px;
	font-weight: 600;
	background-color: #0188fb;
	color: #FFFFFF;
}
.close{
	background-color: #CCCCCC;
}
.chat_msg_left{
	height: 30px;
	padding: 5px;
	line-height: 30px;
	text-align: left;
	padding-left: 10px;
}
.chat_msg_right{
	height: 30px;
	padding: 5px;
	line-height: 30px;
	text-align: right;
	padding-right: 10px;
}
.chat_msg_center{
	height: 30px;
	padding: 5px;
	line-height: 30px;
	border-radius: 5px;
	text-align: center;
	color: #666666;
}
.chat_content{
	overflow:auto;
	height: 470px;
}

2.后端核心代码的实现

2.1 项目中所依赖的pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example.websocket</groupId>
    <artifactId>websocket-service</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>websocket-service</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.28</version>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <!-- websocket依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>
        <!--commons-lang3-->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.9</version>
        </dependency>
    </dependencies>

    <build>
        <!-- 最终包名 -->
        <finalName>websocket-service</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

2.2 config系统配置

WebSocket配置,开启WebSocket支持,同时向Spring注册ServerEndpointExporter。
package com.example.websocket.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

/**
 * WebSocket配置,开启WebSocket支持
 */
@Configuration
public class WebSocketConfig {
    /**
     * 向Spring注册ServerEndpointExporter
     *
     * @return
     */
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}

2.3 controller控制层实现

基于SpringBoot应用程序中的WebSocket控制器。这个控制器定义了几个端点,用于处理WebSocket连接和消息传递。为前端界面提供单聊,群聊,消息发送等接口。消息发送成功或是失败,都给出相应的反馈结果。

package com.example.websocket.controller;

import com.example.websocket.service.WebSocketServer;
import com.example.websocket.utils.IPUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
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 org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

/**
 * WebSocket Controller
 */
@Slf4j
@RestController
@RequestMapping(value = "/api/ws")
public class WebSocketController {
    @Autowired
    private WebSocketServer webSocketServer;

    /**
     * 跳转到WebSocket客户端页面
     *
     * @return
     */
    @GetMapping("/index")
    public ModelAndView page() {
        return new ModelAndView("index");
    }

    /**
     * 发送消息到指定用户
     *
     * @param message
     * @param toUserId
     * @return
     */
    @GetMapping("/push/{toUserId}")
    public ResponseEntity<String> pushToUser(String message, @PathVariable String toUserId, HttpServletRequest request) {
        webSocketServer.sendToUser(String.format("C1L2I3E4N5T_^Ag5F_%s_^Ag5F_私信:%s", IPUtils.getIpAddr(request), message), toUserId);
        return ResponseEntity.ok("消息发送成功");
    }

    /**
     * 群发消息
     *
     * @param message
     * @return
     */
    @GetMapping("/push")
    public ResponseEntity<String> pushToWeb(String message, HttpServletRequest request) {
        webSocketServer.sendToAll(String.format("C1L2I3E4N5T_^Ag5F_%s_^Ag5F_%s", IPUtils.getIpAddr(request), message));
        return ResponseEntity.ok("群发消息成功");
    }
}

2.4 srevice服务层实现

package com.example.websocket.service;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
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.concurrent.ConcurrentHashMap;

/**
 * WebSocket的具体实现类
 */
@Slf4j
@Component
@ServerEndpoint(value = "/ws_test/{id}")
public class WebSocketServer {
    /**
     * 客户端ID
     */
    private String userId = "";
    /**
     * 与某个客户端的连接会话,需要通过它来给客户端发送数据
     */
    private Session session;

    /**
     * 记录当前在线连接数(为保证线程安全,须对使用此变量的方法加lock或synchronized)
     */
    private static int onlineCount = 0;

    /**
     * 用来存储当前在线的客户端(此map线程安全)
     */
    private static ConcurrentHashMap<String, WebSocketServer> webSocketMap = new ConcurrentHashMap<>();

    /**
     * 连接建立成功后调用
     */
    @OnOpen
    public void onOpen(Session session, @PathParam(value = "id") String id) throws IOException {
        this.session = session;
        // 接收到发送消息的客户端ID
        this.userId = id;
        if (webSocketMap.containsKey(userId)) {
            webSocketMap.remove(userId);
            webSocketMap.put(userId, this);
            //加入set中
        } else {
            webSocketMap.put(userId, this);
            //加入set中
            addOnlineCount();
            //在线数加1
        }
        log.info("用户连接:" + userId + ",当前在线人数为:" + getOnlineCount());
        sendToAll("S1Y2S1T3E4M_^Ag5F_" + userId + "加入聊天室!!!");
    }

    /**
     * 连接关闭时调用
     */
    @OnClose
    public void onClose() {
        if (webSocketMap.containsKey(userId)) {
            webSocketMap.remove(userId);
            //从set中删除
            subOnlineCount();
        }
        sendToAll("S1Y2S1T3E4M_^Ag5F_" + userId + "退出聊天室!!!");
        log.info("用户退出:" + userId + ",当前在线人数为:" + getOnlineCount());
    }

    /**
     * 收到客户端消息后调用
     *
     * @param message 客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(String message) {
        //可以群发消息
        //消息可以保存到数据库、redis
        if (StringUtils.isNotBlank(message)) {
            try {
                //传送给对应toUserId用户的websocket
                sendToAll(String.format("C1L2I3E4N5T_^Ag5F_%s_^Ag5F_%s", userId, message));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 发生错误时回调
     *
     * @param error
     */
    @OnError
    public void onError(Throwable error) {
        log.error("用户错误:" + this.userId + ",原因:" + error.getMessage());
        error.printStackTrace();
    }

    /**
     * 推送信息给指定ID客户端,如客户端不在线,则返回不在线信息给自己
     *
     * @param message      客户端发来的消息
     * @param sendClientId 客户端ID
     */
    public void sendToUser(String message, String sendClientId) {
        try {
            if (webSocketMap.get(sendClientId) != null) {
                webSocketMap.get(sendClientId).sendMessage(message);
            } else {
                log.error("客户端{}不存在", sendClientId);
            }
        } catch (Exception e) {
            log.error("推送消息到指定客户端出错", e);
        }
    }

    /**
     * 推送发送信息给所有人
     *
     * @param message 要推送的消息
     */
    public void sendToAll(String message) {
        try {
            for (String key : webSocketMap.keySet()) {
                webSocketMap.get(key).sendMessage(message);
            }
        } catch (Exception e) {
            log.error("推送消息到所有客户端出错", e);
        }
    }

    /**
     * 推送消息
     *
     * @param message 要推送的消息
     * @throws IOException
     */
    private void sendMessage(String message) throws IOException {
        this.session.getBasicRemote().sendText(message);
    }

    private static synchronized int getOnlineCount() {
        return onlineCount;
    }

    private static synchronized void addOnlineCount() {
        WebSocketServer.onlineCount++;
    }

    private static synchronized void subOnlineCount() {
        WebSocketServer.onlineCount--;
    }

}

        创建一个Spring Boot项目,并添加相关的依赖。这里使用Lombok库来简化代码,使用Spring Boot的WebSocket依赖来实现WebSocket功能。

        然后,创建一个名为WebSocketServer的类,它实现了ApplicationRunner接口。在这个类中,定义了一个WebSocket端点,并使用@OnOpen、@OnClose、@OnMessage和@OnError注解来处理WebSocket连接的打开、关闭、接收消息和发生错误时的逻辑。

        在WebSocketServer类中,使用一个ConcurrentHashMap来存储当前在线的客户端,并使用一个静态变量来记录当前在线连接数。这样可以知道当前有多少客户端连接到服务器。

在连接建立成功后,使用Session对象来与客户端进行通信。还可以使用sendToUser方法来向指定ID的客户端发送消息,使用sendToAll方法来向所有客户端发送消息。

        最后,需要在Spring Boot应用程序中运行WebSocketServer类。这可以通过在主类中调用applicationRunner方法来实现。

        通过以上步骤成功地实现了一个基于Java和Spring Boot的WebSocket服务端。这个服务端可以处理多个客户端的连接,可以实时地发送和接收消息,可以进行群发消息等操作。

2.5 代码仓库地址

chat: 基于springboot与websocket所实现的简易聊天室

3.项目效果展示

分别打开三个聊天窗口

基于springboot与websocket实现简易聊天室,websocket,网络协议,网络基于springboot与websocket实现简易聊天室,websocket,网络协议,网络基于springboot与websocket实现简易聊天室,websocket,网络协议,网络

使用第三个窗口发送信息

基于springboot与websocket实现简易聊天室,websocket,网络协议,网络

第一个窗口收到信息

基于springboot与websocket实现简易聊天室,websocket,网络协议,网络

第二个窗口收到信息

基于springboot与websocket实现简易聊天室,websocket,网络协议,网络

群聊功能正常,成功实现群聊聊天室。

4.总结

此次学习,实现了一个简易的网络聊天室,支持一对一聊天、用户信息群发推送、获取在线用户、session机制实现用户识别。
虽然课程已然结束,但是学习还未完结,孟宁老师深入浅出的课程讲解给我留下来深刻的印象。在此感谢孟宁老师的教导。文章来源地址https://www.toymoban.com/news/detail-788781.html

到了这里,关于基于springboot与websocket实现简易聊天室的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • WebSocket+Vue实现简易多人聊天室 以及 对异步调用的理解

    代码仓库:github   HTTP是不支持长连接的,WebSocket是一种通信协议,提供了在单一、长连接上进行全双工通信的方式。它被设计用于在Web浏览器和Web服务器之间实现,但也可以用于任何需要实时通信的应用程序。使用ws作为协议标识符,如果需要加密则使用wss作为协议标识符

    2024年01月17日
    浏览(43)
  • 基于SpringBoot+Vue+WebSocket的在线聊天室

    WebSocket 是一种在 Web 应用程序中实现双向通信的协议。它提供了一种持久连接,允许客户端和服务器之间进行实时数据传输,而无需进行频繁的请求和响应。 相对于传统的 HTTP 请求-响应模式,WebSocket 在客户端和服务器之间建立起一条长久的双向通信通道。这意味着服务器可

    2024年01月16日
    浏览(49)
  • 【WebSocket】SpringBoot整合WebSocket实现聊天室(一)

    目录 一、准备 1、引入依赖 2、创建配置类 二、相关注解 首先我们需要在项目中引入依赖,有两种方式。第一种我们可以在创建Spring Boot项目时搜索WebSocket然后勾选依赖 第二种是我们可以直接在项目的pom.xml文件中插入以下依赖 我们需要进行如下配置 ServerEndpointExporter 是一个

    2024年02月13日
    浏览(27)
  • springboot+websocket实现简单的聊天室

    HTML HTML是创建和构造网页的标准标记语言。它使用一组标记标签描述网页上的内容结构。HTML文档由HTML元素的嵌套结构组成,每个元素由尖括号( )括起的标签表示。这些元素定义了网页的各个部分,如标题、段落、图像、链接、表单等。 JavaScript JavaScript是一种高级、解释性

    2024年01月21日
    浏览(43)
  • SpringBoot与webSocket实现在线聊天室——实现私聊+群聊+聊天记录保存

    引用参考:原文章地址:https://blog.csdn.net/qq_41463655/article/details/92410518 在此基础上实现对聊天记录的保存。 代码地址:链接:https://pan.baidu.com/s/1IJFZDa4S_DF08773sKJWeA 提取码:jkui 思路:新建一个实体类用于保存聊天记录,在消息发送时,设置对象的各个值然后保存到数据库中。

    2024年02月02日
    浏览(33)
  • Springboot + Websocket的集成实现简单的聊天室功能

    WebSocket是一种网络通信协议,它可以在单个TCP连接上实现双向(全双工)通信。WebSocket使用HTML5标准,并且可以在客户端和服务器之间建立持久连接,这意味着连接在浏览器刷新或关闭后仍然保持打开状态。 WebSocket的主要优点包括: 1. 双向通信:WebSocket支持客户端和服务器之

    2024年03月21日
    浏览(32)
  • 【WebSocket&IndexedDB】node+WebSocket&IndexedDB开发简易聊天室

    序幕介绍: WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。 讲人话就是说: WebSocket 使得客户端和服务器之间的数据交换变得更加简单,在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数

    2024年02月10日
    浏览(30)
  • Vue+Nodejs 使用WebSocket创建一个简易聊天室

    使用vue编写前端页面,nodejs处理服务端消息,WebSocket进行实时通信 1.客户端 2. 服务端 使用的是nodejs

    2024年02月16日
    浏览(28)
  • SpringBoot和Vue2集成WebSocket,实现聊天室功能

    springboot集成websocket实现聊天室的功能。如有不足之处,还望大家斧正。

    2024年01月23日
    浏览(35)
  • 在线聊天室(Vue+Springboot+WebSocket)

    实现了一个简单的在线聊天室的前后端。前端用Vue实现,后端用Springboot实现。         在线聊天室的功能包括创建用户和显示在线用户列表、发送消息和显示消息列表、用户和消息列表实时更新这几点。以下是整体功能的活动图: 用户身份         进入聊天室的用户需

    2024年01月15日
    浏览(32)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包