springboot2.0 集成WebSocket(服务端实时向客户端发送信息)

     WebSocket为浏览器和服务端提供了双工异步通信功能。即浏览器可以向服务端发送消息,服务端也可以向浏览器发送消息。

    应用于web项目中,多数情况前端需要实时的数据获取。即服务端向客户端实时的发送消息。

操作步骤如下:

项目目录如下:


1、运用IDE新建一个springboot项目,勾选Web、WebSocket、Thymeleaf等依赖如下图:


2、编写前端页面(客户端)与后台(服务端)通信握手拦截器。此处可记录当前建立连接的用户信息,用于定向信息发送的动能前提。代码如下

package com.example.websocket_springboot.config.websocket;

import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;

import java.util.Map;

/**
 * @description 前端页面与后台通信握手拦截器,可用于完善定向发送信息功能。
 * @author jane
 */
@Component
public class HandshakeInterceptor extends HttpSessionHandshakeInterceptor {

    @Override
    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
                                   Map<String, Object> attributes) throws Exception {
        //此处可将用户信息放入WebSocketSession的属性当中,以便定向发送消息。
        attributes.put("WEBSOCKET_USERID",1L);
        return true;
    }
    @Override
    public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
                               Exception ex) {
        super.afterHandshake(request, response, wsHandler, ex);
    }
}
3、编写WebSocket配置类,比如绑定客户端端点url

package com.example.websocket_springboot.config.websocket;

import com.example.websocket_springboot.handler.DemoHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;

/**
 * @description webSocket配置类,绑定前端连接端点url及其他信息
 * @author jane
 */
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {

    @Autowired
    private DemoHandler demoHandler;

    @Autowired
    private HandshakeInterceptor handshakeInterceptor;
    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        //绑定前端连接端点url
       registry.addHandler(demoHandler, "/webSocket/demo").addInterceptors(handshakeInterceptor).withSockJS();
    }
}

4、自定义实现WebSocket处理类

package com.example.websocket_springboot.handler;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.*;

import java.util.ArrayList;

/**
 * @description webSocket处理类
 * @author jane
 */
@Component
public class DemoHandler implements WebSocketHandler {

    private static final Logger logger = LoggerFactory.getLogger(DemoHandler.class);

    private static final ArrayList<WebSocketSession> users;

    static {
        users = new ArrayList<>();
    }

    @Override
    public void afterConnectionEstablished(WebSocketSession webSocketSession) throws Exception {
        logger.info("系统WebSocket连接已建立!");
        //此处可添加客户端接收用户
        logger.info(webSocketSession.getAttributes().get("WEBSOCKET_USERID").toString());
        users.add(webSocketSession);
    }

    /**
     * 给指定用户发送信息
     * @param webSocketSession
     * @param webSocketMessage
     * @throws Exception
     */
    @Override
    public void handleMessage(WebSocketSession webSocketSession, WebSocketMessage<?> webSocketMessage) throws Exception {

        //获取指定用户ID
        Long userId = (Long) webSocketSession.getAttributes().get("WEBSOCKET_USERID");
        String message;
        logger.info("处理推送的消息");
        //判断客户端是否消息发送,不需要客户端与客户端的单向通信,此处可省略。
        if (!webSocketMessage.getPayload().equals("undefined")){
            message = "client 发送的消息为:" + webSocketMessage.getPayload();
        }else {
            message = "推送测试信息 ---" + System.currentTimeMillis();
        }
        sendMessageToUser(userId, new TextMessage(message));
    }

    @Override
    public void handleTransportError(WebSocketSession webSocketSession, Throwable throwable) throws Exception {
        if (webSocketSession.isOpen()) {
            webSocketSession.close();
        }
        logger.error("系统WebSocket传输错误,连接关闭!用户ID" + webSocketSession.getAttributes().get("WEBSOCKET_USERID"), throwable);
        //移除异常用户信息
        users.remove(webSocketSession);
    }

    @Override
    public void afterConnectionClosed(WebSocketSession webSocketSession, CloseStatus closeStatus) throws Exception {

    }

    @Override
    public boolean supportsPartialMessages() {
        return false;
    }

    public void sendMessageToUser(Long userId, TextMessage message) {
        logger.info("发送消息至用户!");
        for (WebSocketSession user : users) {
            if (user.getAttributes().get("WEBSOCKET_USERID").equals(userId)) {
                sendSocketSessionMsg(user, message);
            }
        }
    }

    /**
     * 发送消息
     * @param user 接收用户
     * @param message 消息
     */
    private boolean sendSocketSessionMsg(WebSocketSession user, TextMessage message) {
        String msg = message.getPayload();
        boolean sendSuccess = true;
        try {
            if (user.isOpen()) {
                synchronized (user) {
                    user.sendMessage(message);
                }
            } else {
                logger.error("WebSocket连接未打开,系统消息推送失败:" + msg);
                sendSuccess = false;
            }
        } catch (Exception e) {
            logger.error("系统消息推送失败:" + msg, e);
            sendSuccess = false;
        }
        return sendSuccess;
    }


}

5、配置MVC页面访问的配置类

package com.example.websocket_springboot.config.mvc;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * @description 配置MVC页面访问
 * @author jane
 */
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    /**
     * 设置页面访问
     * @param registry
     */
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/demo").setViewName("/demo");
    }

    /*    *//**
     * 配置静态访问资源
     * @param registry
     *//*
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/**").addResourceLocations("classpath:/static/");
    }*/
}

6、前端添加demo.html页面,代码如下:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" >
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>测试webSocket</title>
</head>
<body>
<div>消息</div>
<div id="message"></div>
<div>
    <input id="msg">
    <button οnclick="sendMsg()">发送消息</button>
</div>
</body>
<script th:src="@{../static/plugins/sockjs.min.js}"></script>
<script th:src="@{../static/plugins/jquery.min.js}"></script>
<script th:src="@{../static/js/demo.js}"></script>
</html>

js文件如下:

var webSocket= null;
$(function() {
    test();
});
function test() {
    webSocket = new SockJS("/webSocket/demo");
    webSocket.onopen = function () {
        webSocket.send();
    };
    webSocket.onmessage = function (e) {
        if (e.data) {
            var data = e.data;
            $("#message").text(data);
        }

    };
    webSocket.onclose = function () {
        console.log('close run status socket');
    };

    webSocket.onerror = function () {
        console.error("链接出现异常,请检查服务器是否正常运行");
    };
}

function sendMsg() {
    if (webSocket.readyState == SockJS.OPEN){
        var msg = $("#msg").val();
        webSocket.send(msg);
    }else {
        alert("连接失败!")
    }
}

自行添加sockjs.min.js和jquery.min.js前端脚本。



  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值