位置: IT常识 - 正文

Java使用WebStocket实现前后端互发消息(java使用循环结构输出九九乘法表)

编辑:rootadmin
Java使用WebStocket实现前后端互发消息

推荐整理分享Java使用WebStocket实现前后端互发消息(java使用循环结构输出九九乘法表),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:java使用循环结构输出九九乘法表,java使用while循环对n以内的偶数求和,java使用while循环对n以内的偶数求和,java使用for循环作等腰三角形,java使用正则表达式替换,java使用指定版本的jar包,java使用递归的方法求n!,java使用正则表达式替换,内容如对您有帮助,希望把文章链接给更多的朋友!

记录一下自己使用WebStocket实现服务器主动发消息的过程和踩得雷。

需求:车牌识别系统识别到车牌后,持续向前端推送车牌信息,直到前端回复收到。

测试需求:新增 客户后,持续向前端推送客户信息,直到前端收到消息,并且回复收到。

1.引入WebStocket的依赖<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId><version>2.7.0</version></dependency>

2.创建配置类 WebScoketConfig

import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.web.socket.server.standard.ServerEndpointExporter;/** * 开启WebSocket支持 */@Configurationpublic class WebSocketConfig { @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); }}

新增客户的业务层

  这里实现了新增 客户后,持续向前端推送客户信息。

  实现思路:本来是打算 让前端接收到客户信息,回复后端的时候,后端修改数据库中此条客户的 接收状态的字段,然后每次后端往前端发送消息的时候都去数据库查询一次 客户信息的接收状态,如果已经接收到了就不往前端推送。但是好像会造成一边读数据库,一边修改数据库,会出现脏读的问题,而且我在 WebScoketConfigServer 中并不能创建Service层的对象,总是报空指针。

  最后,决定使用 static修饰的静态变量来实现对前端是否接受到消息和是否发送的是同一条重复的消息进行判断。然后根据返回的结果决定是否继续往前端推送消息。

