【WebSocket】

news2025/1/11 15:09:45

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

      • 3.1 介绍
      • 3.2 入门案例
        • 3.2.1 案例分析
        • 3.2.2 代码开发
        • 3.2.3 功能测试
    • 4. 来单提醒
      • 4.1 需求分析和设计
      • 4.2 代码开发
      • 4.3 功能测试
    • 5. 客户催单
      • 5.1 需求分析和设计
      • 5.2 代码开发
        • 5.2.1 Controller层
        • 5.2.2 Service层接口
        • 5.2.3 Service层实现类
      • 5.3 功能测试


3.1 介绍

WebSocket 是基于 TCP 的一种新的网络协议。它实现了浏览器与服务器全双工通信——浏览器和服务器只需要完成一次握手,两者之间就可以创建持久性的连接, 并进行双向数据传输。

HTTP协议和WebSocket协议对比:

  • HTTP是短连接
  • WebSocket是长连接
  • HTTP通信是单向的,基于请求响应模式
  • WebSocket支持双向通信
  • HTTP和WebSocket底层都是TCP连接
    在这里插入图片描述
    **思考:**既然WebSocket支持双向通信,功能看似比HTTP强大,那么我们是不是可以基于WebSocket开发所有的业务功能?

WebSocket缺点:

服务器长期维护长连接需要一定的成本
各个浏览器支持程度不一
WebSocket 是长连接,受网络限制比较大,需要处理好重连

**结论:**WebSocket并不能完全取代HTTP,它只适合在特定的场景下使用

WebSocket应用场景:

1). 视频弹幕
在这里插入图片描述
2). 网页聊天
在这里插入图片描述
3). 体育实况更新
在这里插入图片描述
4). 股票基金报价实时更新
在这里插入图片描述

3.2 入门案例

3.2.1 案例分析

**需求:**实现浏览器与服务器全双工通信。浏览器既可以向服务器发送消息,服务器也可主动向浏览器推送消息。

效果展示:
在这里插入图片描述
实现步骤:

1). 直接使用websocket.html页面作为WebSocket客户端

2). 导入WebSocket的maven坐标

3). 导入WebSocket服务端组件WebSocketServer,用于和客户端通信

4). 导入配置类WebSocketConfiguration,注册WebSocket的服务端组件

5). 导入定时任务类WebSocketTask,定时向客户端推送数据

3.2.2 代码开发

1). 定义websocket.html页面(资料中已提供)

<!DOCTYPE HTML>
<html>
<head>
    <meta charset="UTF-8">
    <title>WebSocket Demo</title>
</head>
<body>
    <input id="text" type="text" />
    <button onclick="send()">发送消息</button>
    <button onclick="closeWebSocket()">关闭连接</button>
    <div id="message">
    </div>
</body>
<script type="text/javascript">
    var websocket = null;
    var clientId = Math.random().toString(36).substr(2);

    //判断当前浏览器是否支持WebSocket
    if('WebSocket' in window){
        //连接WebSocket节点
        websocket = new WebSocket("ws://localhost:8080/ws/"+clientId);
    }
    else{
        alert('Not support websocket')
    }

    //连接发生错误的回调方法
    websocket.onerror = function(){
        setMessageInnerHTML("error");
    };

    //连接成功建立的回调方法
    websocket.onopen = function(){
        setMessageInnerHTML("连接成功");
    }

    //接收到消息的回调方法
    websocket.onmessage = function(event){
        setMessageInnerHTML(event.data);
    }

    //连接关闭的回调方法
    websocket.onclose = function(){
        setMessageInnerHTML("close");
    }

    //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
    window.onbeforeunload = function(){
        websocket.close();
    }

    //将消息显示在网页上
    function setMessageInnerHTML(innerHTML){
        document.getElementById('message').innerHTML += innerHTML + '<br/>';
    }

    //发送消息
    function send(){
        var message = document.getElementById('text').value;
        websocket.send(message);
    }
	
	//关闭连接
    function closeWebSocket() {
        websocket.close();
    }
