解决spring+websocket开启多个页面

483 阅读2分钟

前言

众所周知,最近我在做物联网的项目,还不知道的话,可以看我这篇, 能帮我点个赞就更好了

出现了个问题

服务端开启webSocket服务,前端通过new WebSocket(ws://ip:port/webSocket/aa)来连接。具体的就不赘述了,网上一搜一大把。

服务端拿到数据后,使用websocket传给前端

//给指定用户发送信息
public void sendInfo(String userName, String message){
    Session session = sessionPools.get(userName);
    try {
        sendMessage(session, message);
    }catch (Exception e){
        e.printStackTrace();
    }
}

前端的链接是www.xxxxx.com/iot。单个页面时,webSocket的连接、接收是正常的。但是,如果打开了多个页面,我惊奇的发现,只有最后一个打开的页面,接收到了webSocket消息,并且,在之前页面中socket的onerror和onclose都没有触发。然后我就查找webSocket服务代码。

//建立连接成功调用
    @OnOpen
    public void onOpen(Session session, @PathParam(value = "sid") String userName){
        sessionPools.put(userName, session);
        addOnlineCount();
    }

原来是新连接上的页面session覆盖了之前key为userName的值。
找到了问题,那就好办了,只要把userName映射的值,从单个的session变成多个,然后在发送数据时,循环取出后发送消息。 1、创建一个List用来存放session。

private static List<Session> sessionList = Collections.synchronizedList(new ArrayList<>());

2、ConcurrentHashMap中存放Session的List

private static ConcurrentHashMap<String, List<Session>> sessionPools = new ConcurrentHashMap<>();

3、连接时,将客户端的session存入sessionList中

@OnOpen
public void onOpen(Session session, @PathParam(value = "sid") String userName){
    sessionList.add(session);
    sessionPools.put(userName, sessionList);
}

4、发送消息时,将session集取出

/**
 * 给指定用户发送信息
 * @param userName
 * @param message
 */
public void sendInfo(String userName, String message){
    sessionList = sessionPools.get(userName);
    try {
        if(sessionList != null && !sessionList.isEmpty()){
            for(Session session:sessionList){
                if(session.isOpen()){
                    sendMessage(session, message);
                }
            }
        }
    }catch (Exception e){
        e.printStackTrace();
    }
}

5、当然,在客户端关闭连接时,要在sessionList中去掉

/**
     * 关闭连接时调用
     * @param userName
     */
    @OnClose
    public void onClose(Session session, @PathParam(value = "sid") String userName){
        sessionList.remove(session);
        subOnlineCount();
    }

总结

最终是依靠客户端连接时的session来决定webSocket发送消息的方向来解决了这一问题。
webSocket在服务端和客户端传送消息时是比较常用的方法。在物联网项目中,如果服务端有安装mqtt的话,也可以选择mqtt订阅的模式比较方便。