java后端+vue前端如何完成一个websocket

1、websocket介绍

      WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket通信协议于2011年被IETF定为标准RFC 6455,并由RFC7936补充规范。WebSocket API也被W3C定为标准。

WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

2、java中安装websocket依赖    

<!--        引入websocket-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>

3、java定义实体类

@Data
public class WebSocketDto {

    private int code;

    private String message;

    private String timestamp;
}

4、java定义filter配置类与SessionHandler过滤类

@Slf4j
public class SessionHandlerFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        log.info("SessionHandler过滤器初始化成功");
    }

    @Override
    public void destroy() {
        log.info("SessionHandler过滤器销毁成功");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpSession session = request.getSession();
        session.setAttribute("clientIp", request.getRemoteAddr());
        filterChain.doFilter(request, servletResponse);
    }
}

@Configuration
public class FilterConfig {

    @Bean("SessionHandlerFilter")
    public FilterRegistrationBean getSessionHandlerFilterBean(){
        FilterRegistrationBean bean = new FilterRegistrationBean();
        bean.setFilter(new SessionHandlerFilter());
        bean.addUrlPatterns("/websocket/*","/serverWebsocket/*");
        return bean;
    }
}

5、java定义websocketconfig类与websocket使用类

public class WebSocketServerConfigurator extends ServerEndpointConfig.Configurator {

    @Override
    public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response){
        HttpSession httpSession = (HttpSession) request.getHttpSession();
        if(httpSession!=null){
            Map<String, Object> userProperties = sec.getUserProperties();
            // 存入httpSession
            userProperties.put(HttpSession.class.getName(),httpSession);
        }
    }

}

@Component
@Slf4j
@ServerEndpoint(value = "/xxx/{xxx}",configurator = WebSocketServerConfigurator.class)
public class ServerWebSocket {
    /**
     * 线程安全无序的集合
     */
    private static final CopyOnWriteArraySet<Session> SESSIONS = new CopyOnWriteArraySet<>();

    /**
     * 存储在线连接数
     */
    private static final ConcurrentHashMap<String,Session> SESSION_POOL = new ConcurrentHashMap<>();

    @OnOpen
    public void onOpen(Session session, @PathParam(value = "userId") String userId){
        try {
            HttpSession httpSession = (HttpSession) session.getUserProperties().get(HttpSession.class.getName());
            String remoteAddr = (String) httpSession.getAttribute("clientIp");
            String poolKey = userId;
            if(StringUtils.isNotEmpty(remoteAddr)){
                poolKey = userId + "_" + remoteAddr;
            }
            SESSIONS.add(session);
            SESSION_POOL.put(poolKey,session);
            log.info("【WebSocket消息】有新的连接{},总数为:{}", poolKey, SESSIONS.size());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @OnClose
    public void onClose(Session session){
        try {
            SESSIONS.remove(session);
            log.info("【WebSocket】连接断开,总数为:"+SESSIONS.size());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @OnMessage
    public void onMessage(String message){
        log.info("【WebSocket】收到客户端消息:"+message);
    }

    /**
     * 此为广播消息
     * @param message
     */
    public synchronized void sendAllMessage(String message){
        // 这是给前端发送通讯的位置
        for (Session session : SESSIONS) {
            try {
                if(session.isOpen()){
                    session.getBasicRemote().sendText(message);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}

6、前端代码实现

initWebSocket() {
      const _this = this;
      if (typeof (WebSocket) === 'undefined') {
        _this.message.error('您的浏览器不支持WebSocket,无法获取数据')
        return false
      }

      // ws请求完整地址
      const requstWsUrl = this.wsUrl
      websock = new WebSocket(requstWsUrl)

      websock.onmessage = function initWebSocket(e) {
        _this.websocketonmessage(e)
      }
      websock.onopen = function initWebSocket() {
        _this.websocketOpen()
      }
      websock.onerror = function initWebSocket() {
        _this.message.error('ws连接异常,请稍候重试')
        _this.errorCallback()
      }
      websock.onclose = function initWebSocket(e) {
        this.websocketclose(e)
      }
    },

7、websocket的踩坑事项

        使用websocket的时候,要注意与http同时请求,假设http一直在请求可能会出现websocket长连接失效的问题,等到我找到一个合适的解决方案再补全。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值