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

打印 上一主题 下一主题

主题 578|帖子 578|积分 1734

WebSocket

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












区别

  • HTTP是短连接, WebSocket是长连接
  • HTTP单向通讯, 基于哀求响应模型
  • WebSocket支持双向通讯
相同

  • HTTP和WebSocket底层都是TCP连接
应用场景: 视频弹幕/网页聊天/体育实况更新/股票基金报价实时更新









入门案例
使用webcocket.html页面作为客户端, 双击打开即用
  1. <!DOCTYPE HTML>
  2. <html>
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <title>WebSocket Demo</title>
  6. </head>
  7. <body>
  8.     <input id="text" type="text" />
  9.     <button onclick="send()">发送消息</button>
  10.     <button onclick="closeWebSocket()">关闭连接</button>
  11.     <div id="message">
  12.     </div>
  13. </body>
  14. <script type="text/javascript">
  15.     var websocket = null;
  16.     var clientId = Math.random().toString(36).substr(2);
  17.     //判断当前浏览器是否支持WebSocket
  18.     if('WebSocket' in window){
  19.         //连接WebSocket节点
  20.         websocket = new WebSocket("ws://localhost:8080/ws/"+clientId);
  21.     }
  22.     else{
  23.         alert('Not support websocket')
  24.     }
  25.     //连接发生错误的回调方法
  26.     websocket.onerror = function(){
  27.         setMessageInnerHTML("error");
  28.     };
  29.     //连接成功建立的回调方法
  30.     websocket.onopen = function(){
  31.         setMessageInnerHTML("连接成功");
  32.     }
  33.     //接收到消息的回调方法
  34.     websocket.onmessage = function(event){
  35.         setMessageInnerHTML(event.data);
  36.     }
  37.     //连接关闭的回调方法
  38.     websocket.onclose = function(){
  39.         setMessageInnerHTML("close");
  40.     }
  41.     //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
  42.     window.onbeforeunload = function(){
  43.         websocket.close();
  44.     }
  45.     //将消息显示在网页上
  46.     function setMessageInnerHTML(innerHTML){
  47.         document.getElementById('message').innerHTML += innerHTML + '<br/>';
  48.     }
  49.     //发送消息
  50.     function send(){
  51.         var message = document.getElementById('text').value;
  52.         websocket.send(message);
  53.     }
  54.        
  55.         //关闭连接
  56.     function closeWebSocket() {
  57.         websocket.close();
  58.     }
  59. </script>
  60. </html>
复制代码

  • 大部分欣赏器都支持websocket, 通过new WebSocket就可以创建WebScoket对象

导入Maven坐标
  1. <dependency>
  2.    <groupId>org.springframework.boot</groupId>
  3.    <artifactId>spring-boot-starter-websocket</artifactId>
  4. </dependency>
复制代码

创建WebSocket服务类, 用于处置处罚客户端的通讯, 类似于Controller
  1. /**
  2. * WebSocket服务
  3. */
  4. @Component
  5. @ServerEndpoint("/ws/{sid}")
  6. public class WebSocketServer {
  7.     //存放会话对象
  8.     private static Map<String, Session> sessionMap = new HashMap();
  9.        /**
  10.      * 连接建立成功调用的方法
  11.      */
  12.     @OnOpen
  13.     public void onOpen(Session session, @PathParam("sid") String sid) {
  14.         System.out.println("客户端:" + sid + "建立连接");
  15.         sessionMap.put(sid, session);
  16.     }
  17.      /**
  18.      * 收到客户端消息后调用的方法
  19.      *
  20.      * @param message 客户端发送过来的消息
  21.      */
  22.     @OnMessage
  23.     public void onMessage(String message, @PathParam("sid") String sid) {
  24.         System.out.println("收到来自客户端:" + sid + "的信息:" + message);
  25.     }
  26.     /**
  27.      * 连接关闭调用的方法
  28.      *
  29.      * @param sid
  30.      */
  31.     @OnClose
  32.     public void onClose(@PathParam("sid") String sid) {
  33.         System.out.println("连接断开:" + sid);
  34.         sessionMap.remove(sid);
  35.     }
  36.    
  37.     /**
  38.      * 群发
  39.      *
  40.      * @param message
  41.      */
  42.     public void sendToAllClient(String message) {
  43.         Collection<Session> sessions = sessionMap.values();
  44.         for (Session session : sessions) {
  45.             try {
  46.                 //服务器向客户端发送消息
  47.                 session.getBasicRemote().sendText(message);
  48.             } catch (Exception e) {
  49.                 e.printStackTrace();
  50.             }
  51.         }
  52.     }
  53. }
复制代码

设置类: 用于创建WebSocket的服务对象, 并交给IOC容器管理
  1. /**
  2. * WebSocket配置类,用于注册WebSocket的Bean
  3. */
  4. @Configuration // 声明配置类
  5. public class WebSocketConfiguration {
  6.     @Bean //程序运行时,创建WebSocket的服务对象,把对象交给IOC容器管理
  7.     public ServerEndpointExporter serverEndpointExporter() {
  8.         return new ServerEndpointExporter();
  9.     }
  10. }
