springboot websocket通信

news2025/1/10 17:20:18

目录

一、websocket是什么

二、实现websocket

2.1参考学习b站资料(一定要看,前后端详细)

2.2学习配套代码


一、websocket是什么

WebSocket_ohana!的博客-CSDN博客

二、实现websocket

2.1参考学习b站资料(一定要看,前后端详细)

01-websocket协议及实现_哔哩哔哩_bilibili

2.2学习配套代码

1.导入pom依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

2.编写配置类

//配置类
@Configuration
public class WebSocketConfig {
    @Bean
    //注入ServerEndpointExporter bean对象,自动注册使用注解@ServerEndpoint的bean
    public ServerEndpointExporter serverEndpointExporter(){
        return new ServerEndpointExporter();
    }
}

3.所需要的pojo类:

 4.需要的工具类,用于转化信息格式


import com.example.ex1.mes_websocket.pojo.ResultMessage;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class MessageUtils {
    public static String getMessage(boolean isSystemMessage,String fromName,Object message){
        try {
            ResultMessage result = new ResultMessage();
            result.setSystem(isSystemMessage);
            result.setMessage(message);
            if (fromName!=null){
                result.setFromName(fromName);
            }
            //把字符串转成json格式的字符串
            ObjectMapper mapper = new ObjectMapper();
            return mapper.writeValueAsString(result);
        }catch (JsonProcessingException e){
            e.printStackTrace();
        }
        return null;
    }
}

 5.登录的验证以及获取用户名的controller

import com.example.ex1.mes_websocket.pojo.Result;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpSession;

@RestController
public class LoginController {
    @RequestMapping("/toLogin")
    public Result tologin(@RequestParam("user") String user,@RequestParam("pwd") String pwd, HttpSession session){
        Result result = new Result();
        if (user.equals("张三")&&pwd.equals("123")){
            result.setFlag(true);
            session.setAttribute("user",user);
        }else if (user.equals("李四")&&pwd.equals("123")){
            result.setFlag(true);
            session.setAttribute("user",user);
        }else if (user.equals("123")&&pwd.equals("123")){
            result.setFlag(true);
            session.setAttribute("user",user);
        }
        else if (user.equals("王五")&&pwd.equals("123")){
            result.setFlag(true);
            session.setAttribute("user",user);
        }else {
            result.setFlag(false);
            result.setMessage("登录失败");
        }
        return result;
    }

    @RequestMapping("/getUsername")
    public String getUsername(HttpSession session){
        String username = (String) session.getAttribute("user");
        return username;
    }
}

 6.登录页面(前端页面用到jquery)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script src="js/jquery.min.js"></script>
<form id="loginForm">
    <label>账号:</label>
    <input type="text" name="user">
    <label>密码:</label>
    <input type="password" name="pwd">
    <button type="button" id="btn">登录</button>
</form>
<p id="err_msg"></p>
<script>
    $("#btn").click(function () {
        $.get("toLogin?",$("#loginForm").serialize(),function(res){
            if (res.flag){
                console.log(res);
                location.href = "main.html";
            } else {
                console.log(res);
                $("#err_msg").html(res.message);
            }
        },"json");
    })
</script>
</body>
</html>

7.主页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<style>
    #left{
        float: left;
        width: 30%;
        height: 500px;
        margin-left: 200px;
    }
    #right{
        float: right;
        width: 30%;
        height: 500px;
    }
    #top{
        margin-top: 50px;
        float: top;
        width: 30%;
        height: 250px;
    }
    #content{
        border: aquamarine 1px solid;
        width: 100%;
        height: 300px;
    }
    #input{
        margin-top: 20px;
        width: 100%;
        height: 200px;
    }
    #input input{
        width: 100%;
        height: 100px;
    }
    #input button{
        float: right;
    }
    #mes_left{
        float: left;

    }
    #mes_right{
        float: right;
        width: 50%;
        text-align: right;
    }
</style>
<body>
<script src="js/jquery.min.js"></script>
<h3 style="text-align: center" id="username"></h3>
<div>
    <div id="left">
        <h4 id="new"></h4>
        <div id="content">

        </div>
        <div id="input">
            <input type="text" id="input_text">
            <button id="submit">发送</button>
        </div>
    </div>
    <div id="right">
        <div id="top">
            <p>在线的好友</p>
            <div id="hylist">

            </div>
        </div>
        <div id="bottom">
            <p>系统广播</p>
            <div id="xtlist">
            </div>
        </div>
    </div>
