SpringBoot整合WebSocket

一.什么是WebSocket

  • WebSocket是基于TCP协议的一种网络协议,它实现了浏览器与服务器全双工通信,支持客户端和服务端之间相互发送信息。在有WebSocket之前,如果服务端数据发生了改变,客户端想知道的话,只能采用定时轮询的方式去服务端获取,这种方式很大程度上增大了服务器端的压力,有了WebSocket之后,如果服务端数据发生改变,可以立即通知客户端,客户端就不用轮询去换取,降低了服务器的压力。目前主流的浏览器都已经支持WebSocket协议了。

二.SpringBoot整合

  • pom依赖
      <!--webSocket-->
        <dependency>
    	    <groupId>org.springframework.boot</groupId>
    	    <artifactId>spring-boot-starter-websocket</artifactId>
            <version>${web-socket.version}</version>
        </dependency>
        
        版本:2.1.17.RELEASE
    
  • 配置文件
    //自动注册WebSocket endpoint 启动类上也需要加@EnableWebSocket
    
    @Configuration
    public class WebSocketConfig {
        @Bean
        public ServerEndpointExporter serverEndpointExporter() {
            return new ServerEndpointExporter();
        }
    }
    
  • server端
    import cn.hutool.core.util.ObjectUtil;
    import cn.hutool.core.util.StrUtil;
    import cn.hutool.extra.spring.SpringUtil;
    import cn.hutool.json.JSONObject;
    import cn.hutool.json.JSONUtil;
    import com.huawen.common.constant.Constants;
    import com.huawen.common.core.redis.RedisCache;
    import lombok.extern.slf4j.Slf4j;
    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.concurrent.ConcurrentHashMap;
    
    
    /**
     * @author:kyrie
     * @date:2022/9/16 10:40
     * @Description: websocket 服务端
     **/
    @Component
    @ServerEndpoint("/websocket/{userId}")
    @Slf4j
    public class WebSocketServer {
    
        /**
         * 存放每个客户端对应的WebSocket对象。
         */
        private static final ConcurrentHashMap<Long, WebSocketServer> WEB_SOCKET_USER_MAP = new ConcurrentHashMap<>();
    
        /**
         * 与某个客户端的连接会话,需要通过它来给客户端发送数据
         */
        private Session session;
    
        /**
         * 接收userId
         */
        private Long userId;
    
        /**
         * 空的成功的json
         */
        private static final JSONObject EMPTY_SUCCESS_JSON = JSONUtil.createObj()
                .put("code", "SUCCESS")
                .put("message", "操作成功")
                .put("result", "");
    
    
        /**
         * redis tool
         */
        private RedisCache redisCache;
    
        /**
         * 连接建立成功调用的方法
         *
         * @param session session会话 只有知道session才可以知道发给谁
         * @param userId  登录人的id
         */
        @OnOpen
        public void onOpen(Session session, @PathParam("userId") Long userId) {
            this.session = session;
            this.userId = userId;
            this.redisCache = SpringUtil.getBean(RedisCache.class);
    
            WEB_SOCKET_USER_MAP.remove(userId);
            WEB_SOCKET_USER_MAP.put(userId, this);
    
            log.info("用户连接:--->{}", userId);
    
            sendMessage(EMPTY_SUCCESS_JSON);
        }
    
        /**
         * 关闭方法
         */
        @OnClose
        public void onClose() {
            WEB_SOCKET_USER_MAP.remove(userId);
            log.info("用户退出:--->{}", userId);
        }
    
    
        /**
         * 出现异常
         *
         * @param error 异常
         */
        @OnError
        public void onError(Throwable error) {
            log.error("用户错误:--->{},原因:--->{}", this.userId, error.getMessage());
        }
    
    
        /**
         * 收到客户端消后调用的方法
         *
         * @param message 客户端发送过来的消息
         **/
        @OnMessage
        public void onMessage(String message) {
            log.info("用户消息:--->{}报文:--->{}", userId, message);
    
            if (StrUtil.isBlank(message)) {
                return;
            }
    
            // 消息保存到redis
            try {
                // 解析发送的报文
                JSONObject jsonObject = JSONUtil.parseObj(message);
    			// 处理自己的业务逻辑
                }
            } catch (Exception e) {
                log.error("onMessage error--->{}", e.getMessage());
            }
        }
    
    
        /**
         * 发送消息给某人
         *
         * @param jsonObject {@link JSONObject} json
         * @param toUserId   接收人id
         */
        public static void sendInfo(JSONObject jsonObject, Long toUserId) {
            log.info("发送消息到:--->{},报文:--->{}", toUserId, jsonObject.toString());
    
            if (ObjectUtil.isNotNull(toUserId) && WEB_SOCKET_USER_MAP.containsKey(toUserId)) {
                WEB_SOCKET_USER_MAP.get(toUserId).sendMessage(jsonObject);
            } else {
                log.error("用户--->{},不在线!", toUserId);
            }
        }
    
        /**
         * 发送消息 json类型
         *
         * @param jsonObject {@link JSONObject }  JSON对象
         */
        public void sendMessage(JSONObject jsonObject) {
            try {
                this.session.getBasicRemote().sendText(JSONUtil.toJsonStr(jsonObject));
            } catch (IOException e) {
                log.error("sendMessage error--->{}", e.getMessage());
            }
        }
    }
    
    
  • 测试发送消息
    package com.huawen.websocket;
    
    import cn.hutool.json.JSONObject;
    import com.huawen.common.constant.Constants;
    import com.huawen.common.core.controller.BaseController;
    import com.huawen.common.core.domain.protocols.APIResult;
    import com.huawen.common.core.redis.RedisCache;
    import com.huawen.common.utils.SecurityUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.util.concurrent.TimeUnit;
    
    /**
     * @author:kyrie
     * @date:2022/9/16 10:56
     * @Description: 测试webSocket controller
     **/
    @RestController
    @RequestMapping("/socket")
    public class WebSocketController extends BaseController {
        @Autowired
        private RedisCache redisCache;
    
        @GetMapping("/send")
        public APIResult<String> sendMessage() {
    
            Long loginUserId = SecurityUtils.getLoginUserId();
    
            JSONObject object = new JSONObject();
    
            object.put(Constants.DATA_STR, loginUserId);
            object.put(Constants.TYPE_STR, Constants.MESSAGE_STR);
            // TODO: 2022/9/16  根据实际人员变化
            object.put(Constants.COUNT_STR, 2);
    
            WebSocketServer.sendInfo(object, loginUserId);
    
            redisCache.setCacheObject(Constants.WEB_SOCKET_PREFIX + loginUserId, object.toString(), Constants.REDIS_TIMEOUT, TimeUnit.SECONDS);
    
            return success();
        }
    }
    
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值