[苍穹外卖]-10WebSocket入门与实战

WebSocket

WebSocket是基于TCP的一种新的网络协议, 实现了浏览器与服务器的全双工通信, 即一次握手,建立持久连接,双向数据传输

区别

  1. HTTP是短连接, WebSocket是长连接
  2. HTTP单向通信, 基于请求响应模型
  3. WebSocket支持双向通信

相同

  1. HTTP和WebSocket底层都是TCP连接

应用场景: 视频弹幕/网页聊天/体育实况更新/股票基金报价实时更新

入门案例

使用webcocket.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>
  1. 大部分浏览器都支持websocket, 通过new WebSocket就可以创建WebScoket对象

导入Maven坐标

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

创建WebSocket服务类, 用于处理客户端的通信, 类似于Controller

/** 
 * 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();
            }
        }
    }

}

配置类: 用于创建WebSocket的服务对象, 并交给IOC容器管理

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

    @Bean //程序运行时,创建WebSocket的服务对象,把对象交给IOC容器管理
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }

}

使用WebSocket服务, 完成浏览器/服务器的双向通信

@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()));
    }
}

功能测试: 启动前端页面, 建立WebSocket连接, 服务端通过定时任务类定时给前端推送消息, 前端也可以给服务端发送消息

来单提醒

需求分析: 用户下单并且支付成功后, 需要在第一时间通知外卖商家, 通知的形式是 语音提醒 + 弹出提示框

思路分析

  1. 通过WebSocket实现管理端页面和服务端的长连接
  2. 当客户支付后, 调用WebSocket的相关API实现服务端向客户端推送消息
  3. 客户端浏览器解析服务端推送的消息, 判断是来单提醒还是客户催单, 进行相应的消息提示和语音播报
  4. 约定服务端发送给管理端页面的数据格式为JSON格式
  • type: 消息类型, 1是来单提醒, 2是客户催单
  • orderId: 订单id
  • content: 消息内容

代码开发: 基于WebSocket入门案例改造代码

@Service
@Slf4j
public class OrderServiceImpl implements OrderService {

    @Autowired
    private WebSocketServer webSocketServer;


    /**
     * 支付成功,修改订单状态
     *
     * @param outTradeNo
     */
    public void paySuccess(String outTradeNo) {

        // 根据订单号查询订单
        Orders ordersDB = orderMapper.getByNumber(outTradeNo);

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

        orderMapper.update(orders);

        // 通过webscoket向客户端浏览器推送消息
        Map map = new HashMap();
        map.put("type", 1); // 1:来单提醒, 2:客户催单
        map.put("orderId", ordersDB.getId());
        map.put("content", "订单号:" + outTradeNo);
        String json = JSON.toJSONString(map);
        webSocketServer.sendToAllClient(json);
    }
}

功能测试: 客户端下单并支付成功后, 商家管理端进行语音播报并弹出提示框

交互说明: 客户端的websocket请求也是经过nginx服务器进行的代理转发

客户催单

需求分析: 用户在小程序中点击催单按钮后, 需要通知外卖商家, 通知形式是语音播报 + 弹出提示框

流程分析

  1. 通过WebSocket实现管理端页面和服务端的长连接
  2. 客户点击催单按钮后, 发起催单请求, 服务端收到请求后, 通过WebSocket, 推送消息给管理端页面
  3. 管理端页面拿到消息后, 进行相应的消息提示和语言播报
  4. 约定服务端发送给管理端页面的数据格式为JSON
  • type: 消息类型, 1: 来单提醒, 2: 客户催单
  • orderId: 订单id
  • content: 消息内容

接口设计

代码实现

@RestController("userOrderController")
@RequestMapping("/user/order")
@Slf4j
@Api(tags = "用户端订单相关接口")
public class OrderController {

    @Autowired
    private OrderService orderService;

    /**
     * 客户催单
     */
    @GetMapping("/reminder/{id}")
    @ApiOperation("客户催单")
    public Result reminder(@PathVariable Long id) {
        log.info("订单id:{}", id);
        orderService.reminder(id);
        return Result.success();
    }
}
public interface OrderService {

    /**
     * 客户催单
     * @param id
     */
    void reminder(Long id);
}
@Service
@Slf4j
public class OrderServiceImpl implements OrderService {

    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private WebSocketServer webSocketServer;
    