</div>
<script>
    var username;
    $(function () {
        var toName;
        $.ajax({
            url:"getUsername",
            success:function (res) {
                username = res;
                $("#username").html("用户:"+ username +"<span>在线</span>");
                // $("#username").html("用户:123<span>在线</span>");
            },
            async:false //同步请求,只有上面好了才会接着下面
        });

        var ws = new WebSocket("ws://localhost:8080/chat");
        ws.onopen = function (ev) {
            $("#username").html("用户:"+ username +"<span>在线</span>");
        }
        //接受消息
        ws.onmessage = function (ev) {
            var datastr = ev.data;
            var res = JSON.parse(datastr);
            //判断是否是系统消息
            if(res.system){
                //好友列表
                //系统广播
                var names = res.message;
                var userlistStr = "";
                var broadcastListStr = "";
                for (var name of names){
                    if (name != username){
                        userlistStr += "<a οnclick='showChat(\""+name+"\")'>"+ name +"</a></br>";
                        broadcastListStr += "<p>"+ name +"上线了</p>";
                    }
                };
                $("#hylist").html(userlistStr);
                $("#xtlist").html(broadcastListStr);

            }else {
                //不是系统消息
                var str = "<span id='mes_left'>"+ res.message +"</span></br>";
                if (toName == res.fromName) 
                $("#content").append(str);

                var chatdata = sessionStorage.getItem(res.fromName);
                if (chatdata != null){
                    str = chatdata + str;
                }
                sessionStorage.setItem(res.fromName,str);

            };
        },
        ws.onclose = function (ev) {
            $("#username").html("用户:"+ username +"<span>离线</span>");
        }

        showChat = function(name){
            // alert("dsaad");
            toName = name;
            //清空聊天区
            $("#content").html("");
            $("#new").html("当前正与"+toName+"聊天");
            var chatdata = sessionStorage.getItem(toName);
            if (chatdata != null){
                $("#content").html(chatdata);
            }
        };
        //发送消息
        $("#submit").click(function () {
            //获取输入的内容
            var data = $("#input_text").val();
            $("#input_text").val("");
            var json = {"toName": toName ,"message": data};
            //将数据展示在聊天区
            var str = "<span id='mes_right'>"+ data +"</span></br>";
            $("#content").append(str);

            var chatdata = sessionStorage.getItem(toName);
            if (chatdata != null){
                str = chatdata + str;
            }
            sessionStorage.setItem(toName,str);
            //发送数据
            ws.send(JSON.stringify(json));
        })
    })
</script>
</body>
</html>

8.获取HttpSession对象的类

import javax.servlet.http.HttpSession;
import javax.websocket.HandshakeResponse;
import javax.websocket.server.HandshakeRequest;
import javax.websocket.server.ServerEndpointConfig;

public class GetHttpSessionConfigurator extends ServerEndpointConfig.Configurator {
    @Override
    public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
        //获取HttpSession对象
        HttpSession httpSession = (HttpSession) request.getHttpSession();
        sec.getUserProperties().put(HttpSession.class.getName(),httpSession);
    }
}

9.最后的通信类


import com.example.ex1.mes_websocket.pojo.Message;
import com.example.ex1.mes_websocket.utils.MessageUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpSession;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

@ServerEndpoint(value = "/chat",configurator = GetHttpSessionConfigurator.class)
@Component
public class ChatEndpoint {

    //用来存储每个用户客户端对象的ChatEndpoint对象
    private static Map<String,ChatEndpoint> onlineUsers = new ConcurrentHashMap<>();

    //声明session对象,通过对象可以发送消息给指定的用户
    private Session session;

    //声明HttpSession对象,我们之前在HttpSession对象中存储了用户名
    private HttpSession httpSession;

    //连接建立
    @OnOpen
    public void onOpen(Session session, EndpointConfig config){
        this.session = session;
        HttpSession httpSession = (HttpSession) config.getUserProperties().get(HttpSession.class.getName());
        this.httpSession = httpSession;
        //存储登陆的对象
        String username = (String)httpSession.getAttribute("user");
        onlineUsers.put(username,this);

        //将当前在线用户的用户名推送给所有的客户端
        //1 获取消息
        String message = MessageUtils.getMessage(true, null, getNames());
        //2 调用方法进行系统消息的推送
        broadcastAllUsers(message);
    }