复制代码

使用WebSocket服务, 完成欣赏器/服务器的双向通讯
  1. @Component
  2. public class WebSocketTask {
  3.     @Autowired
  4.     private WebSocketServer webSocketServer;
  5.     /**
  6.      * 通过WebSocket每隔5秒向客户端发送消息
  7.      */
  8.     @Scheduled(cron = "0/5 * * * * ?")
  9.     public void sendMessageToClient() {
  10.         webSocketServer.sendToAllClient("这是来自服务端的消息:" + DateTimeFormatter.ofPattern("HH:mm:ss").format(LocalDateTime.now()));
  11.     }
  12. }
复制代码

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






来单提示

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



思绪分析

  • 通过WebSocket实现管理端页面和服务端的长连接
  • 当客户付出后, 调用WebSocket的相关API实现服务端向客户端推送消息
  • 客户端欣赏器剖析服务端推送的消息, 判定是来单提示照旧客户催单, 进行相应的消息提示和语音播报
  • 约定服务端发送给管理端页面的数据格式为JSON格式


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

代码开发: 基于WebSocket入门案例改造代码
  1. @Service
  2. @Slf4j
  3. public class OrderServiceImpl implements OrderService {
  4.     @Autowired
  5.     private WebSocketServer webSocketServer;
  6.     /**
  7.      * 支付成功,修改订单状态
  8.      *
  9.      * @param outTradeNo
  10.      */
  11.     public void paySuccess(String outTradeNo) {
  12.         // 根据订单号查询订单
  13.         Orders ordersDB = orderMapper.getByNumber(outTradeNo);
  14.         // 根据订单id更新订单的状态、支付方式、支付状态、结账时间
  15.         Orders orders = Orders.builder()
  16.                 .id(ordersDB.getId())
  17.                 .status(Orders.TO_BE_CONFIRMED)
  18.                 .payStatus(Orders.PAID)
  19.                 .checkoutTime(LocalDateTime.now())
  20.                 .build();
  21.         orderMapper.update(orders);
  22.         // 通过webscoket向客户端浏览器推送消息
  23.         Map map = new HashMap();
  24.         map.put("type", 1); // 1:来单提醒, 2:客户催单
  25.         map.put("orderId", ordersDB.getId());
  26.         map.put("content", "订单号:" + outTradeNo);
  27.         String json = JSON.toJSONString(map);
  28.         webSocketServer.sendToAllClient(json);
  29.     }
  30. }
复制代码

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





交互说明: 客户端的websocket哀求也是颠末nginx服务器进行的代理转发




客户催单

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



流程分析

  • 通过WebSocket实现管理端页面和服务端的长连接
  • 客户点击催单按钮后, 发起催单哀求, 服务端收到哀求后, 通过WebSocket, 推送消息给管理端页面
  • 管理端页面拿到消息后, 进行相应的消息提示和语言播报
  • 约定服务端发送给管理端页面的数据格式为JSON


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

接口计划




代码实现
  1. @RestController("userOrderController")
  2. @RequestMapping("/user/order")
  3. @Slf4j
  4. @Api(tags = "用户端订单相关接口")
  5. public class OrderController {
  6.     @Autowired
  7.     private OrderService orderService;
  8.     /**
  9.      * 客户催单
  10.      */
  11.     @GetMapping("/reminder/{id}")
  12.     @ApiOperation("客户催单")
  13.     public Result reminder(@PathVariable Long id) {
  14.         log.info("订单id:{}", id);
  15.         orderService.reminder(id);
  16.         return Result.success();
  17.     }
  18. }
复制代码
  1. public interface OrderService {
  2.     /**
  3.      * 客户催单
  4.      * @param id
  5.      */
  6.     void reminder(Long id);
  7. }
复制代码
  1. @Service
  2. @Slf4j
  3. public class OrderServiceImpl implements OrderService {
  4.     @Autowired
  5.     private OrderMapper orderMapper;
  6.     @Autowired
  7.     private WebSocketServer webSocketServer;
  8.    
  9.     /**
  10.      * 客户催单
  11.      *
  12.      * @param id
  13.      */
  14.     public void reminder(Long id) {
  15.         // 根据id查询订单
  16.         Orders ordersDB = orderMapper.getById(id);
  17.         // 校验订单是否存在
  18.         if (ordersDB == null) {
  19.             throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR);
  20.         }
  21.         Map map = new HashMap();
  22.         map.put("type", 2); // 1表示来单提醒, 2表示客户催单
  23.         map.put("orderId", id);
  24.         map.put("content", "订单号:" + ordersDB.getNumber());
  25.         webSocketServer.sendToAllClient(JSON.toJSONString(map));
  26.     }
  27. }
复制代码

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





免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

金歌

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表