SpringBoot集成WebSocket【复制即用】

前言

本文实现SpringBoot 集成 WebSocket,复制即用,并编写了一些基础消息推送的方法 单体消息、多人消息、广播消息


一、WebSocket介绍

  • WebSocket是一种在单个TCP连接上进行全双工通信的协议
  • WebSocket允许服务端主动向客户端推送数据。
  • WebSocket有单独的协议格式:ws://
  • 浏览器和服务器只需要完成一次握手,两者之间就可以创建持久性的连接,并进行双向数据传输。

二、集成

1.引入依赖

只需要引入如下依赖既可以在项目中使用。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
    <version>2.3.5.RELEASE</version>
</dependency>
<!--日志打印需要-->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.18</version>
</dependency>

2.服务配置文件

将以下代码添加到项目中即可

// @ServerEndpoint注解类似于Controller层的 @RequestMapping注解
// 此处websocket服务地址例如:http://127.0.0.1:8080/websocket/1
@ServerEndpoint(value = "/websocket/{userId}")
@Component
public class WebSocketServer {
    
    

    private static  Logger log = LoggerFactory.getLogger(WebSocketServer.class);
    /**静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。*/
    private static int onlineCount = 0;
    /**concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。*/
    private static ConcurrentHashMap<String,WebSocketServer> webSocketMap = new ConcurrentHashMap<>();
    /**与某个客户端的连接会话,需要通过它来给客户端发送数据*/
    private Session session;
    /**接收userId*/
    private String userId="";

    /**
     * 连接建立成功调用的方法
     * */
    @OnOpen
    public void onOpen(Session session,@PathParam("userId") String userId) {
    
    
        this.session = session;
        this.userId=userId;
        //判断用户集合中是否存在当前用户
        if(webSocketMap.containsKey(userId)){
    
    
            //有则先删除已有用户,再添加
            webSocketMap.remove(userId);
            //加入set中
            webSocketMap.put(userId,this);
        }else{
    
    
            //加入set中
            webSocketMap.put(userId,this);
            //在线数加1
            addOnlineCount();
        }
        log.info("用户连接: "+userId+",当前在线人数为: " + getOnlineCount());

        try {
    
    
            sendMessage("连接成功");
        } catch (IOException e) {
    
    
            log.error("用户: "+userId+",网络异常!!!!!!");
        }
    }

    /**
     * 连接关闭执行
     */
    @OnClose
    public void onClose() {
    
    
        if(webSocketMap.containsKey(userId)){
    
    
            //将当前用户在集合中删除
            webSocketMap.remove(userId);
            //从set中删除
            subOnlineCount();
        }
        log.info("用户【"+userId+"】退出: 当前在线人数为: " + getOnlineCount());
    }

    /**
     * 收到客户端消息时执行
     *
     * @param message 客户端发送过来的消息*/
    @OnMessage
    public void onMessage(String message, Session session) {
    
    
        log.info("当前用户: "+userId+",报文: "+message);
        if(StringUtils.isNotBlank(message)){
    
    
            try {
    
    
                //传送给对应userId用户的websocket, 如果userId不为空 并且 webSocketMap种包含userId 才会发送消息
                if(StringUtils.isNotBlank(userId) && webSocketMap.containsKey(userId)){
    
    
                    webSocketMap.get(userId).sendMessage("心跳响应");
                }else{
    
    
                    //否则不在这个服务器上
                    log.error("请求的userId:"+userId+" 不在该服务器上");
                }
            }catch (Exception e){
    
    
                e.printStackTrace();
            }
        }
    }

    /**
     * 链接异常时执行
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
    
    
        log.error("用户错误:"+this.userId+",原因:"+error.getMessage());
        error.printStackTrace();
    }

    /**
     * 实现服务器主动推送
     * getAsyncRemote:是非阻塞式的
     * getBasicRemote:是阻塞式的
     */
    public void sendMessage(String message) throws IOException {
    
    
//        this.session.getBasicRemote().sendText(message);//同步消息
        this.session.getAsyncRemote().sendText(message);//异步消息
    }


	// --------------------以下三种主动发送消息方法---------------------
	// --------------------通过注入WebSocketServer类使用---------------------

    /**
     * 单体消息
     * */
    public void sendOneMessage(String message, String userId) throws IOException {
    
    
        log.info("发送单体消息到: "+userId+",报文:"+message);
        if(StringUtils.isNotBlank(userId)&&webSocketMap.containsKey(userId)){
    
    
            webSocketMap.get(userId).sendMessage(message);
        }else{
    
    
            log.error("用户: "+userId+",不在线!");
        }
    }


    /**
     * 多人消息
     * */
    public void sendMoreMessage(String message, String[] userIds) throws IOException {
    
    
        log.info("多人消息报文: "+message);
        for (String id : userIds) {
    
    
            if(webSocketMap.containsKey(id)){
    
    
                webSocketMap.get(id).sendMessage(message);
            }else{
    
    
                log.error("用户: "+id+",不在线!");
            }
        }
    }

    /**
     * 广播消息
     * */
    public void sendAllMessage(String message) throws IOException {
    
    
        log.info("广播消息报文: "+message);
        for (Map.Entry<String,WebSocketServer> entry : webSocketMap.entrySet()){
    
    
            entry.getValue().sendMessage(message);
        }
    }

    /**
     * 获取当前在线人数
     * @return
     */
    public synchronized int getOnlineCount() {
    
    
        return onlineCount;
    }

    /**
     * 在线人数加1
     */
    public synchronized void addOnlineCount() {
    
    
        WebSocketServer.onlineCount++;
    }

    /**
     * 在线人数减1
     */
    public synchronized void subOnlineCount() {
    
    
        WebSocketServer.onlineCount--;
    }
}

三、调用

以下代码只是简单的调用示例,实际业务中在需要的地方注入调用方法即可。

@Controller
@RequestMapping("/demo")
public class DemoController {
    
    

    //注入WebSocketServer
    @Autowired
    private WebSocketServer webSocketServer;

    /**
     * 单人消息
     * @param message:消息体
     * @param toUserId:目标人
     * @return
     * @throws IOException
     */
    @GetMapping("/pushOne")
    @ResponseBody
    public ResponseEntity<String> pushToWeb(String message, String toUserId) throws IOException {
    
    
        //此处调用单体消息方法
        webSocketServer.sendOneMessage(message,toUserId);
        return ResponseEntity.ok("MSG SEND SUCCESS");
    }

    /**
     * 多人消息
     * @param message:消息体
     * @param toUserIds:目标人数组
     * @return
     * @throws IOException
     */
    @RequestMapping("/pushMore")
    @ResponseBody
    public ResponseEntity<String> pushToWeb(String message, String[] toUserIds) throws IOException {
    
    
        //此处调用多人消息方法
        webSocketServer.sendMoreMessage(message,toUserIds);
        return ResponseEntity.ok("MSG SEND SUCCESS");
    }

    /**
     * 广播消息
     * @param message:消息体
     * @return
     * @throws IOException
     */
    @RequestMapping("/pushAll")
    @ResponseBody
    public ResponseEntity<String> pushToWeb(String message) throws IOException {
    
    
        //此处调用广播消息方法
        webSocketServer.sendAllMessage(message);
        return ResponseEntity.ok("MSG SEND SUCCESS");
    }

}

总结

本文主要实现了在SpringBoot框架中集成WebSocket通讯。

猜你喜欢

转载自blog.csdn.net/SmallCat0912/article/details/128385539
今日推荐