热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

springboot简单接入websocket

原标题:springboot简单接入websocket序最近一个项目又重启了,之前支付了要手动点击已付款,所以这次想把这个不友好体验干掉。另外以后的扫码登录什么的都需要这

原标题:springboot简单接入websocket


最近一个项目又重启了,之前支付了要手动点击已付款,所以这次想把这个不友好体验干掉。另外以后的扫码登录什么的都需要这个服务支持。之前扫码登录这块用的mqtt,时间上是直接把mqtt的连接信息返回给前端。前端连接mqtt服务,消费信息。这次不想这样弄了,准备接入websocket。
一、环境说明
我这里是springBoot2.4.5 + springCloud2020.1.2,这里先从springBoot对接开始,逐步再增加深度,不过可能时间不够,就简单接入能满足现在业务场景就stop。没办法,从入职就开始的一个项目到现在,要死不活的,没有客户就不投入,有客户就催命,真不知道还能坚持多久。。。。。。
二、引包

<!-- websocket支持 --&www.yii666.comgt;
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

现在springboot对接websocket就值需要这么简单的一个包了。
三、配置类


import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
/**
* websocket配置类
*
* @author zhengwen
**/

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

就这一个,里面的bean是用来扫描Endpoint注解的类的。
配置文件都没什么好说的,简单对接用不上,也不用什么调优。
四、websocketServer


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax文章来源站点https://www.yii666.com/.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author zhengwen
**/