</script>
</html>

2). 导入maven坐标

在sky-server模块pom.xml中已定义

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
``
3). 定义WebSocket服务端组件(资料中已提供)

直接导入到sky-server模块即可`

```java
package com.sky.websocket;

import org.springframework.stereotype.Component;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

/**
 * WebSocket服务
 */
@Component
@ServerEndpoint("/ws/{sid}")
public class WebSocketServer {

    //存放会话对象
    private static Map<String, Session> sessionMap = new HashMap();

    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("sid") String sid) {
        System.out.println("客户端:" + sid + "建立连接");
        sessionMap.put(sid, session);
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(String message, @PathParam("sid") String sid) {
        System.out.println("收到来自客户端:" + sid + "的信息:" + message);
    }

    /**
     * 连接关闭调用的方法
     *
     * @param sid
     */
    @OnClose
    public void onClose(@PathParam("sid") String sid) {
        System.out.println("连接断开:" + sid);
        sessionMap.remove(sid);
    }

    /**
     * 群发
     *
     * @param message
     */
    public void sendToAllClient(String message) {
        Collection<Session> sessions = sessionMap.values();
        for (Session session : sessions) {
            try {
                //服务器向客户端发送消息
                session.getBasicRemote().sendText(message);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}

4). 定义配置类,注册WebSocket的服务端组件(从资料中直接导入即可)

package com.sky.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

/**
 * WebSocket配置类,用于注册WebSocket的Bean
 */
@Configuration
public class WebSocketConfiguration {

    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }

}

5). 定义定时任务类,定时向客户端推送数据(从资料中直接导入即可)

package com.sky.task;

import com.sky.websocket.WebSocketServer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

@Component
public class WebSocketTask {
    @Autowired
    private WebSocketServer webSocketServer;

    /**
     * 通过WebSocket每隔5秒向客户端发送消息
     */
    @Scheduled(cron = "0/5 * * * * ?")
    public void sendMessageToClient() {
        webSocketServer.sendToAllClient("这是来自服务端的消息:" + DateTimeFormatter.ofPattern("HH:mm:ss").format(LocalDateTime.now()));
    }
}

3.2.3 功能测试

启动服务,打开websocket.html页面

浏览器向服务器发送数据:

在这里插入图片描述
服务器向浏览器间隔5秒推送数据:
在这里插入图片描述

4. 来单提醒

4.1 需求分析和设计

用户下单并且支付成功后,需要第一时间通知外卖商家。通知的形式有如下两种:

  • 语音播报 image-20221222194413901

  • 弹出提示框

  • 在这里插入图片描述
    设计思路:

  • 通过WebSocket实现管理端页面和服务端保持长连接状态

  • 当客户支付后,调用WebSocket的相关API实现服务端向客户端推送消息

  • 客户端浏览器解析服务端推送的消息,判断是来单提醒还是客户催单,进行相应的消息提示和语音播报

  • 约定服务端发送给客户端浏览器的数据格式为JSON,字段包括:type,orderId,content

    • type 为消息类型,1为来单提醒 2为客户催单
    • orderId 为订单id
    • content 为消息内容

4.2 代码开发

在OrderServiceImpl中注入WebSocketServer对象,修改paySuccess方法,加入如下代码:

	@Autowired
    private WebSocketServer webSocketServer;
	/**
     * 支付成功,修改订单状态
     *
     * @param outTradeNo
     */
    public void paySuccess(String outTradeNo) {
        // 当前登录用户id
        Long userId = BaseContext.getCurrentId();

        // 根据订单号查询当前用户的订单
        Orders ordersDB = orderMapper.getByNumberAndUserId(outTradeNo, userId);

        // 根据订单id更新订单的状态、支付方式、支付状态、结账时间
        Orders orders = Orders.builder()
                .id(ordersDB.getId())
                .status(Orders.TO_BE_CONFIRMED)
                .payStatus(Orders.PAID)
                .checkoutTime(LocalDateTime.now())
                .build();

        orderMapper.update(orders);
		//
        Map map = new HashMap();
        map.put("type", 1);//消息类型,1表示来单提醒
        map.put("orderId", orders.getId());
        map.put("content", "订单号:" + outTradeNo);

        //通过WebSocket实现来单提醒,向客户端浏览器推送消息
        webSocketServer.sendToAllClient(JSON.toJSONString(map));
        ///
    }

