百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

java SSM框架搭建微信小程序webSocket长连接(webSocket传参)

toyiye 2024-08-17 00:13 11 浏览 0 评论

最近的项目有个功能点: 商户端需要扫描用户端的二维码, 扫描结果要展示给商户和用户端.

商户端的提示比较好处理, 根据接口返回数据进行展示就可以, 稍微麻烦的是用户被扫的提示.

解决方案有两种:

1.用户端进行循环查询,每2秒进行一次接口查询,接口有数据时,根据数据展示;

2.用户端使用webSocket与服务器进行长连接,有返回数据时再进行提示.

两种方式都有实现,简单说明一下1方式的实现, 本篇着重介绍2方式的实现

  • 轮询实现方式
  1. 商户扫码,判断二维码信息的合法性, 合法进行扣款;
  2. 扣款的同时在redis里存储一条记录, key是用户的标识, value是需要返回给用户的消息;
  3. 用户端轮询redis中的数据, 返回数据时提示用户扣款结果.

这种方式对服务器的资源占用较大(仅做说明)

  • webSocket实现方式
  1. 用户进入二维码扫码界面,与服务器建立webSocket连接, 服务端用map存储, key: 用户标识 value: session;
  2. 商户扫码后, 在map中查找用户的session, 向用户发送消息;
  3. 前端接收到webSocket的信息后, 进行相应的展示.

nginx配置

小程序的webSocket是https协议, 我们项目使用的是nginx转发, 需要配置nginx, 贴一下nginx配置,

如果不配置nginx的upgrade协议, wss请求会报错:Error during WebSocket handshake: Unexpected response code: 400

location /webSocket/ {} 中的webSocket根据自己websocket的注解进行更改


  1. map $http_upgrade $connection_upgrade {
  2. default upgrade;
  3. '' close;
  4. }
  5. server {
  6. listen 443 ssl;
  7. server_name 你的域名;
  8. ssl on;
  9. ssl_certificate cert/你的ssl pem.pem;
  10. ssl_certificate_key cert/你的ssl key.key;
  11. ssl_session_timeout 5m;
  12. ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
  13. ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
  14. ssl_prefer_server_ciphers on;
  15. location / {
  16. proxy_pass http://127.0.0.1:8089;
  17. }
  18. location /webSocket/ {
  19. proxy_pass http://127.0.0.1:8089;
  20. proxy_http_version 1.1;
  21. proxy_set_header Upgrade $http_upgrade;
  22. proxy_set_header Connection $connection_upgrade;
  23. }
  24. }

maven依赖


  1. <dependency>
  2. <groupId>javax</groupId>
  3. <artifactId>javaee-api</artifactId>
  4. <version>7.0</version>
  5. <scope>provided</scope>
  6. </dependency>

webSocket 文件

