Websocket front-end and back-end interactive communication

The websocket protocol is a technology used for front-end and back-end long link interaction. This technology is mostly used in scenarios with continuous interaction, such as WeChat. The interaction between two or more of QQ;

The four annotations on the front end of websocket correspond to the four annotation methods on the back end, and the corresponding trigger time will correspond to the message received by the back end.

@OnOpen, link successful interaction initialization
@OnClose, close event
@OnMessage, message event
@OnError exception event

This article simply records the scenarios used in the project, without detailed records, you can check the official documents if you need to know;

1. Introduce the WebSocket Jar package


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

2. Create a WebSocket configuration class

This configuration class is used to detect beans annotated with @ServerEndpoint and register them with the container.

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
 
 
@Configuration
@Slf4j
public class WebSocketConfig {
    
    
    /**
     * 给spring容器注入这个ServerEndpointExporter对象
     * 相当于xml:
     * <beans>
     * <bean id="serverEndpointExporter" class="org.springframework.web.socket.server.standard.ServerEndpointExporter"/>
     * </beans>
     * <p>
     * 检测所有带有@serverEndpoint注解的bean并注册他们。
     *
     * @return
     */
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
    
    
        log.info("serverEndpointExporter被注入了");
        return new ServerEndpointExporter();
    }
}

3. Create a WebSocket processing class

@Component
@Slf4j
@ServerEndpoint("/websocket/{coreCode}/{employeeCode}")//请求案例:// 接口路径 ws://localhost:8087/webSocket/userCode;
public class WebsocketService {
    
    
 
    private Session session;//与某个客户端的连接会话,需要通过它来给客户端发送数据
 
    //concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
    //虽然@Component默认是单例模式的,但springboot还是会为每个websocket连接初始化一个bean,所以可以用一个静态set保存起来。
    //  注:底下WebSocket是当前类名
    private static CopyOnWriteArraySet<WebsocketService> webSockets = new CopyOnWriteArraySet<>();
    // 用来存在线连接数
    private static Map<String, Session> sessionPool = new HashMap<String, Session>();
 
    // 用来存储当前用户登录的归属核企
    private static Map<String, String> coreMap = new HashMap<String, String>();
 
    private String employeeCode;  //每次链接访问的时候,都是一个新的请求,所以这个变量是不会覆盖的
 
    /**
     * 链接成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam(value = "coreCode") String coreCode, @PathParam(value = "employeeCode") String employeeCode) {
    
    
        try {
    
    
            this.session = session;
            this.employeeCode = employeeCode;
            webSockets.add(this);
            sessionPool.put(employeeCode, session);
            if (coreMap.containsKey((employeeCode))) {
    
    
                coreMap.remove(employeeCode);
                //加入map
            }
            coreMap.put(employeeCode, coreCode);
            log.info("【websocket消息】有新的连接,总数为:" + webSockets.size());
        } catch (Exception e) {
    
    
            log.error("websocket链接失败:", e.getMessage());
        }
    }
 
    /**
     * 链接关闭调用的方法<br>    *此方法关闭事件,不管是关闭浏览器还是直接退出或者超时回话都会触发这个接口<br>
     */
    @OnClose
    public void onClose() {
    
    
        try {
    
    
            webSockets.remove(this);
            if (coreMap.containsKey(employeeCode)) {
    
    
                coreMap.remove(employeeCode);
            }
            if(sessionPool.containsKey(employeeCode)){
    
    
                sessionPool.remove(employeeCode);
            }
            log.info("【websocket消息】连接断开,总数为:" + webSockets.size());
        } catch (Exception e) {
    
    
            log.error("websocket关闭失败:", e.getMessage());
        }
    }
 
    /**
     * 收到客户端消息后调用的方法
     *
     * @param message
     */
    @OnMessage
    public void onMessage(String message) {
    
    
        log.info("【websocket消息】收到客户端消息:" + message);
    }
 