4.3 功能测试

可以通过如下方式进行测试:

  • 查看浏览器调试工具数据交互过程
  • 前后端联调

1). 登录管理端后台

登录成功后,浏览器与服务器建立长连接
在这里插入图片描述
2). 小程序端下单支付

修改回调地址,利用内网穿透获取域名
在这里插入图片描述
下单支付
在这里插入图片描述
3). 查看来单提醒

支付成功后,后台收到来单提醒,并有语音播报
在这里插入图片描述

5. 客户催单

5.1 需求分析和设计

用户在小程序中点击催单按钮后,需要第一时间通知外卖商家。通知的形式有如下两种:

  • 语音播报 image-20221222203301218

  • 弹出提示框

  • 在这里插入图片描述
    设计思路:

  • 通过WebSocket实现管理端页面和服务端保持长连接状态

  • 当用户点击催单按钮后,调用WebSocket的相关API实现服务端向客户端推送消息

  • 客户端浏览器解析服务端推送的消息,判断是来单提醒还是客户催单,进行相应的消息提示和语音播报
    约定服务端发送给客户端浏览器的数据格式为JSON,字段包括:type,orderId,content

    • type 为消息类型,1为来单提醒 2为客户催单
    • orderId 为订单id
    • content 为消息内容

当用户点击催单按钮时,向服务端发送请求。

接口设计(催单):
在这里插入图片描述

5.2 代码开发

5.2.1 Controller层

根据用户催单的接口定义,在user/OrderController中创建催单方法:

	/**
     * 用户催单
     *
     * @param id
     * @return
     */
    @GetMapping("/reminder/{id}")
    @ApiOperation("用户催单")
    public Result reminder(@PathVariable("id") Long id) {
        orderService.reminder(id);
        return Result.success();
    }

5.2.2 Service层接口

在OrderService接口中声明reminder方法:

	/**
     * 用户催单
     * @param id
     */
    void reminder(Long id);

5.2.3 Service层实现类

在OrderServiceImpl中实现reminder方法:

	/**
     * 用户催单
     *
     * @param id
     */
    public void reminder(Long id) {
        // 查询订单是否存在
        Orders orders = orderMapper.getById(id);
        if (orders == null) {
            throw new OrderBusinessException(MessageConstant.ORDER_NOT_FOUND);
        }

        //基于WebSocket实现催单
        Map map = new HashMap();
        map.put("type", 2);//2代表用户催单
        map.put("orderId", id);
        map.put("content", "订单号:" + orders.getNumber());
        webSocketServer.sendToAllClient(JSON.toJSONString(map));
    }

5.2.4 Mapper层

在OrderMapper中添加getById:

	/**
     * 根据id查询订单
     * @param id
     */
    @Select("select * from orders where id=#{id}")
    Orders getById(Long id);

5.3 功能测试

可以通过如下方式进行测试:

  • 查看浏览器调试工具数据交互过程
  • 前后端联调

1). 登录管理端后台

登录成功后,浏览器与服务器建立长连接
在这里插入图片描述
查看控制台日志
在这里插入图片描述
2). 用户进行催单

用户可在订单列表或者订单详情,进行催单
在这里插入图片描述
3). 查看催单提醒

既有催单弹窗,同时语音播报
在这里插入图片描述

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

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

相关文章

接口自动化测试,一键快速校验接口返回值全部字段

