java springboot webSocket

        springboot 中 webSocket 学习记录

依赖

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

添加 websocket 配置类

@Configuration
@EnableWebSocket // 开启 WebSocket 支持
public class WebSocketConfig {
    /**
     * 必须要有的
     *
     * @return serverEndpointExporter
     */
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }

    /**
     * WebSocket 配置信息
     *
     * @return servletServerContainerFactoryBean
     */
    @Bean
    public ServletServerContainerFactoryBean createWebSocketContainer() {
        ServletServerContainerFactoryBean bean = new ServletServerContainerFactoryBean();

        // 文本缓冲区大小
        bean.setMaxTextMessageBufferSize(8192);
        // 字节缓冲区大小
        bean.setMaxBinaryMessageBufferSize(8192);

        return bean;
    }
}

需求代码

        注意路径放行,特别是使用 Spring Security 或 Shiro,很容易遗忘放行请求路径

@Component
@ServerEndpoint("/websocket")
public class BaseWebSocket {
    Logger logger = LoggerFactory.getLogger(this.getClass());

    // ConcurrentHashMap, 保证线程安全, static全局共享 session
    // 这里之所以static,是因为这个类不是单例的!!
    // 它虽然有@Controller注解,但是不适用Ioc容器中拿对象,每一次请求过来都是一个新的对象
      /**
     * 存放 session
     */
    public final static Map<String, Session> SESSION_MAP = new ConcurrentHashMap<>();

	/**
     * 存放 userName
     */
    public final static Map<String, String> USERNAME_MAP = new ConcurrentHashMap<>();
    /**
     * 连接时触发
     *
     * @param session session
     * @param config  config
     */
    @OnOpen
    public void openSession(Session session, EndpointConfig config) {
        // 将session存起来, 用于服务器向浏览器发送消息
        SESSION_MAP.put(session.getId(), session);
        //getQueryString获取查询字符串。
        String queryStrin = session.getQueryString();
        //解决使用.getQueryString方法获取到路径信息后乱码问题
        String queryString = URLDecoder.decode(queryStrin, StandardCharsets.UTF_8);
        String name = queryString.substring(queryString.indexOf("=")+1);
        USERNAME_MAP.put(session.getId(),name);
        String res = "OnOpen [" + name + "]进入房间";
        sendAll(res);
        logger.info(res);
    }


    /**
     * 有消息时触发
     *
     * @param session session
     * @param message message
     */
    @OnMessage
    public void onMessage(Session session, String message) {
        String res = "OnMessage [" + session.getId() + "]" + message;
        sendAll(res);
        logger.info(res);
    }

    /**
     * 响应字节流
     *
     * @param session session
     * @param message message
     */
    @OnMessage
    public void onMessage(Session session, byte[] message) {
        // 这个以后再说
    }

    /**
     * 连接关闭时触发
     *
     * @param session     session
     * @param closeReason closeReason
     */
    @OnClose
    public void closeSession(Session session, CloseReason closeReason) {
        //记得移除相对应的session
        SESSION_MAP.remove(session.getId());

        String res = "OnClose [" + USERNAME_MAP.get(session.getId()) + "]离开了房间";
        USERNAME_MAP.remove(session.getId());
        sendAll(res);
        logger.info(res);
    }