    /**
     * 发送错误时的处理
     *
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
    
    
        log.error("用户错误,原因:" + error.getMessage());
        error.printStackTrace();
    }
 
 
    /**
     * 全部人员消息
     *
     * @param message
     */
    public void sendAllMessage(String message) {
    
    
        log.info("【websocket消息】全部人员消息:" + message);
        for (WebsocketService webSocket : webSockets) {
    
    
            try {
    
    
                if (webSocket.session.isOpen()) {
    
    
                    webSocket.session.getAsyncRemote().sendText(message);
                }
            } catch (Exception e) {
    
    
                e.printStackTrace();
                log.error("全部人员发送消息失败:", e.getMessage());
            }
        }
    }
 
    /**
     * 点对点发送指定人消息
     *
     * @param employeeCode
     * @param message
     */
    public void sendOneMessage(String employeeCode, String message) {
    
    
        Session session = sessionPool.get(employeeCode);
        if (session != null && session.isOpen()) {
    
    
            try {
    
    
                log.info("【websocket消息】 点对点发送指定人消息:" + message);
                session.getAsyncRemote().sendText(message);
            } catch (Exception e) {
    
    
                e.printStackTrace();
                log.error("点对点发送指定人消息:", e.getMessage());
            }
        }
    }
 
    /**
     * 发送指定多个人员消息
     *
     * @param employeeCodes
     * @param message
     */
    public void sendMoreMessage(String[] employeeCodes, String message) {
    
    
        for (String employeeCode : employeeCodes) {
    
    
            Session session = sessionPool.get(employeeCode);
            if (session != null && session.isOpen()) {
    
    
                try {
    
    
                    log.info("【websocket消息】 发送指定多个人员消息:" + message);
                    session.getAsyncRemote().sendText(message);
                } catch (Exception e) {
    
    
                    e.printStackTrace();
                    log.error("发送指定多个人员消息:", e.getMessage());
                }
            }
        }
    }
 
    /**
     * 点对点发送指定场景人员编码消息
     *
     * @param centres
     * @param configTemplates
     */
    public void sendScenetOneMessage(List<InformationCentre> centres, InformationConfigTemplate configTemplates, String code) {
    
    
        log.info("当前存储的用户编码和核企的关系集合:{},session集合:{}",coreMap,sessionPool);
        centres.stream().forEach(item -> {
    
    
            String value = coreMap.get(item.getEmployeeCode());
            if(StrUtil.isNotBlank(value)){
    
    
                //判断是否是全部核企还是部分核企,如果是部分核企,当前登录人员所属核企消息发送对象是否包含
                if ("PART".equals(configTemplates.getScope()) && StrUtil.isNotBlank(configTemplates.getCoreStrand())) {
    
    
                    List<InformationCofigCore> informationCofigCores = JSONUtil.toList(configTemplates.getCoreStrand(), InformationCofigCore.class);
                    List<String> coreList = informationCofigCores.stream().map(InformationCofigCore::getCoreCode).collect(Collectors.toList());
                    String coreCodeMap = coreMap.get(item.getEmployeeCode());
                    if (!coreList.contains(coreCodeMap)) {
    
    
                        return;
                    }
                }
                if (InformationEnum.INTERNALINFORMATIONCHANNEL.code.equals(code)) {
    
    
                    //发送给当前登录人消息
                    Session session = sessionPool.get(item.getEmployeeCode());
                    if (session != null && session.isOpen()) {
    
    
                        try {
    
    
                            log.info("【websocket消息】 点对点发送指定人消息:" + item);
                            session.getAsyncRemote().sendText(JSONUtil.toJsonStr(item));
                        } catch (Exception e) {
    
    
                            e.printStackTrace();
                            log.error("点对点发送指定人消息:", e.getMessage());
                        }
                    }
                }
            }
        });
    }
}

Guess you like

Origin blog.csdn.net/qq_27480007/article/details/128834349