目录 前言&#xff1a; 一、认识一下&#xff0c;DeepDiff 介绍 主要组成部分&#xff1a; 二、DeepDiff 使用 2.1 案例一&#xff1a;比较两个 JSON 2.2 案例二&#xff1a;比较接口响应 2.3 案例三&#xff1a;正则搜索匹配 三、最后一个小技巧&#xff1a;DeepDiff …

【代码随想录 | Leetcode | 第二天】数组 | 双指针法 | 相向双指针 | 27

前言 欢迎来到小K的Leetcode|代码随想录|专题化专栏&#xff0c;今天将为大家带来双指针法和相向双指针的分享✨ 目录 前言27. 移除元素 27. 移除元素 ✨题目链接点这里 给你一个数组 nums 和一个值 val&#xff0c;你需要 原地 移除所有数值等于val的元素&#xff0c;并返回…

keep-alive和router-view配合使用缓存整个路由页面以及路由切换

实现内容&#xff1a;通过vue实现&#xff0c;在页面有侧边栏动态来展示当前页面流程&#xff0c;右边进行页面的切换&#xff0c;左右两边都是组件&#xff0c;但是A/B/C组件的切换是通过keep-alive搭配router-view实现的&#xff0c;首先在当前文件中创建五个文件&#xff1a…

Linux系统编程(传统信号和实时信号)

文章目录 前言一、传统信号和实时信号概念二、重要函数介绍三、实时信号和传统信号被处理的次数总结 前言 本篇文章我们来讲解传统信号和实时信号&#xff0c;这里我们将从实际应用给大家讲解。 一、传统信号和实时信号概念 传统信号&#xff08;Traditional Signals&#x…

spring boot学习第一篇:spring boot 1.5.x版本启动接口服务

1、pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.…

华为云出品《IDEA-Plugin-开发手册》电子书——学完即会场景设计

小智又来给各位开发者送书啦&#xff01; 助力各位开发者们提升技能 海量案例串联 IEDA Plugin 插件开发技能 重实践与验证帮助避免踩坑 学完就可自己完成一些场景设计和开发 适合有一定编程基础&#xff0c;1年以上经验的开发者 适合对IDEA Plugin有学习需求或想拓展业务…

出海企业系列风险分析--网站需要验证码吗?

最近接待了几位从discuz来的用户&#xff0c;说是想要给自己海外的网站安装验证码&#xff0c;但是discuz境外服务器还要解析安装中心的DNS到境外服务器上&#xff0c;所以基于discuz建站的不好之处就在这里。 而且我们还讨论到一个问题&#xff0c;海外的网站&#xff0c;需要…

【线程概念和线程控制】

目录 1 :peach:线程概念 :peach:1.1 :apple:什么是线程&#xff1f;:apple:1.2 :apple:线程的优点和缺点:apple:1.3 :apple:页表的大小:apple:1.4 :apple:线程异常和用途:apple:1.5 :apple:进程VS线程:apple: 2 :peach:线程控制:peach:2.1 :apple:POSIX线程库:apple:2.2 :apple…

tp6的runtime/Logs目录下产生大量日记文件,怎么取消自动生成?

一开始查了好多网上提供的&#xff0c;很幸运都是抄袭别人的&#xff0c;没一个成功&#xff0c;最后无奈只能自己解决方法 其实很简单&#xff0c;不用修改config/log.php文件&#xff0c;没用因为只要有登入错误&#xff0c;警告&#xff0c;消息或者sql错误都会写入 解决方…

windows编译poco c++库

背景 最近有了解到poco c库&#xff0c;这里记录下编译及使用过程。 最开始使用的vs studio 2022 和 poco 1.12.4版本编译&#xff0c;不管openssl 使用哪种版本&#xff0c;都会编译报错&#xff0c;最后妥协了。 参考&#xff1a;https://www.bilibili.com/read/cv1416565…

《语文新读写》期刊简介及投稿邮箱