    /**
     * 有异常时触发
     * @param session
     * @param throwable
     */
    @OnError
    public void sessionError(Session session, Throwable throwable) {
        // 通常有异常会关闭 session
        try {
            session.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * sendAll
     *
     * @param message message
     */
    public void sendAll(String message) {
        for (Session s : SESSION_MAP.values()) {
            // 获得session发送消息的对象
            // Basic是同步, 会阻塞
            // Async是异步, 这个会有多线程并发导致异常, 发送消息太快也会有并发异常, 需要有 消息队列 来辅助使用
            final RemoteEndpoint.Basic remote = s.getBasicRemote();

            try {
                // 发送消息
                remote.sendText(message);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>websocket-demo</title>

    <link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/4.2.1/css/bootstrap.min.css">
</head>
<body>
<div class="container py-3">

    <div class="row">

        <div class="col-6">
            <div>
                <label for="messageArea">聊天信息:</label>
            </div>
            <div>
                <textarea id="messageArea" readonly class="w-100" style="height: 75vh;"></textarea>
            </div>
        </div>

        <div class="col">

            <div class="my-1">
                <label for="messageArea">用 户 名:</label>
            </div>

            <div class="my-1">
                <input type="text" id="username" autocomplete="off">
            </div>

            <div class="my-1">
                <button class="btn-info" id="joinRoomBtn">进入聊天室</button>
                <button class="btn-warning" id="leaveRoomBtn">离开聊天室</button>
            </div>

            <hr/>

            <div class="my-1">
                <label for="sendMessage">输入消息:</label>
            </div>
            <div>
                <textarea id="sendMessage" rows="5" class="w-100" style="max-height: 50vh"></textarea>
            </div>

            <div class="my-1">
                <button class="btn-primary" id="sendBtn">发送消息</button>
            </div>

        </div>

    </div>

</div>
]

<script src="https://s3.pstatp.com/cdn/expire-1-M/jquery/3.3.1/jquery.min.js"></script>

<script>
    let webSocket;
    // ip和端口号用自己项目的
    // {websocket}: 其实是刚刚那个@ServerEndpoint("/websocket")中定义的
    let url = 'ws://localhost:8081/test/websocket';

    $('#username').keyup(function (e) {
        let keycode = e.which;
        if (keycode === 13) {
            $('#joinRoomBtn').click();
        }
    });

    // 进入聊天室
    $('#joinRoomBtn').click(function () {
        let username = $('#username').val();
		//判断当前浏览器是否支持WebSocket
		if('WebSocket' in window){
			webSocket = new WebSocket(url+"?username="+username);
		}else{
			alert('Not support websocket')
		}
        
        webSocket.onopen = function () {
            console.log('webSocket连接创建。。。');
        }
        webSocket.onclose = function () {
            console.log('webSocket已断开。。。');
            $('#messageArea').append('websocket已断开\n');
        }
        webSocket.onmessage = function (event) {
            $('#messageArea').append(event.data + '\n');
        }
        webSocket.onerror = function (event) {
            console.log(event)
            console.log('webSocket连接异常。。。');
        }
    });

    // 退出聊天室
    $('#leaveRoomBtn').click(function () {
        if (webSocket) {
            // 关闭连接
            webSocket.close();
        }
    });

    // 发送消息
    $('#sendBtn').click(function () {
        var msg = $('#sendMessage').val();
        if (msg.trim().length === 0) {
            alert('请输入内容');
            return;
        }
        webSocket.send($('#sendMessage').val());

        $('#sendMessage').val('');
    });

	// 监听窗口关闭事件,当窗口关闭时
	// 主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
	window.onbeforeunload = function () {
	   if (webSocket) {
            // 关闭连接
            webSocket.close();
        }
	};

</script>

</body>
</html>

自动推送信息

1、 session 共享

session 共享后拿到 session 即可推送

2、建立客户端


/**
 * websocket 客户端
 */
@ClientEndpoint
public class WebSocketClient {
    @OnOpen
    public void onOpen(Session session) {
        // 打开通信通道时发生
        System.out.println("client onOpen");
    }

    @OnMessage
    public void onMessage(String message, Session session) {
        // 处理接收到的消息
        System.out.println("client onMessage");
    }

    @OnClose
    public void onClose(Session session, CloseReason reason) {
        // 关闭连接
        System.out.println("client onClose");
    }

    @OnError
    public void onError(Session session, Throwable error) {
        // 错误处理
        System.out.println("client onError");
    }
}

客户端与服务端链接,然后用客户端发送信息给服务端,服务端再次发送信息

 WebSocketContainer container = ContainerProvider.getWebSocketContainer();
 Session session = container.connectToServer(WebSocketClient.class, URI.create("ws://localhost:8081/test/websocket?username=admin"));
 session.getBasicRemote().sendText("[系统通知] ... ...");

原文参考: https://blog.csdn.net/weixin_43874301/article/details/129348769

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值