    private void broadcastAllUsers(String message){
        try {
            //将消息推送给所有的客户端
            Set<String> names = onlineUsers.keySet();
            for (String name : names) {
                ChatEndpoint chatEndpoint = onlineUsers.get(name);
                chatEndpoint.session.getBasicRemote().sendText(message);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    //返回在线用户名
    private Set<String> getNames(){
        return onlineUsers.keySet();
    }

    //收到消息
    @OnMessage
    public void onMessage(String message,Session session){
        //将数据转换成对象
        try {
            ObjectMapper mapper =new ObjectMapper();
            Message mess = mapper.readValue(message, Message.class);
            String toName = mess.getToName();
            String data = mess.getMessage();
            String username = (String) httpSession.getAttribute("user");
            String resultMessage = MessageUtils.getMessage(false, username, data);
            //发送数据
            onlineUsers.get(toName).session.getBasicRemote().sendText(resultMessage);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
    //关闭
    @OnClose
    public void onClose(Session session) {
        String username = (String) httpSession.getAttribute("user");
        //从容器中删除指定的用户
        onlineUsers.remove(username);
        MessageUtils.getMessage(true,null,getNames());
    }}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/482768.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

4 异常机制--数组、切片、算法【Go语言教程】

4 异常机制–数组、切片、算法【Go语言教程】 1 异常机制 1.1 处理错误 Go 语言追求简洁优雅&#xff0c;所以&#xff0c;Go 语言不支持传统的 try…catch…finally 这种处理。Go 中引入的处理方式为&#xff1a;defer, panic, recover这几个异常的使用场景可以这么简单描述…

【小沐学Python】Python实现Web服务器(Flask框架扩展:Flask-Admin)

文章目录 1、简介1.1 flask1.2 flask-admin 2、安装2.1 安装库2.2 打印库版本 3、初始化4、添加独立视图&#xff08;BaseView&#xff09;4.1 管理接口索引页4.2 自定义视图 5、添加模型视图&#xff08;ModelView&#xff09;6、添加特殊视图6.1 Managing Files & Folder…

VS2019配置redis客户端的c++开发环境

目录 需要的开源库&#xff1a; 具体步骤&#xff1a; 遇到的问题&#xff1a; 1. 确保每个项目使用的配置解决方案管理器一样 2.CMAKE 的安装 3. 使用 CMAKE 的路径配置 4. redis 编译报错&#xff1a;jemalloc/jemalloc.h没有这个文件&#xff0c;或者找不到.dll 5. linux …

【Linux】初识Linux --指令Ⅰ

Halo&#xff0c;这里是Ppeua。平时主要更新C语言&#xff0c;C&#xff0c;数据结构算法&#xff0c;Linux…感兴趣就关注我吧&#xff01;你定不会失望。 目录 1.ls 显示当前目录下的文件内内容2.pwd-显示用户当前所在的目录3.cd-改变工作目录。将当前工作目录改变到指定的目…

C++ STL-deque

deque&#xff1a;双端队列 目录 deque&#xff1a;双端队列 1、 基本介绍 2、使用方法 2.1、 头文件 2.2、 定义 2.3、 方法函数 3、排序 1、 基本介绍 首尾都可插入和删除的队列为双端队列。 deque容器是连续的空间&#xff0c;其他连续的行空间还有 array 和 vect…

E. Multihedgehog(多叉树找root节点)

Problem - E - Codeforces 有人给Ivan一个奇怪的生日礼物&#xff0c;这是一只刺猬 - 一个连通的无向图&#xff0c;其中一个顶点的度至少为3&#xff08;我们称其为中心&#xff09;&#xff0c;而所有其他顶点的度数均为1。Ivan认为刺猬太无聊了&#xff0c;决定自己制造k-多…

总结838

四月结束&#xff0c;五月来临。又到了月度总结与规划的时候了。 四月总结&#xff1a;高等数学原计划复习完18讲内容&#xff0c;刷完对应的习题。如今还剩三讲&#xff0c;本可以看完&#xff0c;但因为后面分专题了&#xff0c;还没确定是数1还是数2.所以耽搁了一下。英语原…

SG函数(博弈论)

一&#xff0c;定义 对于满足以下条件的公平二人游戏&#xff0c;均可以用sg函数&#xff08;暴搜&#xff09;获得答案 人数2人 两人交替进行合法操作&#xff0c;无法进行者LOSE对 于游戏的任意一种可能的局面&#xff0c;合法的操作集合只取决于这个局面的本身&#xff0c;…

掌握 Python 接口自动化测试理论,深度解读测试框架源码

目录&#xff1a;导读 引言 一、什么是接口测试、为什么要做接口测试 1、什么是接口测试 2、为什么要做接口测试 二、接口测试的流程 1、接口测试的流程 2、为什么要写测试用例 3、接口测试设计要点 三、python接口自动化-requests的应用 1、requests简介 2、reques…

Winform从入门到精通(37)——FolderBrowserDialog(史上最全)

文章目录 前言1、Name2、Description3、RootFolder4、SelectedPath5、ShowNewFolderButton前言 当需要获取一个可以通过用户自由选择路径的时候,这时候就需要FolderBrowserDialog控件 1、Name 获取FolderBrowserDialog对象 2、Description 用于指示对话框的描述,如下: …

Doris(22):Doris的函数—地理位置函数

1 ST_AsText(GEOMETRY geo) 将一个几何图形转化为WKT(Well Known Text)的表示形式 SELECT ST_AsText(ST_Point(24.7, 56.7)); 2 ST_Circle(DOUBLE center_lng, DOUBLE center_lat, DOUBLE radius) 将一个WKT(Well Known Text)转化为地球球面上的一个圆。其中center_lng表…

20230502 强化学习与反馈控制_利用自然决策方法设计最优自适应控制器

目录&#xff1a;强化学习与反馈控制_利用自然决策方法设计最优自适应控制器 总体介绍强化学习二级目录三级目录 总体介绍 本文描述了利用强化学习原理为离散和连续系统设计反馈控制器&#xff0c;该控制器结合了自适应控制和最优控制的特点。自适应控制和最优控制代表了设计反…

【ElasticSearch】EQL操作相关

文章目录 EQL操作基础语法数据准备数据窗口搜索统计符合条件的事件事件序列 安全检测数据准备查看数据导入情况获取 regsvr32 事件的计数检查命令行参数检查恶意脚本加载检查攻击成功可能性 EQL操作 EQL 的全名是 Event Query Language (EQL)。事件查询语言&#xff08;EQL&…

Meta财报预测:市场悲观情绪被过度放大,Meta股价未来将强势反弹

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 4月26日收盘后&#xff0c;Meta(META)将发布2023年第一季度财报。由于全球在线广告支出的减少给Meta这样的广告平台带来了很大的压力&#xff0c;市场对Meta的投资情绪非常悲观&#xff0c;华尔街分析师也预测&#xff0c;…

chatGPT免登录的版本哪里有啊

ChatGPT免费次数 Chat GPT 模型通常通过 API 或 SDK 的方式进行使用&#xff0c;并且有一定的免费使用次数或免费试用期&#xff0c;以便用户可以在部分场景下了解模型的性能和效果。但是&#xff0c;每个机器学习平台或服务商的免费使用次数和试用期都可能不同&#xff0c;您…

ChatGPT回复中断的原因-chatGPT国内中文版免费

ChatGPT回复中断怎么办啊 如果您使用ChatGPT时遇到了中断或错误&#xff0c;以下是一些可能有用的解决方案&#xff1a; 检查输入是否正常&#xff1a;输入文本是否符合语法规范和限制条件&#xff0c;例如输入文本长度是否超过了模型限制等等。如果输入不符合要求&#xff0c…

pikachu靶场-Unsafe Filedownload

不安全的文件下载 文件下载功能在很多web系统上都会出现&#xff0c;一般我们当点击下载链接&#xff0c;便会向后台发送一个下载请求&#xff0c;一般这个请求会包含一个需要下载的文件名称&#xff0c;后台在收到请求后 会开始执行下载代码&#xff0c;将该文件名对应的文件…

Mysql数据库基础知识总复习

前言 小亭子正在努力的学习编程&#xff0c;接下来将开启javaEE的学习~~ 分享的文章都是学习的笔记和感悟&#xff0c;如有不妥之处希望大佬们批评指正~~ 同时如果本文对你有帮助的话&#xff0c;烦请点赞关注支持一波, 感激不尽~~ 目录 数据库基础知识 数据&#xff0c;数据…

GPT是什么,GPT-4是什么

GPT是Generative Pre-trained Transformer的缩写&#xff0c;是一种人工智能语言模型。为了实现自然语言生成和文本补全等功能&#xff0c;通过训练大规模数据集&#xff0c;GPT模型可以预测某个词或文本的下一个可能的词或文本。GPT是由OpenAI团队推出的&#xff0c;目前已经推…

如何用 GPT-4 帮你写游戏?

你知道的&#xff0c;GPT-4 发布了。 目前你想要用上 GPT-4&#xff0c;主要的渠道是 ChatGPT Plus 。作为交了订阅费的用户&#xff0c;你可以在对话的时候选择模型来使用。 另一种渠道&#xff0c;就是申请官方 API 的排队。我在申请 New Bing Chat 的时候&#xff0c;耐心被…