webSocket的路径中包含了用户标识{userId}和{carwashId}, 这个方法也是借鉴大神的,没有找到出处了, 就没注明啦


  1. import com.carwash.util.ValidatorUtil;
  2. import javax.websocket.*;
  3. import javax.websocket.server.PathParam;
  4. import javax.websocket.server.ServerEndpoint;
  5. import java.io.IOException;
  6. import java.util.concurrent.ConcurrentHashMap;
  7. /**
  8. * @ServerEndpoint 注解是一个类层次的注解,它的功能主要是将目前的类定义成一个websocket服务器端,
  9. * 注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端
  10. */
  11. @ServerEndpoint("/webSocket/{userId}/{carwashId}")
  12. public class WebSocketTest {
  13. //静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
  14. private static int onlineCount = 0;
  15. //concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。若要实现服务端与单一客户端通信的话,可以使用Map来存放,其中Key可以为用户标识
  16. private static ConcurrentHashMap<String, WebSocketTest> webSocketSet = new ConcurrentHashMap<String, WebSocketTest>();
  17. //与某个客户端的连接会话,需要通过它来给客户端发送数据
  18. private Session session;
  19. private String userIdCarwashId;
  20. /**
  21. * 连接建立成功调用的方法
  22. * @param session 可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据
  23. */
  24. @OnOpen
  25. public void onOpen(Session session, @PathParam("userId") Integer userId, @PathParam("carwashId") Integer carwashId){
  26. this.session = session;
  27. this.userIdCarwashId = userId + "_" + carwashId;
  28. webSocketSet.put(userIdCarwashId, this); //加入set中
  29. addOnlineCount(); //在线数加1
  30. System.out.println("有新连接加入!当前在线人数为" + getOnlineCount());
  31. }
  32. /**
  33. * 连接关闭调用的方法
  34. */
  35. @OnClose
  36. public void onClose(){
  37. webSocketSet.remove(this.userIdCarwashId); //从set中删除
  38. subOnlineCount(); //在线数减1
  39. System.out.println("有一连接关闭!当前在线人数为" + getOnlineCount());
  40. }
  41. /**
  42. * 收到客户端消息后调用的方法
  43. * @param message 客户端发送过来的消息
  44. * @param session 可选的参数
  45. */
  46. @OnMessage
  47. public void onMessage(String message, Session session) {
  48. // System.out.println("来自客户端的消息:" + message);
  49. // //群发消息
  50. // for(WebSocketTest item: webSocketSet){
  51. // try {
  52. // item.sendMessage(message);
  53. // } catch (IOException e) {
  54. // e.printStackTrace();
  55. // continue;
  56. // }
  57. // }
  58. }
  59. /**
  60. * 发生错误时调用
  61. * @param session
  62. * @param error
  63. */
  64. @OnError
  65. public void onError(Session session, Throwable error){
  66. System.out.println("发生错误");
  67. error.printStackTrace();
  68. }
  69. /**
  70. * 这个方法与上面几个方法不一样。没有用注解,是根据自己需要添加的方法。
  71. * @param message
  72. * @throws IOException
  73. */
  74. public static void sendMessage(String userIdCarwashId, String message) throws IOException{
  75. System.out.println("当前在线用户数量: " + webSocketSet.size());
  76. WebSocketTest userSocket = webSocketSet.get(userIdCarwashId);
  77. if(ValidatorUtil.isNotNull(userSocket)) {
  78. userSocket.session.getBasicRemote().sendText(message);
  79. }
  80. //this.session.getAsyncRemote().sendText(message);
  81. }
  82. public static synchronized int getOnlineCount() {
  83. return onlineCount;
  84. }
  85. public static synchronized void addOnlineCount() {
  86. WebSocketTest.onlineCount++;
  87. }
  88. public static synchronized void subOnlineCount() {
  89. WebSocketTest.onlineCount--;
  90. }
  91. }

还需要在springMvc.xml中增加包扫描

<context:component-scan base-package="com.carwash.websocket" />

调用发送消息的方法为

WebSocketTest.sendMessage(QRUserId + "_" + QRCarwashId, "0_扣费成功_剩余次数: " + restNumber);


小程序调试

在这里贴一下小程序的调试代码

websocket.wxml


  1. <!--pages/websocket/websocket.wxml-->
  2. <view class="page">
  3. <view class="page__hd">
  4. </view>
  5. <view class="page__bd">
  6. <button bindtap="connectWebsocket" type="primary">连接websocket</button>
  7. </view>
  8. </view>

websocket.js


  1. // pages/websocket/websocket.js
  2. Page({
  3. /**
  4. * 页面的初始数据
  5. */
  6. data: {
  7. },
  8. connectWebsocket: function () {
  9. wx.connectSocket({
  10. url: 'wss://你的域名/webSocket/17/2',
  11. data: {
  12. x: '1',
  13. y: '22'
  14. },
  15. header: {
  16. 'content-type': 'application/json'
  17. },
  18. method: "GET"
  19. })
  20. wx.onSocketOpen(function (res) {
  21. console.log('WebSocket连接已打开!')
  22. })
  23. wx.onSocketError(function (res) {
  24. console.log(res)
  25. console.log('WebSocket连接打开失败,请检查!')
  26. })
  27. wx.onSocketMessage(function (res) {
  28. console.log('收到服务器内容:' + res.data)
  29. })
  30. }
  31. })