import io.recycle.modules.rest.api.dto.system.CustomerDto;import io.recycle.modules.rest.api.dto.system.CustomerQueryDto;import io.recycle.modules.rest.api.dto.weigh.CardDto;import io.recycle.modules.rest.api.dto.weigh.CustomerParam;import io.recycle.modules.rest.api.dto.weigh.CustomerWeighDto;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import java.util.List;import java.util.Map;import io.recycle.modules.rest.api.dao.RecycleCustomerDao;import io.recycle.modules.rest.api.entity.RecycleCustomerEntity;import io.recycle.modules.rest.api.service.RecycleCustomerService;@Service("recycleCustomerService")public class RecycleCustomerServiceImpl implements RecycleCustomerService{private static int count=0;@Autowiredprivate NoticeWebsocket noticeWebsocket;@Autowiredprivate RecycleCustomerDao recycleCustomerDao;@Overridepublic void save(RecycleCustomerEntity recycleCustomer){recycleCustomerDao.save(recycleCustomer);//测试webstocket,实现新增客户往前端推送消息,直到前端回复////测试webstocketboolean flag = false;do{try {Thread.sleep(300); //休息300毫秒} catch (InterruptedException e) {e.printStackTrace();System.out.println("休息时出错000000");}//往前端发送消息System.out.println("count===="+count);boolean resultFlag = noticeWebsocket.sendMessage("新增了用户:" + recycleCustomer.toString(),count);flag = resultFlag;if (resultFlag){System.out.println("停止往前端发送数据,因为 resultFlag 为: "+resultFlag+"==说明前端已接收的消息");}else {System.out.println("往前端发送数据,因为 resultFlag 为: "+resultFlag+"==说明前端还没接收到消息");}}while ( !flag );System.out.println("停止往前端发送数据,因为 delFlag 为: "+flag);count = count +1;}}

3.创建WebScoketConfigServer

在websocket协议下,后端服务器相当于ws里的客户端,需要用@ServerEndpoint指定访问的路径,并使用@Component注入容器。

这里实现了新增 客户后,持续向前端推送客户信息,直到前端收到消息,并且回复收到。

Java使用WebStocket实现前后端互发消息(java使用循环结构输出九九乘法表)

实现思路:

import com.alibaba.fastjson.JSONObject;import io.recycle.modules.rest.api.dao.RecycleCustomerDao;import io.recycle.modules.rest.api.dto.websocket.NoticeWebsocketResp;import io.recycle.modules.rest.api.entity.RecycleCustomerEntity;import lombok.extern.slf4j.Slf4j;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import org.springframework.util.StringUtils;import javax.websocket.*;import javax.websocket.server.PathParam;import javax.websocket.server.ServerEndpoint;import java.io.IOException;import java.util.*;import java.util.concurrent.ConcurrentHashMap;/** * @ServerEndpoint 注解是一个类层次的注解,它的功能主要是将目前的类定义成一个websocket服务器端, * 注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端 */@ServerEndpoint("/chepaisend")@Component@Slf4jpublic class NoticeWebsocket { //记录连接的客户端 public static Map<String, Session> clients = new ConcurrentHashMap<>(); /** * userId关联sid(解决同一用户id,在多个web端连接的问题) */ public static Map<String, Set<String>> conns = new ConcurrentHashMap<>(); private String sid = null; //一些记录发送消息状态 private static int initFlag =0; private static int tempFlag =0; //区分新旧消息的变量 private static int sum=0; /** * 连接成功后调用的方法 * @param session * */ @OnOpen public void onOpen(Session session) { this.sid = UUID.randomUUID().toString(); clients.put(this.sid, session); log.info(this.sid + "连接开启!"); } /** * 连接关闭调用的方法 */ @OnClose public void onClose() { log.info(this.sid + "连接断开!"); clients.remove(this.sid); } /** * 判断是否连接的方法 * @return */ public static boolean isServerClose() { if (NoticeWebsocket.clients.values().size() == 0) { log.info("已断开"); return true; }else { log.info("已连接"); return false; } } /** * 发送给所有用户 * @param noticeType */ public static boolean sendMessage(String noticeType,int count){ //判断是否是新的新增客户 System.out.println("count= "+count+",sum= "+sum+",initFlag= "+initFlag+",tempFlag= "+tempFlag); if (sum != count){ NoticeWebsocketResp noticeWebsocketResp = new NoticeWebsocketResp(); noticeWebsocketResp.setNoticeType(noticeType); sendMessage(noticeWebsocketResp); sum = count; } //判断前端是否 回复了 收到消息 相等没收到,不相等 收到 if (initFlag==tempFlag){ NoticeWebsocketResp noticeWebsocketResp = new NoticeWebsocketResp(); noticeWebsocketResp.setNoticeType(noticeType); sendMessage(noticeWebsocketResp); }else { //收到消息了,别发同一个消息了 tempFlag = initFlag; return true; } tempFlag = initFlag; //没收到消息继续发 return false; } /** * 发送给所有用户 * @param noticeWebsocketResp */ public static void sendMessage(NoticeWebsocketResp noticeWebsocketResp){ String message = JSONObject.toJSONString(noticeWebsocketResp); for (Session session1 : NoticeWebsocket.clients.values()) { try { session1.getBasicRemote().sendText(message); } catch (IOException e) { e.printStackTrace(); } } } /** * 根据用户id发送给某一个用户 * **/ public static void sendMessageByUserId(String userId, NoticeWebsocketResp noticeWebsocketResp) { if (!StringUtils.isEmpty(userId)) { String message = JSONObject.toJSONString(noticeWebsocketResp); Set<String> clientSet = conns.get(userId); if (clientSet != null) { Iterator<String> iterator = clientSet.iterator(); while (iterator.hasNext()) { String sid = iterator.next(); Session session = clients.get(sid); if (session != null) { try { session.getBasicRemote().sendText(message); } catch (IOException e) { e.printStackTrace(); } } } } } } /** * 收到客户端消息后调用的方法 * @param message * @param session */ @OnMessage public void onMessage(String message, Session session) { log.info("收到来自窗口"+"的信息:"+message); if ("已接收到消息".equals(message)){ //收到消息,改变flag的值 System.out.println("前端已经收到消息,开始改变 initFlag的值,此时initFlag= "+initFlag); initFlag = initFlag +1; System.out.println("前端已经收到消息,已经改变 initFlag的值,此时initFlag== "+initFlag); } } /** * 发生错误时的回调函数 * @param error */ @OnError public void onError(Throwable error) { log.info("错误"); error.printStackTrace(); }}

封装的发送消息的对象

import io.swagger.annotations.ApiModel;import io.swagger.annotations.ApiModelProperty;import lombok.Data;@Data@ApiModel("ws通知返回对象")public class NoticeWebsocketResp<T> { @ApiModelProperty(value = "通知类型") private String noticeType; @ApiModelProperty(value = "通知内容") private T noticeInfo;}

4.WebSocket调用

用户端调用此接口,主动将消息发送给后端,后端接收到消息后再主动推送给指定/全部用户,可以实现消息的私聊和群发功能。

import io.recycle.common.utils.R;import io.recycle.modules.rest.api.service.impl.NoticeWebsocket;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;@RestController@RequestMapping("/order")public class OrderController {@GetMapping("/test") public R test() { NoticeWebsocket.sendMessage("你好,WebSocket",1); return R.ok(); }}

前端WebSocket连接

<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>SseEmitter</title></head><body><div id="message"></div></body><script> var limitConnect = 0; init(); function init() { //开启webstocket服务的ip地址 ws:// + ip地址 + 访问路径 var ws = new WebSocket('ws://127.0.0.1:8191/double-win/chepaisend');// 获取连接状态 console.log('ws连接状态:' + ws.readyState);//监听是否连接成功 ws.onopen = function () { console.log('ws连接状态:' + ws.readyState); limitConnect = 0; //连接成功则发送一个数据 ws.send('我们建立连接啦'); }// 接听服务器发回的信息并处理展示 ws.onmessage = function (data) { console.log('接收到来自服务器的消息:'); console.log(data); //接收到 消息后给后端发送的 确认收到消息,后端接收到后 不再重复发消息 ws.send('已接收到消息'); //完成通信后关闭WebSocket连接 // ws.close(); }// 监听连接关闭事件 ws.onclose = function () { // 监听整个过程中websocket的状态 console.log('ws连接状态:' + ws.readyState); reconnect(); }// 监听并处理error事件 ws.onerror = function (error) { console.log(error); } } function reconnect() { limitConnect ++; console.log("重连第" + limitConnect + "次"); setTimeout(function(){ init(); },2000); }</script></html>

项目启动后,打开写好的前端页面后控制台打印连接信息

 新增客户后,前端接收到,并回复收到了

  新增客户后,前端接收到,并回复收到了,后端停止推送

前端接收到,但是骗后端没收到,或者说后端不知道 前端已经接收到消息。 

后端展示,后端一直往前端推送

 

本文链接地址:https://www.jiuchutong.com/zhishi/298859.html 转载请保留说明!

上一篇:css深度选择器deep(css选择器nth)

下一篇:睿智的目标检测——PyQt5搭建目标检测界面(睿智目标检测yolov8)

  • 论坛发帖推广七大技巧(论坛发帖推广七律怎么写)

    论坛发帖推广七大技巧(论坛发帖推广七律怎么写)

  • qq音乐桌面歌词锁定怎么解除(qq音乐桌面歌词怎么变颜色)

    qq音乐桌面歌词锁定怎么解除(qq音乐桌面歌词怎么变颜色)

  • 苹果手机为什么隔空投送找不到对方(苹果手机为什么充不进去电)

    苹果手机为什么隔空投送找不到对方(苹果手机为什么充不进去电)

  • 微信号搜索不到对方(微信号搜索不到是怎么回事)

    微信号搜索不到对方(微信号搜索不到是怎么回事)

  • 腾讯包季会员是几个月(腾讯会员包季划算还是包月)

    腾讯包季会员是几个月(腾讯会员包季划算还是包月)

  • 虎牙直播是哪个公司旗下的(虎牙直播是哪个公司的软件)

    虎牙直播是哪个公司旗下的(虎牙直播是哪个公司的软件)

  • 抖音同一个人看播放量会增加吗(抖音同一个人看了浏览量还会增加吗)

    抖音同一个人看播放量会增加吗(抖音同一个人看了浏览量还会增加吗)

  • 语音忙线对方有提醒吗(语音提示对方忙线中)

    语音忙线对方有提醒吗(语音提示对方忙线中)

  • 12306的账号一般是什么(12306账号一般是什么格式)

    12306的账号一般是什么(12306账号一般是什么格式)

  • 小米手环支付宝付款可以离开手机使用吗(小米手环支付宝支付怎么用)

    小米手环支付宝付款可以离开手机使用吗(小米手环支付宝支付怎么用)

  • 淘宝超时发货赔付规则(淘宝超时发货赔付后还要发货吗)

    淘宝超时发货赔付规则(淘宝超时发货赔付后还要发货吗)

  • wps专业版和个人版的区别(wps专业版和个人版可以一起用吗)

    wps专业版和个人版的区别(wps专业版和个人版可以一起用吗)

  • 华为p30什么时候上市的(华为p30什么时候升级鸿蒙3.0)

    华为p30什么时候上市的(华为p30什么时候升级鸿蒙3.0)

  • 苹果x是第几代产品(苹果x是第几代处理器)

    苹果x是第几代产品(苹果x是第几代处理器)

  • 铃声多多怎么弄到手机音乐(铃声多多怎么弄歌词到屏幕上)

    铃声多多怎么弄到手机音乐(铃声多多怎么弄歌词到屏幕上)

  • 华为荣耀20什么时候上市的(华为荣耀20什么配置)

    华为荣耀20什么时候上市的(华为荣耀20什么配置)

  • ppt图片工具栏在哪(ppt图片工具栏怎么调出来)

    ppt图片工具栏在哪(ppt图片工具栏怎么调出来)

  • 陌陌卸载后什么状态(陌陌卸载之后别人还能看到我吗)

    陌陌卸载后什么状态(陌陌卸载之后别人还能看到我吗)

  • 一加6t要用什么耳机(一加6t用什么钱包好)

    一加6t要用什么耳机(一加6t用什么钱包好)

  • 华为手机打电话时不能上网(华为手机打电话4g变2g怎么回事)

    华为手机打电话时不能上网(华为手机打电话4g变2g怎么回事)

  • 苹果延时摄影怎么调速(苹果延时摄影怎么转换正常)

    苹果延时摄影怎么调速(苹果延时摄影怎么转换正常)

  • 华为手机哪一款好用推荐(华为手机哪一款好用性价比高)

    华为手机哪一款好用推荐(华为手机哪一款好用性价比高)

  • B/S架构(b/s架构的正确解释方式)

    B/S架构(b/s架构的正确解释方式)

  • 织梦dede文章列表有缩略图显示没有缩略图的不显示图片(织梦发布文章栏目怎么不显示)

    织梦dede文章列表有缩略图显示没有缩略图的不显示图片(织梦发布文章栏目怎么不显示)

  • 税务会计常用会计科目
  • 拍卖行业收取手续费标准
  • 个人名字的发票专用章
  • 更改增值税申报表有退税会很麻烦吗
  • 报销销售部门差旅费
  • 房地产开发企业资质等级有几个
  • 填写银行结算凭证的有关印鉴,应集中由谁保管
  • 股权转让如何避免土地增值税
  • 员工借备用金怎么写摘要
  • 城市建设维护税和教育费附加怎么算
  • 加工开票税率是多少
  • 房地产企业增值税税率是多少
  • 工作量法计提折旧会计分录
  • 税法相关问题
  • 小规模印花税减免性质代码和项目名称
  • 记账凭证应交税费应交增值税怎么写
  • 房地产开发企业需要缴纳哪些税
  • 失控发票进项转出申报
  • 集团提供厂房是否需要缴纳印花税?
  • 专用发票验旧后还领不到发票
  • 发票丢失税局怎么罚款
  • 企业停产后员工怎么办
  • 企业应收是什么意思
  • 反映留存收益的账户
  • 买购物卡发福利怎么发
  • 利空啥意思
  • 退款给客户怎么写分录
  • 开具给个人的发票哪里查询
  • 取得基建借款分录
  • 所得税季报填报说明
  • 住宅用途的房屋可以办理医疗器械证吗
  • nginx静态文件服务器
  • vue 滚动条往下滑
  • yolov1网络结构图详解
  • php 使用 AWS kinesis
  • php中实现文件上传需要用到哪几个函数
  • php的序列化操作生成的哪种格式
  • 省外的发票能入账吗
  • 苹果cmsjsui
  • 对公账户的资金怎么转出
  • 发票开具的常见错误以及盖章问题
  • 广告合同印花税税目怎么填
  • 所得税预缴申报表
  • 基于vue的开源甘特图控件
  • 织梦官方网站
  • 累计盈余下设明细科目吗
  • 收缩数据库日志文件对数据有影响吗
  • 母子公司收入合并
  • 一般纳税人企业所得税5%还是25%
  • 应付劳务费怎么做账
  • 进项税额是怎么算的
  • 企业转让固定资产发生的费用可扣除吗
  • 其他债权投资的特征有哪些
  • 房地产开发公司是做什么的
  • 分公司给总公司分红怎么入账
  • 预付账款无法取得发票如何做账
  • mysql增删改查实例
  • solaris newfs
  • StatusClient.exe - StatusClient是什么进程 有什么作用
  • 修改虚拟机中的用户名
  • wysafe.exe是什么
  • windows推送
  • win1020h2镜像
  • 电脑市场调查报告
  • windows7的使用方法
  • linux升级系统版本
  • linux用
  • winpe 系统还原
  • python urllib urlopen
  • shell脚本监控日志输出
  • perl-dbd-mysql是什么
  • perl keys
  • jquery jsonview
  • 浅谈python
  • javascript入门教程
  • js math.js
  • jQuery简单实现title提示效果示例
  • 国家税务总局吕梁市税务局官网
  • 多缴税款可以抵顶以后欠费的税款吗
  • 杨柳青还迁房2024年还建不建
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设