springboot+vue实现websocket通信实例,进入页面建立连接

springboot+vue实现websocket通信实例

在这里插入图片描述
进入页面建立连接
在这里插入图片描述

前端代码:

<template><div class="app-container"><el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px"><el-form-item label="姓名" prop="name"><el-inputv-model="queryParams.name"placeholder="请输入姓名"clearable@keyup.enter.native="handleQuery"/></el-form-item><el-form-item label="密码" prop="pwd"><el-inputv-model="queryParams.pwd"placeholder="请输入密码"clearable@keyup.enter.native="handleQuery"/></el-form-item><el-form-item><el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button><el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button></el-form-item></el-form><el-row :gutter="10" class="mb8"><el-col :span="1.5"><el-buttontype="primary"plainicon="el-icon-plus"size="mini"@click="handleAdd"v-hasPermi="['testuser:testuser:add']">新增</el-button></el-col><el-col :span="1.5"><el-buttontype="success"plainicon="el-icon-edit"size="mini":disabled="single"@click="handleUpdate"v-hasPermi="['testuser:testuser:edit']">修改</el-button><el-buttontype="success"plainicon="el-icon-edit"size="mini":disabled="single"@click="handleTestNormal">自定义</el-button></el-col><el-col :span="1.5"><el-buttontype="danger"plainicon="el-icon-delete"size="mini":disabled="multiple"@click="handleDelete"v-hasPermi="['testuser:testuser:remove']">删除</el-button></el-col><el-col :span="1.5"><el-buttontype="warning"plainicon="el-icon-download"size="mini"@click="handleExport"v-hasPermi="['testuser:testuser:export']">导出</el-button></el-col><right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar></el-row><el-table v-loading="loading" :data="testuserList" @selection-change="handleSelectionChange"><el-table-column type="selection" width="55" align="center" /><el-table-column label="主键" align="center" prop="id" /><el-table-column label="姓名" align="center" prop="name" /><el-table-column label="密码" align="center" prop="pwd" /><el-table-column label="操作" align="center" class-name="small-padding fixed-width"><template slot-scope="scope"><el-buttonsize="mini"type="text"icon="el-icon-edit"@click="handleUpdate(scope.row)"v-hasPermi="['testuser:testuser:edit']">修改</el-button><el-buttonsize="mini"type="text"icon="el-icon-edit"@click="handleTestNormal(scope.row)"v-hasPermi="['testuser:testuser:edit']">自定义</el-button><el-buttonsize="mini"type="text"icon="el-icon-delete"@click="handleDelete(scope.row)"v-hasPermi="['testuser:testuser:remove']">删除</el-button></template></el-table-column></el-table><paginationv-show="total>0":total="total":page.sync="queryParams.pageNum":limit.sync="queryParams.pageSize"@pagination="getList"/><!-- 添加或修改testuser对话框 --><el-dialog :title="title" :visible.sync="open" width="500px" append-to-body><el-form ref="form" :model="form" :rules="rules" label-width="80px"><el-form-item label="姓名" prop="name"><el-input v-model="form.name" placeholder="请输入姓名" /></el-form-item><el-form-item label="密码" prop="pwd"><el-input v-model="form.pwd" placeholder="请输入密码" /></el-form-item></el-form><div slot="footer" class="dialog-footer"><el-button type="primary" @click="submitForm">确 定</el-button><el-button @click="cancel">取 消</el-button></div></el-dialog></div>
</template><script>
import { listTestuser, getTestuser, delTestuser, addTestuser, updateTestuser, handleTest} from "@/api/testuser/testuser";export default {name: "Testuser",data() {return {// 遮罩层loading: true,// 选中数组ids: [],// 非单个禁用single: true,// 非多个禁用multiple: true,// 显示搜索条件showSearch: true,// 总条数total: 0,// testuser表格数据testuserList: [],// 弹出层标题title: "",// 是否显示弹出层open: false,// 查询参数queryParams: {pageNum: 1,pageSize: 10,name: null,pwd: null,},// 表单参数form: {},// 表单校验rules: {},//自定义表单校验check: {},reconnectCount : 0};},created() {this.getList();this.connectWebSocket();},methods: {connectWebSocket: function() {// 创建 WebSocket 连接if('WebSocket' in window){this.socket = new WebSocket("ws://127.0.0.1:8080/websocket/yuanrenjie");} else{alert('Not support websocket')};//最大尝试链接次数const maxReconnectAttempts = 10;const reconnectInterval = 1000; // 1秒const tryReconnect = () => {if (this.reconnectCount < maxReconnectAttempts) {console.log('Reconnecting...');this.connectWebSocket();this.reconnectCount++;} else {console.log('Exceeded max reconnect attempts, stopping reconnecting.');}};this.socket.addEventListener('open', (event) => {console.log('WebSocket 连接已建立')let msg = {// clientName: '发送erp仓库连接消息',clientName: '',message: null,printPiece: 1,labelInfo: null}let json = JSON.stringify(msg)this.socket.send(json)})this.socket.addEventListener('message', (event) => {//接收到的数据const receivedData = event.data;// alert('接收到的信息receivedData:  ' + receivedData);console.log('Received data:', receivedData)})// socket.addEventListener('close', (event) => {this.socket.addEventListener('close', (event) => {console.log('WebSocket connection closed')// 在连接关闭时触发重连逻辑// setTimeout(() => {//   console.log('Reconnecting...')//   this.connectWebSocket()// }, 1000) // 1秒后重连// 清除重连计数,防止无限递增// 在连接关闭后,间隔一段时间进行重连setTimeout(tryReconnect, reconnectInterval);})// socket.addEventListener('error', (event) => {this.socket.addEventListener('error', (event) => {console.error('WebSocket error:', event)// 在错误发生时触发重连逻辑// setTimeout(() => {//   console.log('Reconnecting...')//   this.connectWebSocket()// }, 1000) // 1秒后重连// 在连接错误后,间隔一段时间进行重连setTimeout(tryReconnect, reconnectInterval);})window.addEventListener('beforeunload', (event) => {// 当 tab 关闭时,关闭 WebSocket 连接this.socket.close();});},/** 查询testuser列表 */getList() {this.loading = true;listTestuser(this.queryParams).then(response => {this.testuserList = response.rows;this.total = response.total;this.loading = false;});},// 取消按钮cancel() {this.open = false;this.reset();},// 表单重置reset() {this.form = {id: null,name: null,pwd: null,createTime: null,updateTime: null};this.resetForm("form");},/** 搜索按钮操作 */handleQuery() {this.queryParams.pageNum = 1;this.getList();},/** 重置按钮操作 */resetQuery() {this.resetForm("queryForm");this.handleQuery();},// 多选框选中数据handleSelectionChange(selection) {this.ids = selection.map(item => item.id)this.single = selection.length!==1this.multiple = !selection.length},/** 新增按钮操作 */handleAdd() {this.reset();this.open = true;this.title = "添加testuser";},/** 修改按钮操作 */handleUpdate(row) {this.reset();const id = row.id || this.idsgetTestuser(id).then(response => {this.form = response.data;this.open = true;this.title = "修改testuser";});},/** 自定义按钮操作 */handleTestNormal(row) {if(row.id){handleTest(this.check).then(response => {});}else {const id = row.id || this.idsgetTestuser(id).then(response => {this.check = response.data;handleTest(this.check).then(response => {});});}},/** 提交按钮 */submitForm() {this.$refs["form"].validate(valid => {if (valid) {if (this.form.id != null) {updateTestuser(this.form).then(response => {this.$modal.msgSuccess("修改成功");this.open = false;this.getList();});} else {addTestuser(this.form).then(response => {this.$modal.msgSuccess("新增成功");this.open = false;this.getList();});}}});},/** 删除按钮操作 */handleDelete(row) {const ids = row.id || this.ids;this.$modal.confirm('是否确认删除testuser编号为"' + ids + '"的数据项?').then(function() {return delTestuser(ids);}).then(() => {this.getList();this.$modal.msgSuccess("删除成功");}).catch(() => {});},/** 导出按钮操作 */handleExport() {this.download('testuser/testuser/export', {...this.queryParams}, `testuser_${new Date().getTime()}.xlsx`)}/** 导出发货计划 */// handleExportExcelNeed(row) {//   const ids = row.id || this.ids;//   toExcel(ids).then(response => {//     this.$alert(response.msg, "导出成功", response.msg);//   });//// }}
};
</script>

后端java:
开启配置

package com.ruoyi.web.core.config;import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;@Component
public class WebSocketConfig {/*** ServerEndpointExporter 作用** 这个Bean会自动注册使用@ServerEndpoint注解声明的websocket endpoint** @return*/@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}
}

具体接口:

package com.ruoyi.web.core.config;import com.ruoyi.common.annotation.Anonymous;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;@Anonymous
@Component
@Slf4j
@ServerEndpoint("/websocket/{userId}")  // 接口路径 ws://localhost:8087/webSocket/userId;
public class WebSocketServer {//与某个客户端的连接会话,需要通过它来给客户端发送数据private Session session;/*** 用户ID*/private String userId;//concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。//虽然@Component默认是单例模式的,但springboot还是会为每个websocket连接初始化一个bean,所以可以用一个静态set保存起来。//  注:底下WebSocket是当前类名private static CopyOnWriteArraySet<WebSocketServer> webSockets =new CopyOnWriteArraySet<>();// 用来存在线连接用户信息private static ConcurrentHashMap<String,Session> sessionPool = new ConcurrentHashMap<String,Session>();/*** 链接成功调用的方法*/@OnOpenpublic void onOpen(Session session, @PathParam(value="userId")String userId) {try {this.session = session;this.userId = userId;webSockets.add(this);sessionPool.put(userId, session);log.info("【websocket消息】有新的连接,总数为:"+webSockets.size());} catch (Exception e) {}}/*** 链接关闭调用的方法*/@OnClosepublic void onClose() {try {webSockets.remove(this);sessionPool.remove(this.userId);log.info("【websocket消息】连接断开,总数为:"+webSockets.size());} catch (Exception e) {}}/*** 收到客户端消息后调用的方法** @param message* @param*/@OnMessagepublic void onMessage(String message) {log.info("【websocket消息】收到客户端消息:"+message);}/** 发送错误时的处理* @param session* @param error*/@OnErrorpublic void onError(Session session, Throwable error) {log.error("用户错误,原因:"+error.getMessage());error.printStackTrace();}// 此为广播消息public void sendAllMessage(String message) {log.info("【websocket消息】广播消息:"+message);for(WebSocketServer webSocket : webSockets) {try {if(webSocket.session.isOpen()) {webSocket.session.getAsyncRemote().sendText(message);}} catch (Exception e) {e.printStackTrace();}}}// 此为单点消息public void sendOneMessage(String userId, String message) {Session session = sessionPool.get(userId);if (session != null&&session.isOpen()) {try {log.info("【websocket消息】 单点消息:"+message);session.getAsyncRemote().sendText(message);} catch (Exception e) {e.printStackTrace();}}}// 此为单点消息(多人)public void sendMoreMessage(String[] userIds, String message) {for(String userId:userIds) {Session session = sessionPool.get(userId);if (session != null&&session.isOpen()) {try {log.info("【websocket消息】 单点消息:"+message);session.getAsyncRemote().sendText(message);} catch (Exception e) {e.printStackTrace();}}}}}

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

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

相关文章

HarmonyOS应用开发者高级认证【题库答案】

HarmonyOS应用开发者基础认证【题库答案】 一、判断题 云函数打包完成后&#xff0c;需要到AppGallery Connect创建对应函数的触发器才可以在端侧中调用&#xff08;错&#xff09;在column和Row容器组件中&#xff0c;aligntems用于设置子组件在主轴方向上的对齐格式&#xf…

NFTScan | 11.20~11.26 NFT 市场热点汇总

欢迎来到由 NFT 基础设施 NFTScan 出品的 NFT 生态热点事件每周汇总。 周期&#xff1a;2023.11.20~ 2023.11.26 NFT Hot News 01/ OKX Ordinals 市场 API 完成升级 11 月 21 日&#xff0c;OKX Ordinals 市场 API 现已完成升级&#xff0c;新增支持按币种单价查询、排序&…

【Python游戏开发】使用Python编写拼图益智游戏教程

使用Python编写拼图益智游戏 大家一般都玩过拼图益智游戏&#xff0c;或者类似的游戏。今天&#xff0c;就给大家使用pygame库在Python中构建一个拼图益智小游戏。这个拼图小游戏是构建一个围绕着将1-15个数字排列在16个方块的网格中的游戏。 现在&#xff0c;让我们从今天的惊…

反思一次效能提升

前天与一个大佬交流。想起自己在6年多前在团队里做的一次小小的效能提升。 改进前 在同一个产品团队&#xff0c;同时有前端工程师和后端工程师。他们经常需要共同协作完成features。 前端是一个传统的多页应用。前端渲染是由后端的velocity模板引擎实现的。 打包后&#xff0c…

十四、机器学习进阶知识:KNN分类算法

文章目录 1、KNN分类介绍2、KNN分类核心要素3、KNN分类实例1.1 鸢尾花分类1.2 手写数字识别 1、KNN分类介绍 分类是数据分析中非常重要的方法&#xff0c;是对己有数据进行学习,得到一个分类两数或构造出一个分类模型&#xff08;即通常所说的分类器(Classifier))。分类是使用…

卸载软件最最最彻底的工具——Uninstall Tool

卸载软件最最最彻底的工具——Uninstall Tool Uninstall Tool 是一款功能强大的专业卸载工具。针对一些普通卸载不彻底的问题&#xff0c;它可以做到最优&#xff0c;比如Matlab等软件的卸载难的问题也可以较好地解决。 它比 Windows 自带的“添加/删除程序”功能快 3 倍&…

经典的Shiro反序列化漏洞复现

目录 0x01、前言 0x02、环境搭建 0x03、漏洞原理 0x04、漏洞复现 0x05、漏洞分析 5.1、加密 5.2、解密 0x06、总结 0x01、前言 相信大家总是面试会问到java反序列化&#xff0c;或者会问到标志性的漏洞&#xff0c;比如shiro反序列化&#xff0c;或者weblogic反序列化漏…

arcgis pro使用自定义svg图标

1.点击目录窗格中的样式 可以将本地图标加载到收藏夹中 2.右键收藏夹&#xff0c;点击管理样式 3.双击收藏夹进入此页面 4.在空白处右键&#xff0c;点击新建 5.选中新建的符号&#xff0c;更改图标 6.上传完毕&#xff0c;点击应用即可使用 7.效果 8.此外也可以直接上传图片…

【Linux】vim-多模式的文本编辑器

本篇文章内容和干货较多&#xff0c;希望对大家有所帮助&#x1f44d; 目录 一、vim的介绍 1.1 vi 与 vim的概念1.2 Vim 和 Vi 的一些对比 二、vim 模式之间的切换 2.1 进入vim2.2 [正常模式]切换到[插入模式]2.3 [插入模式]切换至[正常模式]2.4 [正常模式]切换至[底行模式…

怎么快速制作一本出色的电子期刊!

比起传统纸质期刊&#xff0c;电子期刊有着众多的优势&#xff0c;它打破了以往的传播形式和人们传统的时空观念&#xff0c;从而更加贴近人们的生活&#xff0c;更好地满足新时代人们对文化生活的更高要求。如何制作电子期刊呢&#xff1f; 其实很简单&#xff0c;只需要使用…

【在线AI绘画平台】哩布AI 在线生成图片、训练Lora、上传AI生成图简易实测

文章目录 一、主页面介绍1.1首页[网址 https://www.liblib.ai/](https://www.liblib.ai/)侧边栏可收起 1.2 模型页面1.2.1 按模型筛选相关1.2.2 封面的细节1.2.3 点击后进入封面&#xff1a; 二、在线生成图片2.1 直接从主页面进入2.1.1 在线生成的链接&#xff08;与webui几乎…

代理模式-C语言实现

UML图&#xff1a; 代码实现&#xff1a; #include <stdio.h>// 抽象主题接口 typedef struct {void (*request)(void*); } Subject;// 具体主题类 typedef struct {void (*request)(void*); } RealSubject;void RealSubject_request(void* obj) {printf("RealSubj…

win10下载Remix IDE桌面版以及空白页面的解决

文章目录 Remix IDE 的下载Remix IDE 空白页面的解决 Remix IDE 的下载 到 github 地址 https://github.com/ethereum/remix-desktop/releases 选择exe文件或根据自己电脑版本选择对应的zip文件进行下载&#xff0c;然后正常安装即可。 Remix IDE 空白页面的解决 有时打开Remix…

docker容器的生命周期管理常用命令

容器的生命周期管理命令 docker create &#xff1a;创建一个新的容器但不启动它 docker create nginx docker run :创建一个新的容器并运行一个命令 常用选项&#xff1a; 常用选项1. --add-host&#xff1a;容器中hosts文件添加 host:ip 映射记录 2. -a, --attach&#…

【STL】string类 (下)

目录 1&#xff0c;insert 2&#xff0c;erase 3&#xff0c;find 4&#xff0c;replace 5&#xff0c;rfind 6&#xff0c;substr 7&#xff0c;find_first_of 8&#xff0c;find_first_not_of 9&#xff0c;find_last_of 10&#xff0c;operator 11&#xff0c;ge…

深入理解对象与垃圾回收机制

1、虚拟机中对象创建过程 1.1 对象创建过程 当我们使用 new 创建一个对象时&#xff0c;在 JVM 中进行了如下操作&#xff1a; 类加载&#xff1a;把 class 加载到 JVM 运行时数据区的过程。可以通过本地文件的形式&#xff0c;也可以通过网络加载。 检查加载&#xff1a;首…

【23真题】大题全原题的211!题源已定位!

今天分享的是23年长安大学814的信号与系统试题及解析。 本套试卷难度分析&#xff1a;22年长安大学814考研真题&#xff0c;我也发布过&#xff0c;若有需要&#xff0c;戳这里自取&#xff01;本套试题难度中等偏下&#xff0c;题量偏多&#xff0c;考察的知识点也是很常见的…

Robot Framework自动化测试(四)--- 分层思想

&#x1f4e2;专注于分享软件测试干货内容&#xff0c;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01;&#x1f4e2;交流讨论&#xff1a;欢迎加入我们一起学习&#xff01;&#x1f4e2;资源分享&#xff1a;耗时200小时精选的「软件测试」资…

Chatbot开发三剑客:LLAMA、LangChain和Python

聊天机器人&#xff08;Chatbot&#xff09;开发是一项充满挑战的复杂任务&#xff0c;需要综合运用多种技术和工具。在这一领域中&#xff0c;LLAMA、LangChain和Python的联合形成了一个强大的组合&#xff0c;为Chatbot的设计和实现提供了卓越支持。 首先&#xff0c;LLAMA是…

如何往excel中写子表?

with pd.ExcelWriter("C:/last_date.xlsx") as writer:for i in range(0, 10):df pd.DataFrame()df.to_excel(writer, indexFalse, sheet_namestr(days[i 1]))