SpringBoot intègre WebSocket [copier et utiliser]

avant-propos

Cet article implémente SpringBoot pour intégrer WebSocket , copier et utiliser, et écrit quelques méthodes de transmission de message de base pour un message unique, un message multi-personnes et un message diffusé.


1. Présentation de WebSocket

  • WebSocket est un protocole de communication en duplex intégral sur une seule connexion TCP
  • WebSocket permet 服务端主动向客户端de pousser des données.
  • WebSocket a un format de protocole distinct :ws://
  • Le navigateur et le serveur n'ont qu'à effectuer une poignée de main, et une connexion persistante peut être établie entre les deux, et une transmission de données bidirectionnelle peut être effectuée.

2. Intégration

1. Introduire des dépendances

Il vous suffit d'introduire les dépendances suivantes et elles peuvent être utilisées dans le projet.

<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. Fichier de configuration des services

Ajoutez simplement le code suivant à votre projet

// @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--;
    }
}

3. Appel

Le code suivant n'est qu'un simple exemple d'appel, et la méthode d'appel peut être injectée là où c'est nécessaire dans une entreprise réelle.

@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");
    }

}

Résumer

Cet article réalise principalement l'intégration de la communication WebSocket dans le framework SpringBoot.

Je suppose que tu aimes

Origine blog.csdn.net/SmallCat0912/article/details/128385539
conseillé
Classement