    /**
     * 客户催单
     *
     * @param id
     */
    public void reminder(Long id) {
        // 根据id查询订单
        Orders ordersDB = orderMapper.getById(id);

        // 校验订单是否存在
        if (ordersDB == null) {
            throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR);
        }

        Map map = new HashMap();
        map.put("type", 2); // 1表示来单提醒, 2表示客户催单
        map.put("orderId", id);
        map.put("content", "订单号:" + ordersDB.getNumber());
        webSocketServer.sendToAllClient(JSON.toJSONString(map));
    }
}

功能测试: 用户点击催单按钮, 商家管理端播放语音提示, 并弹出消息框

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于Java+SpringBoot+Vue+MySQL的西安旅游管理系统网站

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 基于SpringBootVue的西安旅游管理系统网站【附源码文档】、…

跨系统环境下LabVIEW程序稳定运行

在LabVIEW开发中&#xff0c;不同电脑的配置和操作系统&#xff08;如Win11与Win7&#xff09;可能对程序的稳定运行产生影响。为了确保程序在不同平台上都能正常且稳定运行&#xff0c;需要从兼容性、驱动、以及性能优化等多个方面入手。本文将详细介绍如何在不同系统环境下&a…

视频监控基础学习

IPC&#xff1a;网络摄像机 NVR&#xff1a;网络硬盘录像机产品&#xff0c;搭配IPC使用。集成存储、解码显示、拼接控制、智能分析等多种功能于一体。一机多用&#xff0c;部署简单&#xff0c;功能齐全。安全可靠&#xff0c;适用于各类场景。 ONVIF协议&#xff1a;网络摄像…

Docker:对已有的容器,对当前容器映射的端口实时 (增删改查)

首先我的docker已经起了一个容器&#xff0c;我突然想把他的80->80映射的端口改成80->8080 但是我不想去新启动容器&#xff0c;想在现有容器基础上去修改&#xff0c;或者我想删除某个端口映射&#xff08;只是大概思路&#xff09; 如何寻找容器配置文件位置 首先我这…

代码随想录27期|Python|Day54|​单调栈|​42. 接雨水|84. 柱状图中最大的矩形

42. 接雨水 根据常识可以归纳出&#xff0c;对于每一列所能够存住的水的高度 Height min(LeftMax, RightMax) - height 也就是&#xff0c;当前列的存水高度 左侧和右侧柱子的最大高度的较小值&#xff0c;减去当前列的柱子高度&#xff0c;所得到的差值。 可以验证第4列&…

如何通过OceanBase的多级弹性扩缩容能力应对业务洪峰

每周四晚上的10点&#xff0c;都有近百万的年轻用户进入泡泡玛特的抽盒机小程序&#xff0c;共同参与到抢抽盲盒新品的活动中。瞬间的并发流量激增对抽盒机小程序的系统构成了巨大的挑战&#xff0c;同时也对其数据库的扩容能力也提出了更高的要求。 但泡泡玛特的工程师们一点…

【系统架构师】-论文-2024-2009年系统架构师历年论文题目

2024年5月 大数据Lambda架构的应用与分析 云原生云上DevOps运维应用与分析 模型驱动软件开发方法与应用 论单元测试在软件回归测试中的应用和分析 2023年 论面向对象设计的应用与实现 论多数据源集成的应用与实现 论软件可靠性模型的设计与实现 论边缘计算技术的设计与实现 …

【Linux】3.切换操作系统

文章目录 1. 为什么要切换操作系统2. 如何备份操作系统文件3.如何切换操作系统4. 在Ubuntu操作系统中恢复文件 1. 为什么要切换操作系统 由于CentoS官方宣布不再维护了&#xff0c;为了避免服务器安全和各类环境问题&#xff0c;我将云服务器改为Ubuntu操作系统。 Ubuntu 不仅…

HarmonyOS开发实战( Beta5.0)自动生成动态路由实践

鸿蒙HarmonyOS开发往期必看&#xff1a; HarmonyOS NEXT应用开发性能实践总结 最新版&#xff01;“非常详细的” 鸿蒙HarmonyOS Next应用开发学习路线&#xff01;&#xff08;从零基础入门到精通&#xff09; 介绍 本示例将介绍如何使用装饰器和插件&#xff0c;自动生成动…

使用Azure Devops Pipeline将Docker应用部署到你的Raspberry Pi上

