springboot+websocket+微信小程序实现评论区功能

springboot+websocket+微信小程序实现评论区功能

    • WebSocket
    • STOMP协议
    • 具体实现
      • 1.在pom文件中添加Spring WebSocket依赖
      • 2. 创建WebSocket配置类
      • 3.接收发送消息
      • 4.前端
    • 参考

WebSocket

1. 什么是WebSocket?

WebSocket 是 HTML5 一种新的协议。它实现了浏览器与服务器全双工通信,能更好的节省服务器资源和带宽并达到实时通讯,它建立在 TCP 之上,同 HTTP 一样通过 TCP 来传输数据,但是它和 HTTP 最大不同是:
WebSocket 是一种双向通信协议,在建立连接后,WebSocket 服务器和 Browser/Client Agent 都能主动的向对方发送或接收数据,就像 Socket 一样;
WebSocket 需要类似 TCP 的客户端和服务器端通过握手连接,连接成功后才能相互通信。

2. WebSocket的特点

  • 全双工通信:WebSocket协议支持服务器和客户端之间的全双工通信,客户端和服务器可以同时发送消息。
  • 持久连接:WebSocket连接一旦建立,将持续保持打开状态,直到客户端或服务器关闭连接。
  • 跨域通信:WebSocket协议支持跨域通信,允许不同域的服务器与客户端建立连接。

STOMP协议

STOMP协议相当于Websocket的子协议。

STOMP 中文为: 面向消息的简单文本协议

websocket定义了两种传输信息类型:文本信息和二进制信息。类型虽然被确定,但是他们的传输体是没有规定的。所以,需要用一种简单的文本传输类型来规定传输内容,它可以作为通讯中的文本传输协议。

STOMP是基于帧的协议,客户端和服务器使用STOMP帧流通讯

一个STOMP客户端是一个可以以两种模式运行的用户代理,可能是同时运行两种模式。

作为生产者,通过SEND框架将消息发送给服务器的某个服务
作为消费者,通过SUBSCRIBE制定一个目标服务,通过MESSAGE框架,从服务器接收消息。
例如:

COMMAND
header1:value1
header2:value2Body^@

注:帧以commnand字符串开始,以EOL结束。其中包括可选回车符(13字节),紧接着是换行符(10字节)。command下面是0个或多个:格式的header条目, 每个条目由EOL结束。一个空白行(即额外EOL)表示header结束和body开始。body连接着NULL字节。本文档中的例子将使用^@代表NULL字节。NULL字节可以选择跟多个EOLs。欲了解更多关于STOMP帧的详细信息,请参阅STOMP1.2协议规范。

具体实现

微信小程序提供的关于WebSocket的API不是基于STOMP协议的,只能用websocket实现,当然可以对微信小程序的前端进行更改,使其可以使用基于STOMP协议的后端实现。

基于STOMP协议的websocket实现可以参考:Java实战:Spring Boot实现WebSocket实时通信

1.在pom文件中添加Spring WebSocket依赖

<dependencies><!-- Spring Boot Web依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- Spring Boot WebSocket依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency>
</dependencies>

2. 创建WebSocket配置类