商户扫码后的结果

到这里就大功告成了, 如有疑问可以留言

相关推荐

# Python 3 # Python 3字典Dictionary(1)

Python3字典字典是另一种可变容器模型,且可存储任意类型对象。字典的每个键值(key=>value)对用冒号(:)分割,每个对之间用逗号(,)分割,整个字典包括在花括号({})中,格式如...

Python第八课:数据类型中的字典及其函数与方法

Python3字典字典是另一种可变容器模型,且可存储任意类型对象。字典的每个键值...

Python中字典详解(python 中字典)

字典是Python中使用键进行索引的重要数据结构。它们是无序的项序列(键值对),这意味着顺序不被保留。键是不可变的。与列表一样,字典的值可以保存异构数据,即整数、浮点、字符串、NaN、布尔值、列表、数...

Python3.9又更新了:dict内置新功能,正式版十月见面

机器之心报道参与:一鸣、JaminPython3.8的热乎劲还没过去,Python就又双叒叕要更新了。近日,3.9版本的第四个alpha版已经开源。从文档中,我们可以看到官方透露的对dic...

Python3 基本数据类型详解(python三种基本数据类型)

文章来源:加米谷大数据Python中的变量不需要声明。每个变量在使用前都必须赋值,变量赋值以后该变量才会被创建。在Python中,变量就是变量,它没有类型,我们所说的"类型"是变...

一文掌握Python的字典(python字典用法大全)

字典是Python中最强大、最灵活的内置数据结构之一。它们允许存储键值对,从而实现高效的数据检索、操作和组织。本文深入探讨了字典,涵盖了它们的创建、操作和高级用法,以帮助中级Python开发...

超级完整|Python字典详解(python字典的方法或操作)

一、字典概述01字典的格式Python字典是一种可变容器模型,且可存储任意类型对象,如字符串、数字、元组等其他容器模型。字典的每个键值key=>value对用冒号:分割,每个对之间用逗号,...

Python3.9版本新特性:字典合并操作的详细解读

处于测试阶段的Python3.9版本中有一个新特性:我们在使用Python字典时,将能够编写出更可读、更紧凑的代码啦!Python版本你现在使用哪种版本的Python?3.7分?3.5分?还是2.7...

python 自学,字典3(一些例子)(python字典有哪些基本操作)

例子11;如何批量复制字典里的内容2;如何批量修改字典的内容3;如何批量修改字典里某些指定的内容...

Python3.9中的字典合并和更新,几乎影响了所有Python程序员

全文共2837字,预计学习时长9分钟Python3.9正在积极开发,并计划于今年10月发布。2月26日,开发团队发布了alpha4版本。该版本引入了新的合并(|)和更新(|=)运算符,这个新特性几乎...

Python3大字典:《Python3自学速查手册.pdf》限时下载中

最近有人会想了,2022了,想学Python晚不晚,学习python有前途吗?IT行业行业薪资高,发展前景好,是很多求职群里严重的香饽饽,而要进入这个高薪行业,也不是那么轻而易举的,拿信工专业的大学生...

python学习——字典(python字典基本操作)

字典Python的字典数据类型是基于hash散列算法实现的,采用键值对(key:value)的形式,根据key的值计算value的地址,具有非常快的查取和插入速度。但它是无序的,包含的元素个数不限,值...

324页清华教授撰写【Python 3 菜鸟查询手册】火了,小白入门字典

如何入门学习python...

Python3.9中的字典合并和更新,了解一下

全文共2837字,预计学习时长9分钟Python3.9正在积极开发,并计划于今年10月发布。2月26日,开发团队发布了alpha4版本。该版本引入了新的合并(|)和更新(|=)运算符,这个新特性几乎...

python3基础之字典(python中字典的基本操作)

字典和列表一样,也是python内置的一种数据结构。字典的结构如下图:列表用中括号[]把元素包起来,而字典是用大括号{}把元素包起来,只不过字典的每一个元素都包含键和值两部分。键和值是一一对应的...

取消回复欢迎 发表评论:

请填写验证码