文章目录 1. 添加树莓派到 Agent Pool1.1 添加pool1.2 添加agent 2. 将树莓派添加到 Deployment Pool2.1 添加pool2.2 添加target 3. 添加编译流水线3.1 添加编译命令3.2 配置触发器 4. 添加发布流水线4.1 添加命令行4.2 配置artifact和触发器 5. 完成 1. 添加树莓派到 Agent P…

三菱FX5U CPU 内置以太网功能

什么是内置以太网功能FX5CPU模块内置以太网通信端口&#xff0c;可以利用TCP/IPUDP/IP通信协议&#xff0c;经过以太网(100BASE-TX、10BASET)与计算机或其他以太网设备进行通信。 MELSOFT连接 与MELSOFT产品连接的功能&#xff0c;MELSOFT产品主要指三菱的软件及GOT。 SLMP通信…

Kafka原理剖析之「Topic创建」

一、前言 Kafka提供了高性能的读写&#xff0c;而这些读写操作均是操作在Topic上的&#xff0c;Topic的创建就尤为关键&#xff0c;其中涉及分区分配策略、状态流转等&#xff0c;而Topic的新建语句非常简单 bash kafka-topics.sh \ --bootstrap-server localhost:9092 \ // …

【GBase 8c V5_3.0.0 分布式数据库常用维护命令】

一、查看数据库状态/检查&#xff08;gbase用户&#xff09; 1.gha_ctl monitor 使用gha_ctl monitor查看节点运行情况(跟dcs的地址和端口) gha_ctl monitor -c gbase -l http://172.20.10.8:2379 -Hall |coordinator | datanode | gtm | server|dcs:必选字段。指定查看哪类集…

Oracle EBS AP预付款行分配行剩余预付金额数据修复

系统环境 RDBMS : 12.1.0.2.0 Oracle Applications : 12.2.6 问题情况 AP预付款已验证和自动审批但是未过账已经AP付款但是又撤消付款并且未过账问题症状 AP预付款暂挂: AP预付款行金额(等于发票金额)与分配行金额不相等: 取消AP预付款提示如下:

基于Python的B站热门视频可视化分析与挖掘系统

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长 QQ 名片 :) 1. 项目简介 随着互联网视频平台的迅猛发展&#xff0c;如何从海量的数据中提炼出有价值的信息成为了内容创作者们关注的重点之一。B站&#xff08;哔哩哔哩&#xff09;作为国内领先的年轻人文化社区&#xf…

08 vue3之认识bem架构及less sass 和scoped

bem架构 他是一种css架构 oocss 实现的一种 &#xff08;面向对象css&#xff09; &#xff0c;BEM实际上是block、element、modifier的缩写&#xff0c;分别为块层、元素层、修饰符层&#xff0c;element UI 也使用的是这种架构 1. BEM架构 1. 介绍 1. BEM是Block Element M…

美联社发稿推广中必备的6个社交媒体平台

社交媒体是现代社会中不可或缺的一部分&#xff0c;它已经成为了信息传播、群体交流和网络推广的重要工具。对于彭博社这样的专业媒体来说&#xff0c;充分利用社交媒体平台可以更好地推广自己的新闻报道和文章。 在这篇文章中&#xff0c;我们将介绍彭博社发稿推广中必备的六…

SpringBoot实现房产销售系统全解析

第二章关键技术的研究 2.1相关技术 房产销售系统是在Java MySQL开发环境的基础上开发的。Java是一种服务器端脚本语言&#xff0c;易于学习&#xff0c;实用且面向用户。全球超过35&#xff05;的Java驱动的互联网站点使用Java。MySQL是一个数据库管理系统&#xff0c;因为它的…

2024/9/9 408“回头看”:b树

B树是什么&#xff1f;有什么作用&#xff1f;B树的插入和删除具体细节是什么&#xff1f;除了B树还有一个是B&#xff0b;树、还是B-树&#xff0c;他们有什么区别&#xff0c;又有什么相同点&#xff1f; b树在王道考研查找这一章&#xff0c;所以他的主要作用就是查找。 在…

spring常用注解(10)@Order

一、 1、作用 加Order()注解&#xff0c;在注解中加入数字&#xff0c;数字越小&#xff0c;优先级越高&#xff0c;最先执行。 2、使用方法 &#xff08;1&#xff09;自定义顺序 Component Order(1) public class XxxFilter extends OncePerRequestFilter{}Component Or…