不想努力的程序员 2022-04-04 16:28 采纳率: 50.8%
浏览 188
已结题

springboot+vue整合webscoket时,总是调用onclos()方法,这是咋回事

springboot整合webscoket时写了一个service,代码如下:

package com.xjc.leleservice.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.xjc.common.client.WebSocketClient;
import com.xjc.common.untils.RedisUtils;
import com.xjc.entity.OrderList;
import com.xjc.leleservice.OrderListService;
import com.xjc.vo.AdminOrderManagerVO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author bill
 * @ClassName WebSocketService
 * @Describe
 * @Date 2022/4/1 15:00
 **/

@ServerEndpoint(value = "/websocket/{orderId}")
@Component
public class WebSocketService {
    private static final Logger log = LoggerFactory.getLogger(WebSocketService.class);

    //静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
    private static int onlineCount = 0;
    //concurrent包的线程安全Set,用来存放每个客户端对应的WebSocketServer对象。
    private static ConcurrentHashMap<String, WebSocketClient> webSocketMap = new ConcurrentHashMap<>();

    /**与某个客户端的连接会话,需要通过它来给客户端发送数据*/
    private Session session;
    /**接收orderId*/
    private String orderId="";
    @Autowired
    private RedisUtils redisUtils;

    /**
     * 连接建立成功调用的方法*/
    @OnOpen
    public void onOpen(Session session, @PathParam("orderId") String orderId) {
        if(!webSocketMap.containsKey(orderId))
        {
            addOnlineCount(); // 订单数 +1
        }
        this.session = session;
        this.orderId= orderId;
        WebSocketClient client = new WebSocketClient();
        client.setSession(session);

        client.setUri(session.getRequestURI().toString());


        webSocketMap.put(orderId, client);
        log.info("----------------------------------------------------------------------------");
        log.info("订单:"+orderId+",当前订单数:" + getOnlineCount());
         sendMessage("1","有新订单了");

    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        log.info("你好性感");
        if(webSocketMap.containsKey(orderId)){
            webSocketMap.remove(orderId);
            if(webSocketMap.size()>0)
            {
                //从set中删除
                subOnlineCount();
            }
        }
        log.info("----------------------------------------------------------------------------");
        log.info(orderId+"用户退出,当前在线人数为:" + getOnlineCount());
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息*/
    @OnMessage
    public void onMessage(String message, Session session) {
        log.info("收到新的订单:"+orderId+",报文:"+message);
        //可以群发消息
        //消息保存到数据库、redis
        if(StringUtils.isNotBlank(message)){

        }
    }

    /**
     *
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("用户错误:"+this.orderId+",原因:"+error.getMessage());
        error.printStackTrace();
    }

    /**
     * 连接服务器成功后主动推送
     */
    public void sendMessage(String message) throws IOException {
        System.out.println(message);
        synchronized (session){
            this.session.getBasicRemote().sendText(message);
        }
    }

    /**
     * 向指定客户端发送消息
     * @param orderId
     * @param message
     */
    public void sendMessage(String orderId,String message){
        try {
            if (StringUtils.isEmpty(orderId)) {
                throw new IOException("后台错误,请联系管理员");
            }

            WebSocketClient webSocketClient = webSocketMap.get(orderId);
           
            if(webSocketClient!=null){
                webSocketClient.getSession().getBasicRemote().sendText(message);
            }

        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        }
    }


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

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

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

    public static void setOnlineCount(int onlineCount) {
        WebSocketService.onlineCount = onlineCount;
    }


    public static ConcurrentHashMap<String, WebSocketClient> getWebSocketMap() {
        return webSocketMap;
    }

    public static void setWebSocketMap(ConcurrentHashMap<String, WebSocketClient> webSocketMap) {
        WebSocketService.webSocketMap = webSocketMap;
    }

    public Session getSession() {
        return session;
    }

    public void setSession(Session session) {
        this.session = session;
    }

    public String getOrderId() {
        return orderId;
    }

    public void setOrderId(String orderId) {
        this.orderId = orderId;
    }
}


前端vue封装了一下websocket,如下




export function  useWebSocket(handleMessage){
    console.log(265235)

    const ws = new WebSocket('ws://localhost:2000/websocket/1')
    const init = () => {
        bindEvent()
    }
    function bindEvent(){
        ws.addEventListener('open',handleOpen,false)
        ws.addEventListener('close',handleClose,false)
        ws.addEventListener('error',handleError,false)
        ws.addEventListener('message',handleMessage,false)
        function handleOpen(e) {
            console.log('handleOpen'+e)
        }
        function handleClose(e) {
            console.log('handleClose'+e)
        }
        function handleError(e) {
            console.log('handleError'+e)
        }
        console.log(2652321325)
        init()

    }
    return ws
}

在页面调用如下图

img

第一次打开页面时没有调用onclose,但是第二次访问时onclose被调用了,这是咋回事

  • 写回答

1条回答 默认 最新

  • heling_m6ss 2022-04-04 18:50
    关注

    onclose 说明后端没有问题。是前端关闭了websocket 的连接 造成的 排查你的前端代码。 还有就是连接上了再次发送消息不要去刷新页面。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

问题事件

  • 系统已结题 4月12日
  • 已采纳回答 4月4日
  • 创建了问题 4月4日

悬赏问题

  • ¥15 镍氢电池充电器设计实物使用原理
  • ¥15 逻辑谓词和消解原理的运用
  • ¥15 三菱伺服电机按启动按钮有使能但不动作
  • ¥15 js,页面2返回页面1时定位进入的设备
  • ¥50 导入文件到网吧的电脑并且在重启之后不会被恢复
  • ¥15 (希望可以解决问题)ma和mb文件无法正常打开,打开后是空白,但是有正常内存占用,但可以在打开Maya应用程序后打开场景ma和mb格式。
  • ¥20 ML307A在使用AT命令连接EMQX平台的MQTT时被拒绝
  • ¥20 腾讯企业邮箱邮件可以恢复么
  • ¥15 有人知道怎么将自己的迁移策略布到edgecloudsim上使用吗?
  • ¥15 错误 LNK2001 无法解析的外部符号