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

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

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

解决方案有两种:

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的注解进行更改

    map $http_upgrade $connection_upgrade {
        default upgrade;
        ''      close;
    }

    server {
    listen 443 ssl;
    server_name 你的域名;
    ssl on;
    ssl_certificate   cert/你的ssl pem.pem;
    ssl_certificate_key  cert/你的ssl key.key;
    ssl_session_timeout 5m;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
    location / {
        proxy_pass   http://127.0.0.1:8089;
    }
    location /webSocket/ {
            proxy_pass http://127.0.0.1:8089;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection $connection_upgrade;
        }

}

maven依赖

        <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-api</artifactId>
            <version>7.0</version>
            <scope>provided</scope>
        </dependency>

webSocket 文件

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

import com.carwash.util.ValidatorUtil;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @ServerEndpoint 注解是一个类层次的注解,它的功能主要是将目前的类定义成一个websocket服务器端,
 * 注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端
 */
@ServerEndpoint("/webSocket/{userId}/{carwashId}")
public class WebSocketTest {
    //静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
    private static int onlineCount = 0;

    //concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。若要实现服务端与单一客户端通信的话,可以使用Map来存放,其中Key可以为用户标识
    private static ConcurrentHashMap<String, WebSocketTest> webSocketSet = new ConcurrentHashMap<String, WebSocketTest>();

    //与某个客户端的连接会话,需要通过它来给客户端发送数据
    private Session session;
    private String userIdCarwashId;

    /**
     * 连接建立成功调用的方法
     * @param session  可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("userId") Integer userId, @PathParam("carwashId") Integer carwashId){
        this.session = session;
        this.userIdCarwashId = userId + "_" + carwashId;
        webSocketSet.put(userIdCarwashId, this);     //加入set中
        addOnlineCount();           //在线数加1
        System.out.println("有新连接加入!当前在线人数为" + getOnlineCount());
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose(){
        webSocketSet.remove(this.userIdCarwashId);  //从set中删除
        subOnlineCount();           //在线数减1
        System.out.println("有一连接关闭!当前在线人数为" + getOnlineCount());
    }

    /**
     * 收到客户端消息后调用的方法
     * @param message 客户端发送过来的消息
     * @param session 可选的参数
     */
    @OnMessage
    public void onMessage(String message, Session session) {
//        System.out.println("来自客户端的消息:" + message);
//        //群发消息
//        for(WebSocketTest item: webSocketSet){
//            try {
//                item.sendMessage(message);
//            } catch (IOException e) {
//                e.printStackTrace();
//                continue;
//            }
//        }
    }

    /**
     * 发生错误时调用
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error){
        System.out.println("发生错误");
        error.printStackTrace();
    }

    /**
     * 这个方法与上面几个方法不一样。没有用注解,是根据自己需要添加的方法。
     * @param message
     * @throws IOException
     */
    public static void sendMessage(String userIdCarwashId, String message) throws IOException{
        System.out.println("当前在线用户数量: " + webSocketSet.size());
        WebSocketTest userSocket = webSocketSet.get(userIdCarwashId);
        if(ValidatorUtil.isNotNull(userSocket)) {
            userSocket.session.getBasicRemote().sendText(message);
        }
        //this.session.getAsyncRemote().sendText(message);
    }

    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
        WebSocketTest.onlineCount++;
    }

    public static synchronized void subOnlineCount() {
        WebSocketTest.onlineCount--;
    }
}

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

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

调用发送消息的方法为

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

小程序调试

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

websocket.wxml

<!--pages/websocket/websocket.wxml-->
<view class="page">
  <view class="page__hd">
  </view>
  <view class="page__bd">

  <button bindtap="connectWebsocket" type="primary">连接websocket</button>

  </view>
</view>

websocket.js

// pages/websocket/websocket.js
Page({

  /**
   * 页面的初始数据
   */
  data: {

  },
  connectWebsocket: function () {
    wx.connectSocket({
      url: 'wss://你的域名/webSocket/17/2',
      data: {
        x: '1',
        y: '22'
      },
      header: {
        'content-type': 'application/json'
      },
      method: "GET"
    })
    wx.onSocketOpen(function (res) {
      console.log('WebSocket连接已打开!')
    })
    wx.onSocketError(function (res) {
      console.log(res)
      console.log('WebSocket连接打开失败,请检查!')
    })
    wx.onSocketMessage(function (res) {
      console.log('收到服务器内容:' + res.data)
    })
  }
})

商户扫码后的结果

到这里就大功告成了, 如有疑问可以留言或者私信我.

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值