a server-side message push websocket

Because of work reasons, we need to implement a server-side message push functionality, published an article on a similar, but pushed to designated users, and finally decided to adopt websocket way to achieve this functionality.

First, prepare

Realization is divided into server and client, the client and server-side by websocket stay connected, so that the server can initiate a request to the client.

Second, the server

I springboot server used, if only with the need to introduce websocket can rely on the websocket

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-websocket</artifactId>
	<version>2.0.4.RELEASE</version>
</dependency>

Then mainly need to implement two classes, one class websocket configuration, there is provided a service call other Service

WebSocketConfig.java

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

/**
 * @author chenwenrui
 * @description: WebSocket配置类
 * @date 2019/6/11 18:17
 */
@Configuration
public class WebSocketConfig {
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}

This configuration file only play a role is registered ServerEndpointExporter objects, the bean will be automatically registered to use class @ServerEndpoint annotation statement, such as the following WebSocketService class

WebSocketService.java

import org.springframework.stereotype.Service;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.stream.Collectors;

/**
 * @author chenwenrui
 * @description: TODO
 * @date 2019/6/11 18:11
 */
@Service
@ServerEndpoint(value = "/websocket/{userId}")
public class WebSocketService {

    /**
     * concurrent包的线程安全Set,用来存放每个客户端对应的WebSocketSet对象。
     */
    private static CopyOnWriteArraySet<WebSocketService> webSocketSet = new CopyOnWriteArraySet<>();

    /**
     * 与某个客户端的连接会话,需要通过它来给客户端发送数据
     */
    private Session session;

    /**
     * 客户端用户id
     */
    private String userId;

    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("userId") String userId) {
        this.session = session;
        this.userId = userId;
        if (userId != null) {
            webSocketSet.add(this);     //加入set中
        }
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        webSocketSet.remove(this);  //从set中删除
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(String message, Session session) {

    }

    /**
     * 发生错误时调用
     *
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        error.printStackTrace();
    }

    /**
     * 向客户端发送消息
     *
     * @param message 消息内容
     * @param userIds 需要发送的客户端用户id列表
     */
    public void sendMessage(String message, List<String> userIds) {
        // 需要发送消息的客户端
        List<WebSocketService> services = webSocketSet.stream()
                .filter(temp -> userIds.contains(temp.userId))
                .collect(Collectors.toList());
        services.forEach(temp -> {
            try {
                temp.session.getBasicRemote().sendText(message);
            } catch (IOException e) {
                e.printStackTrace();
            }
        });
    }
}

@ServerEndpoint that this is a websocket, because each user is a client login, so here used to distinguish different user client id to facilitate sending messages to the corresponding user, each client initiates a connection request websocket time required to the corresponding object (WebSocketService, mainly to save userId and corresponding client Session) to save the collection (to be used by other service call), the time when the user closes the connection needs to be removed from the collection.

Third, the client

My client is a vue use only () hook inside to open a connection to the mounted websocket

mounted(){
	let websocket = new WebSocket(
		"ws://localhost:8089/websocket/" + userId
	);
	 //连接成功建立的回调方法
	websocket.onopen = function(event) {
		console.log("连接成功");
	};
	//接收到消息的回调方法
	websocket.onmessage = function(event) {
		console.log(event);
	};
	 //连接关闭的回调方法
	websocket.onclose = function() {
		console.log("连接关闭");
	};
	//连接发生错误的回调方法
	websocket.onerror = function() {
		console.log("发生错误");
	};
}

When WebSocket object instantiation, of a currently logged-on user id (token also, as long as it can ensure that the current state is unique) for each mark corresponding to the client WebSocket connection.

Guess you like

Origin blog.csdn.net/cwr452829537/article/details/91580331