@Slf4j
@Component
@ServerEndpoint("/wsPushMessage/{wsUserId}")
public class MyWebSocketSever {
/**
* 静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
*/

private static int onlineCount = 0;
/**
* concurrent包的线程安全Set,用来存放每个客户端对应的WebSocket对象。
*/

private static ConcurrentHashMap<String, MyWebSocketSever> webSocketMap = new ConcurrentHashMap<>();
/**
* 与某个客户端的连接会话,需要通过它来给客户端发送数据
*/

private Session session;
/**
* 接收wsUserId
*/

private String wsUserId = "";
/**
* 连接建立成
* 功调用的方法
*/

@OnOpen
public void onOpen(Session session, @PathParam("wsUserId") String userId) {
this.session = session;
this.wsUserId = userId;
if (webSocketMap.containsKey(userId)) {
webSocketMap.remove(userId);
//加入set中
webSocketMap.put(userId, this);
} else {
//加入set中
webSocketMap.put(userId, this);
//在线数加1
addOnlineCount();
}
log.info("用户连接:" + userId + ",当前在线人数为:" + getOnlineCount());
文章来源地址41561.html sendMessage("连接成功");
}
/**
* 连接关闭
* 调用的方法
*/

@OnClose
public void onClose() {
if (webSocketMap.containsKey(wsUserId)) {
webSocketMap.remove(wsUserId);
//从set中删除
subOnlineCount();
}
log.info("用户退出:" + wsUserId + ",当前在线人数为:" + getOnlineCount());
}
/**
* 收到客户端消
* 息后调用的方法
*
* @param message 客户端发送过来的消息
**/

@OnMessage
public void onMessage(String message, Session session) {
log.info("用户消息:" + wsUserId + ",报文:" + message);
//可以群发消息
//消息保存到数据库、redis
if (StringUtils.isNotBlank(message)) {
try {
//解析发送的报文
JSONObject jsonObject = JSON.parseObject(message);
//追加发送人(防止串改)
jsonObject.put("fromUserId", this.wsUserId);
String toUserId = jsonObject.getString("toUserId");
//传送给对应toUserId用户的websocket
if (StringUtils.isNotBlank(toUserId) && webSocketMap.containsKey(toUserId)) {
webSocketMap.get(toUserId).sendMessage(message);
} else {
//否则不在这个服务器上,发送到mysql或者redis
log.error("请求的userId:" + toUserId + "不在该服务器上");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
文章来源地址41561.html * @param session
* @param error
*/

@OnError
public void onError(Session session, Throwable error) {
log.error("用户错误:" + this.wsUserId + ",原因:" + error.getMessage());
error.printStackTrace();
}
}

核心方法就这么几个,这里面的细节可以自行根据业务场景处理,比如给信息增加一个类型,然后搞个公用方法,根据信息类型走不同业务逻辑,存库等等都可以的。
五、前端测试js

<www.yii666.com;!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>websocket通讯</title>
</head>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
<script>
let socket;
function openSocket() {
const socketUrl = "ws://localhost:8810/wsPushMessage/" + $("#userId").val();
console.log(socketUrl);
if(socket!=null){
socket.close();
socket=null;
}
socket = new WebSocket(socketUrl);
//打开事件
socket.onopen = function() {
console.log("websocket已打开");
};
//获得消息事件
socket.onmessage = function(msg) {
console.log(msg.data);
//发现消息进入,开始处理前端触发逻辑
};
//关闭事件
socket.onclose = function() {
console.log("websocket已关闭");
};
//发生了错误事件
socket.onerror = function() {
console.log("websocket发生了错误");
}
}
function sendMessage() {
socket.send('{"toUserId":"'+$("#toUserId").val()+'","contentText":"'+$("#contentText").val()+'"}');
console.log('{"toUserId":"'+$("#toUserId").val()+'","contentText":"'+$("#contentText").val()+'"}');
}
function closeSocket(){
socket.close();
}
</script>
<body>
<p>【socket开启者的ID信息】:<div><input id="userId" name="userId" type="text" value="10"></div>
<p>【客户端向服务器发送的内容】:<div><input id="toUserId" name="toUserId" type="text" value="20">
<input id="contentText" name="contentText" type="text" value="hello websocket"></div>
<p>【开启连接】:<div><a onclick="openSocket()">开启socket</a></div>
<p>【发送信息】:<div><a onclick="sendMessage()">发送消息</a></div>
<p>【关闭连接】:<div><a onclick="closeSocket()">关闭socket</a></div>
</body>
</html>

六、测试效果
在这里插入图片描述
到此就结束了,基本上就是这么简单,我这边发送,另一个网页上能收到,而且发送的信息都经过了websocket服务,里面可以做差异化处理哦。要存储发送记录,记录是否消费,后面再通过自动任务扫描这种未被消费(发送失败)的信息,等用户上线再次发送,实现推送信息等等。

来源于:springboot简单接入websocket


推荐阅读
  • Spring学习(4):Spring管理对象之间的关联关系
    本文是关于Spring学习的第四篇文章,讲述了Spring框架中管理对象之间的关联关系。文章介绍了MessageService类和MessagePrinter类的实现,并解释了它们之间的关联关系。通过学习本文,读者可以了解Spring框架中对象之间的关联关系的概念和实现方式。 ... [详细]
  • 在重复造轮子的情况下用ProxyServlet反向代理来减少工作量
    像不少公司内部不同团队都会自己研发自己工具产品,当各个产品逐渐成熟,到达了一定的发展瓶颈,同时每个产品都有着自己的入口,用户 ... [详细]
  • Vue3中setup函数的参数props和context配置详解
    本文详细介绍了Vue3中setup函数的参数props和context的配置方法,包括props的接收和配置声明,以及未通过props进行接收配置时的输出值。同时还介绍了父组件传递给子组件的值和模板的相关内容。阅读本文后,读者将对Vue3中setup函数的参数props和context的配置有更深入的理解。 ... [详细]
  • Spring源码解密之默认标签的解析方式分析
    本文分析了Spring源码解密中默认标签的解析方式。通过对命名空间的判断,区分默认命名空间和自定义命名空间,并采用不同的解析方式。其中,bean标签的解析最为复杂和重要。 ... [详细]
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • Voicewo在线语音识别转换jQuery插件的特点和示例
    本文介绍了一款名为Voicewo的在线语音识别转换jQuery插件,该插件具有快速、架构、风格、扩展和兼容等特点,适合在互联网应用中使用。同时还提供了一个快速示例供开发人员参考。 ... [详细]
  • 本文介绍了计算机网络的定义和通信流程,包括客户端编译文件、二进制转换、三层路由设备等。同时,还介绍了计算机网络中常用的关键词,如MAC地址和IP地址。 ... [详细]
  • 利用Visual Basic开发SAP接口程序初探的方法与原理
    本文介绍了利用Visual Basic开发SAP接口程序的方法与原理,以及SAP R/3系统的特点和二次开发平台ABAP的使用。通过程序接口自动读取SAP R/3的数据表或视图,在外部进行处理和利用水晶报表等工具生成符合中国人习惯的报表样式。具体介绍了RFC调用的原理和模型,并强调本文主要不讨论SAP R/3函数的开发,而是针对使用SAP的公司的非ABAP开发人员提供了初步的接口程序开发指导。 ... [详细]
  • ASP.NET2.0数据教程之十四:使用FormView的模板
    本文介绍了在ASP.NET 2.0中使用FormView控件来实现自定义的显示外观,与GridView和DetailsView不同,FormView使用模板来呈现,可以实现不规则的外观呈现。同时还介绍了TemplateField的用法和FormView与DetailsView的区别。 ... [详细]
  • 本文介绍了如何使用C#制作Java+Mysql+Tomcat环境安装程序,实现一键式安装。通过将JDK、Mysql、Tomcat三者制作成一个安装包,解决了客户在安装软件时的复杂配置和繁琐问题,便于管理软件版本和系统集成。具体步骤包括配置JDK环境变量和安装Mysql服务,其中使用了MySQL Server 5.5社区版和my.ini文件。安装方法为通过命令行将目录转到mysql的bin目录下,执行mysqld --install MySQL5命令。 ... [详细]
  • 本文介绍了在wepy中运用小顺序页面受权的计划,包含了用户点击作废后的从新受权计划。 ... [详细]
  • uniapp开发H5解决跨域问题的两种代理方法
    本文介绍了uniapp开发H5解决跨域问题的两种代理方法,分别是在manifest.json文件和vue.config.js文件中设置代理。通过设置代理根域名和配置路径别名,可以实现H5页面的跨域访问。同时还介绍了如何开启内网穿透,让外网的人可以访问到本地调试的H5页面。 ... [详细]
  • 分享css中提升优先级属性!important的用法总结
    web前端|css教程css!importantweb前端-css教程本文分享css中提升优先级属性!important的用法总结微信门店展示源码,vscode如何管理站点,ubu ... [详细]
  • 一次上线事故,30岁+的程序员踩坑经验之谈
    本文主要介绍了一位30岁+的程序员在一次上线事故中踩坑的经验之谈。文章提到了在双十一活动期间,作为一个在线医疗项目,他们进行了优惠折扣活动的升级改造。然而,在上线前的最后一天,由于大量数据请求,导致部分接口出现问题。作者通过部署两台opentsdb来解决问题,但读数据的opentsdb仍然经常假死。作者只能查询最近24小时的数据。这次事故给他带来了很多教训和经验。 ... [详细]
  • 开发笔记:spring boot项目打成war包部署到服务器的步骤与注意事项
    本文介绍了将spring boot项目打成war包并部署到服务器的步骤与注意事项。通过本文的学习,读者可以了解到如何将spring boot项目打包成war包,并成功地部署到服务器上。 ... [详细]
author-avatar
mobiledu2502859427
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有