package com.lixy.sharingcurriculum.config;import com.lixy.sharingcurriculum.controller.CommentController;
import com.lixy.sharingcurriculum.service.CommentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {/*使用springboot内置tomcat需要该bean,打war包则注释掉该bean*/@Beanpublic ServerEndpointExporter serverEndpoint() {return new ServerEndpointExporter();}@Overridepublic void registerStompEndpoints(StompEndpointRegistry registry) {//注册一个WebSocket端点,路径为"/ws"//registry.addEndpoint("/ws").withSockJS();//客户端调用的URL;registry.addEndpoint("/ws").setAllowedOrigins("*");}//因为websocket中不能直接使用@Autowired注入Service,添加下面配置 在socket引入Service@Autowiredpublic void socketUserService(CommentService commentService){CommentController.commentService = commentService;}
}
  • 创建一个WebSocket的配置类WebSocketConfig 实现WebSocketMessageBrokerConfigurer 接口,需要手动注入ServerEndpointExporter,这个bean会自动注册使用了@ServerEndpoint注解声明的Websocket endpoint。
    我的理解是为了将WebSocket与Spring容器整合,通过在配置类中添加@Bean,使其返回对象ServerEndpointExporter,意味着将该对象纳入spring框架的管理中,spring容器将能够处理WebSocket相关的配置和依赖。

  • registry.addEndpoint("/ws").setAllowedOrigins("*");意思是允许/ws/*的所有请求访问。websocket默认禁止了非同源访问 ,如果没有加入自己的跨域配置或这个配置的话,前端将会报403错误。参考:客户端连接spring websocket 返回403错误

  • 因为我需要同时对数据库进行修改,所以引入了commentService进行数据相关操作。

同源访问指的是WebSocket连接的客户端和服务器端拥有相同的协议、主机和端口

在Web开发中,同源策略是一种安全机制,它要求前端的网页脚本只能与同源的服务器进行交互。具体来说,同源访问要求客户端的页面和服务器端的服务必须使用相同的协议(如HTTP或HTTPS)、相同的主机名(如www.example.com)以及相同的端口号(如80或443)。如果这些条件中有任何一个不匹配,那么就是非同源访问

对于WebSocket而言,虽然它本身并不强制执行同源策略,但浏览器的安全限制通常要求WebSocket遵循同源策略。这意味着默认情况下,一个网页中的WebSocket脚本只能连接到与其同源的服务器。如果需要连接到不同源的服务器,可以使用CORS(跨域资源共享)来允许这种跨域访问。

总结来说,同源访问是WebSocket通信的一种默认安全限制,它要求客户端和服务器在协议、主机和端口上保持一致。如果需要进行非同源访问,开发者需要在服务器端配置相应的CORS策略,以允许跨域的WebSocket连接。

3.接收发送消息

webSocket接收和发送的消息的类型只能是String类型,所以在传数据的时候需要做相应的处理。

package com.lixy.sharingcurriculum.controller;import com.alibaba.fastjson.JSON;
import com.lixy.sharingcurriculum.entity.Message;
import com.lixy.sharingcurriculum.entity.dto.MessDto;
import com.lixy.sharingcurriculum.service.CommentService;
import jakarta.websocket.*;
import jakarta.websocket.server.PathParam;
import jakarta.websocket.server.ServerEndpoint;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;@Component
@ServerEndpoint("/ws/{courid}/{userid}")
@Slf4j
public class CommentController {//存储被课程id和正在讨论区中的用户id和对应会话public static final Map<String, Map<String, Session>> sessionMap = new ConcurrentHashMap<>();public static CommentService commentService;/**** 建立连接时调用* 1.第一层map存储被课程id和浏览的用户及会话* 2.第二层map存储用户id及会话*/@OnOpenpublic void onOpen(Session session, @PathParam("courid") String courid,@PathParam("userid") String userid){log.info("用户{}打开了课程{}的讨论区",userid,courid);if(sessionMap.containsKey(courid)){sessionMap.get(courid).put(userid,session);}else {Map<String,Session> map = new HashMap<>();map.put(userid,session);sessionMap.put(courid,map);}log.info(String.valueOf(sessionMap));}/*** 接收处理客户端发来的数据*/@OnMessagepublic void onMessage(String message) {
//        解析消息为java对象Message msg = JSON.parseObject(message, Message.class);log.info("msg:"+msg);if(msg != null&& msg.getContent() != null &&!msg.getContent().isEmpty()){//将评论内容存入数据库MessDto messDto=commentService.saveComment(msg);//将评论内容发送给其他正在浏览该文章的用户sendAllMessage(messDto);}else{System.out.println("评论内容为空");}}//服务端发送消息给客户端private void sendAllMessage(Message message) {log.info("sendAllMessage:{}",message);try {String courid = message.getCourid();log.info("courid:{}",courid);//根据评论发送课程的id,将该评论发送给正在讨论区中的用户Map<String,Session> passageMap = sessionMap.get(courid);for (Session session : passageMap.values()) {session.getBasicRemote().sendText(JSON.toJSONString(message));}} catch (Exception e) {e.printStackTrace();}}//关闭连接/*** 1.把登出的用户从sessionMap中剃除* 2.发送给所有人当前登录人员信息*/@OnClosepublic void onClose(@PathParam("courid") String courid,@PathParam("userid") String userid) {//用户退出讨论区,则将该用户及其会话移除Map<String,Session> passageMap = sessionMap.get(courid);passageMap.remove(userid);//没有用户在讨论区中,则将课程id从map中移除if(passageMap.isEmpty()){sessionMap.remove(courid);}}@OnErrorpublic void onError(Session session, Throwable error) {System.out.println("发生错误");error.printStackTrace();}}

4.前端

//创建WebSocket连接createWebSocket(){const websocket =wx.connectSocket({url: 'ws://localhost:8080/ws/'+this.data.courid+"/"+this.data.userid,success: () => {console.log('WebSocket连接成功');},fail: (error) => {console.log('WebSocket连接失败', error);}})// 监听WebSocket连接打开事件websocket.onOpen(() => {console.log('WebSocket连接已打开');console.log('readyState:', websocket.readyState); // 应该输出: OPEN (1) });// 监听WebSocket接收到服务器消息事件websocket.onMessage((message) => {console.log('收到服务器消息', message);// 处理服务器返回的消息,例如更新页面数据等操作var comment=JSON.parse(message.data)comment.createtime=this.timestampToDate(comment.createtime)var comment_list=this.data.comment_list;comment_list.push(comment)this.setData({comment_list})});// 监听WebSocket连接关闭事件websocket.onClose(() => {console.log('WebSocket连接已关闭');});// 监听WebSocket错误事件websocket.onError((error) => {console.log('WebSocket发生错误', error);});// 将WebSocket对象保存到data中this.setData({websocket: websocket,});},// 发送消息到WebSocket服务器if (this.data.websocket && this.data.websocket.readyState === 1) {this.data.websocket.send({data: JSON.stringify(message), // 要发送的消息内容success: () => {console.log('消息发送成功');},fail: (error) => {console.log('消息发送失败', error);},});} else {console.log('WebSocket连接未打开或不存在');}

参考

Java实战:Spring Boot实现WebSocket实时通信
WebSocket和Stomp协议
个人博客——使用websocket实现评论实时展示
客户端连接spring websocket 返回403错误
微信小程序 内容评论-回复评论-回复回复的实现

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

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

相关文章

深入浅出 -- 系统架构之性能优化的核心思维

“在当前的互联网开发模式下&#xff0c;系统访问量日涨、并发暴增、线上瓶颈等各种性能问题纷涌而至&#xff0c;性能优化成为了现时代开发过程中炙手可热的名词&#xff0c;无论是在开发、面试过程中&#xff0c;性能优化都是一个常谈常新的话题”。Java语言作为企业应用中的…

ArcGIS Server 安装教程

​​​​​​​ 一、环境与文件准备 1.软件环境 已安装arcgis Desktop 10.2 2.安装及授权文件 二、安装步骤 1.下载安装包和授权文件&#xff0c;解压后打开ArcGIS Server10.2文件夹&#xff0c;打开ESRI.exe。 2.点击ArcGIS for Server后的Setup&#xff0c;开始安装。 3.…

labelme安装和使用

源码地址&#xff1a; git clone https://github.com/labelmeai/labelme.git 描述 是一个图形图像注释工具,灵感来自 http://labelme.csail.mit.edu . 它是用比顿编写的,并使用QT进行图形化接口。 实例分割的VOC数据集示例。 其他例子(语义分割、B箱检测和分类)。 各种原语(多…

Flutter 使用flutter_swiper_null_safety 实现轮播图

目录 引入flutter_swiper_null_safety 在pubspec.yaml文件中dependencies下添加以下依赖 然后执行命令进行下载 实现轮播图 引入flutter_swiper_null_safety 在pubspec.yaml文件中dependencies下添加以下依赖 flutter_swiper_null_safety: ^1.0.2 然后执行命令进行下载 flu…

manga-ocr漫画日文ocr

github 下载 解压 anaconda新建环境 conda create -n manga_ocr python3.8 激活环境 conda activate manga_ocr cd到解压目录 cd /d manga-ocr-master 安装依赖包 pip install -r requirements.txt pip3 install manga-ocr 下载离线model huggingface 123云盘 解压到一个目录…

宏集PLC如何为楼宇自动化行业提供空调、供暖与通风的解决方案?

一、应用背景 楼宇自动化行业是通过将先进的技术和系统应用于建筑物中&#xff0c;以提高其运营效率、舒适度和能源利用效率的行业&#xff0c;其目标是使建筑物能够自动监控、调节和控制各种设备和系统&#xff0c;包括照明系统、空调系统、安全系统、通风系统、电力供应系统…

rsync 远程同步 基础介绍

目录 一 Rsync 简介 1&#xff0c;rsync 是什么 2&#xff0c;rsync 中的发起端 同步源 3&#xff0c;同步方式 4&#xff0c;备份的方式 5&#xff0c;常用Rsync命令 6&#xff0c; 配置源的两种表达方法 7&#xff0c;rsync做本地复制时与cp 对比 二&#xff…

【4036】基于小程序+ssm实现的软件学院会议室管理系统

作者主页&#xff1a;Java码库 主营内容&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app等设计与开发。 收藏点赞不迷路 关注作者有好处 文末获取源码 技术选型 【后端】&#xff1a;Java 【框架】&#xff1a;ssm 【…

Vue中的键盘事件

目 录 1. 概述 2. JavaScript 键盘事件 2.1 键盘事件类型 2.1.1 keydown 事件2.1.2 keypress 事件2.1.3 keyup 事件2.1.4 input 事件 2.2 键盘事件的响应顺序 3. Vue 键盘事件监听与处理 3.1 获取按键的 键码&#xff08;keyCode&#xff09;3.2 监听按键事件 4. Vue 按键…

java理论小作业(2)--类

第一题 1.题目&#xff1a; 2.解析&#xff1a; 首先&#xff0c;我们来分析Hello1类的结构和给定代码的执行流程&#xff1a; Hello1类中有两个成员变量&#xff0c;一个静态的a和一个非静态的b。静态变量a属于类本身&#xff0c;而非静态变量b属于类的每一个实例&#xff…

开启Java之旅——用Java实现简易的图书管理系统(24.4.7)

图书管理系统 一、设计思路 1、首先需要区分两类人&#xff0c;图书管理员和借书用户&#xff0c;不同的用户要展现不同的界面&#xff0c;利用继承和多态可以将其实现。 2、要将不同的操作封装起来&#xff0c;单独设计成为一个类&#xff0c;为了规范实现&#xff0c;需要…

gcc/g++:预编译阶段取消宏定义

预编译阶段取消宏定义&#xff0c;可分为两种情况&#xff1a;1&#xff09;内部取消&#xff0c;2&#xff09;外部取消。 示例&#xff1a; 1&#xff09;用户程序 /*brief test demo-for-precompile-to-undef? show you hereauthor wenxuanpeiemail 15873152445163.com(q…

synchronized-锁优化

自旋锁 自旋锁是一种基于忙等待的同步机制&#xff0c;用于保护临界区代码的并发访问。与互斥锁相比&#xff0c;自旋锁尝试通过忙等待来避免线程的切换和阻塞&#xff0c;从而减少开销。 自旋锁的定义&#xff1a;自旋锁是一种基于忙等待的同步机制&#xff0c;在线程无法获…

蓝桥杯 第 9 场 小白入门赛 字符迁移

题目&#xff1a; 3.字符迁移【算法赛】 - 蓝桥云课 (lanqiao.cn) 思路&#xff1a; 此题通过把小写字母映射成数字&#xff0c;进行差分即可。 AC代码&#xff1a; #include<iostream> #include<cstring> #include<algorithm>using namespace std;typed…

LeetCode-33. 搜索旋转排序数组【数组 二分查找】

LeetCode-33. 搜索旋转排序数组【数组 二分查找】 题目描述&#xff1a;解题思路一&#xff1a;二分查找。1.找哨兵节点&#xff08;nums[0]或nums[-1]&#xff09;可以确定nums[mid]位于前一段或后一段有序数组中。2. 就是边界left和right的变换&#xff0c;具体看代码。解题思…

基于SpringBoot的“民宿管理平台系统”的设计与实现(源码+数据库+文档+PPT)

基于SpringBoot的“民宿管理平台系统”的设计与实现&#xff08;源码数据库文档PPT) 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBoot 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 用户首页界面图 民宿信息管理界面图 房间预订…

IFC文件分析工具Top 5

分析行业基础类 (IFC) 文件是确保建筑信息模型 (BIM) 数据准确性和一致性的关键步骤。 在验证这些文件期间需要考虑各个方面&#xff0c;以避免错误并确保项目的最佳运行。 在本文中&#xff0c;我们将介绍验证 IFC 文件的五种有效方法&#xff0c;帮助你对 IFC 文件的质量充…

python开发poc2,爆破脚本

#本课知识点和目的&#xff1a; ---协议模块使用&#xff0c;Request 爬虫技术&#xff0c;简易多线程技术&#xff0c;编码技术&#xff0c;Bypass 后门技术 下载ftp服务器模拟器 https://lcba.lanzouy.com/iAMePxl378h 随便创建一个账户&#xff0c;然后登录进去把ip改成…

AI大模型下的策略模式与模板方法模式对比解析

​&#x1f308; 个人主页&#xff1a;danci_ &#x1f525; 系列专栏&#xff1a;《设计模式》《MYSQL应用》 &#x1f4aa;&#x1f3fb; 制定明确可量化的目标&#xff0c;坚持默默的做事。 &#x1f680; 转载自热榜文章&#xff1a;设计模式深度解析&#xff1a;AI大模型下…

3D目标检测跟踪 | 基于kitti+waymo数据集的自动驾驶场景的3D目标检测+跟踪渲染可视化

项目应用场景 面向自动驾驶场景的 3D 目标检测目标跟踪&#xff0c;基于kittiwaymo数据集的自动驾驶场景的3D目标检测跟踪渲染可视化查看。 项目效果 项目细节 > 具体参见项目 README.md (1) Kitti detection 数据集结构 # For Kitti Detection Dataset └── k…