《语文新读写》期刊简介&#xff1a; 《语文新读写》是“国家期刊奖”获奖期刊&#xff0c;中国期刊方阵双效期刊&#xff0c;中国核心期刊&#xff08;遴选&#xff09;数据库收录期刊&#xff0c;被授予上海市期刊优秀编辑部。杂志的主要读者对象为各大院校、中小学各科教师…

安全帽佩戴检测算法模型训练详细流程

一、任务描述 实际施工现场需要对每个进出的人员进行安全帽监测&#xff0c;对未佩戴安全帽的人员平台进行风险告警&#xff0c;通知工作人员并记录下来。 主要包括三类目标物体&#xff1a;头盔&#xff08;helmet&#xff09;&#xff0c;人&#xff08;person&#xff09;…

100种思维模型之耗散结构理论思维模型-96

避免熵死的方法之一就是建立 耗散结构 。 那么&#xff0c;何谓耗散结构理论&#xff1f; 01、何谓耗散结构思维模型‍‍‍ 一、耗散结构理论 1969年&#xff0c;比利时学者 伊里亚普利高津 在对热力学第二定律研究的基础上&#xff0c;提出了 “耗散结构理论”。 他认…

【导航电子地图(MAP)模块功能】

Map功能&#xff1a;提供导航系统中地图描画、地图操作、地图检索的功能。 地图操作功能&#xff1a;地图滚动等。 地图检索功能&#xff1a;附近名称取得、View内检索等。 地图描画功能&#xff1a;是指从地图Data base中读出地点情报&#xff0c;然后按照一定的风格&#…

Meta提出全新参数高效微调方案,仅需一个RNN,Transformer模型GPU使用量减少84%!

近来&#xff0c;随着ChatGPT和GPT-4模型的不断发展&#xff0c;国内外互联网大厂纷纷推出了自家的大语言模型&#xff0c;例如谷歌的PaLM系列&#xff0c;MetaAI的LLaMA系列&#xff0c;还有国内公司和高校推出的一些大模型&#xff0c;例如百度的文心一言&#xff0c;清华的C…

vue3中通过vue-i18n实现国际化

效果图 前言 突然想在vue3项目中使用国际化功能&#xff0c;查阅相关资料后发现和vue2的用法有些出入&#xff0c;记录一下 使用 下载vue-i18n npm i vue-i18n2、准备语言文件 目前我的项目只支持中英文切换&#xff0c;故准备一份中文文件和一份对应的英译文件 创建langur…

七大排序算法——直接插入排序,通俗易懂的思路讲解与图解(完整Java代码)

文章目录 一、排序的概念排序的概念排序的稳定性七大排序算法 二、直接插入排序核心思想代码实现 三、性能分析四、七大排序算法性能对比 一、排序的概念 排序的概念 排序&#xff1a;所谓排序&#xff0c;就是使一串记录&#xff0c;按照其中的某个或某些关键字的大小&#…

【Java进阶之路】NIO基础

一、NIO基础 Java New IO是从Java1.4版本开始引入的一个新的IO api&#xff0c;可以替代以往的标准IO&#xff0c;NIO相比原来的IO有同样的作用和目的&#xff0c;但是使用的方式完全不一样&#xff0c;NIO是面向缓冲区的&#xff0c;基于通道的IO操作&#xff0c;这也让它比传…

美团外卖智能陪伴型导购的探索与实践

相比于其他电商场景&#xff0c;外卖场景对于实时发现和反馈用户兴趣的能力有着更高的要求。近年来&#xff0c;美团外卖算法团队摸索出了一套适用于外卖场景的智能陪伴型导购架构和策略。这一举措已经取得了显著成效&#xff0c;本文将详细介绍外卖搜索技术团队搭建智能陪伴型…

Redis数据结构 — IntSet

目录 整数集合IntSet结构设计 IntSet的升级操作 升级具体过程 升级具体源码 小结 IntSet是Redis中set集合的一种实现方式&#xff0c;基于整数数组来实现&#xff0c;并且具备长度可变、有序等特征。 整数集合IntSet结构设计 整数集合本质上是一块连续内存空间&#xff…