springBoot整合websocket实现服务端向客户端推送消息

       Http只能由客户端发起请求,服务端返回请求,这就导致如果服务端有新的消息需要发送给客户端就比较麻烦,所以websocket就应运而生了。下面是springBoot整合websocket,实现服务端推送消息到客户端的一个小demo,这里使用的是定时任务的方式来模拟这种推送,实际使用中,可以根据情况主动推送。

1.创建maven工程,添加如下依赖(使用的是springBoot  2.2.2.RELEASE):


        
            org.springframework.boot
            spring-boot-starter-web
        
        
            org.springframework.boot
            spring-boot-starter-websocket
        
        
            com.alibaba
            fastjson
            1.2.44
        
        
        
            cn.hutool
            hutool-all
            4.3.2
        
    

2.websocket服务端:

@ServerEndpoint("/ws/{userId}")
@Component
public class WebSocketServer {
    /**concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。*/
    private static ConcurrentHashMap 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);
            webSocketMap.put(userId,this);
        }else{
            webSocketMap.put(userId,this);
        }

        System.out.println("当前连接用户:"+userId);

    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        if(webSocketMap.containsKey(userId)){
            webSocketMap.remove(userId);
        }
        System.out.println("用户 "+userId+" 退出:");
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息*/
    @OnMessage
    public void onMessage(String message, Session session) {
        System.out.println("收到用户消息:"+userId+",报文:"+message);
        if(StrUtil.isNotBlank(message)){
            try {
                //解析发送的报文
                JSONObject jsonObject = JSON.parseObject(message);
                //追加发送人(防止串改)
                jsonObject.put("fromUserId",this.userId);
                String toUserId=jsonObject.getString("toUserId");
                //传送给对应toUserId用户的websocket
                if(StrUtil.isNotBlank(toUserId) && webSocketMap.containsKey(toUserId)){
                    webSocketMap.get(toUserId).sendMessage(jsonObject.toJSONString());
                }else{
                    webSocketMap.get(this.userId).sendMessage("请求的userId:"+toUserId+"不在该服务器上");
                    System.out.println("请求的userId:"+toUserId+"不在该服务器上");
                }
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }

    /**
     *
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        System.out.println("用户错误:"+this.userId+",原因:"+error.getMessage());
        error.printStackTrace();
    }
    /**
     * 实现服务器主动推送
     */
    public void sendMessage(String message) throws IOException {
        this.session.getBasicRemote().sendText(message);
    }


    /**
     * 发送自定义消息
     * */
    public static void sendInfo(String message,String userId) throws IOException {
        System.out.println("发送消息到:"+userId+",报文:"+message);
        if(StrUtil.isNotBlank(userId) && webSocketMap.containsKey(userId)){
            webSocketMap.get(userId).sendMessage(message);
        }else{
            System.out.println("用户"+userId+",不在线!");
        }
    }

    public static ConcurrentHashMap getWebSocketMap() {
        return webSocketMap;
    }

    public static void setWebSocketMap(ConcurrentHashMap webSocketMap) {
        WebSocketServer.webSocketMap = webSocketMap;
    }
}

3.websocket客户端,在resources目录下,创建static目录,在创建一个文件test.html,其内容如下:




    
    websocket通讯




【请输入用户名】:
【目标用户名】:



 【内容】:
 

主要就是那几个监听事件,比如

onmessage,表示收到消息时的回调

4.定时任务模式主动推送:

@Component
public class SendMsgToClient {

    //从第10秒开始,每隔5秒发送一次
    @Scheduled(cron="10/5 * * * * ?")
    public void sendMsg() {
        try {
            ConcurrentHashMap webSocketMap = WebSocketServer.getWebSocketMap();
            ConcurrentHashMap.KeySetView userIds = webSocketMap.keySet();
            if (userIds.size() <= 0){
                System.out.println("当前没有用户连接,不发送消息");
                return;
            }

            String toUserId = null;
            int count = new Random(System.currentTimeMillis()).nextInt(userIds.size());
            //取一个发送消息
            for (int i = 0; i < userIds.size();i++){
                Iterator iterator = userIds.iterator();
                if (iterator.hasNext()){
                    if (i == count){
                        toUserId = iterator.next();
                    }else {
                        iterator.next();
                    }

                }
            }
            if (StrUtil.isNotBlank(toUserId)){
                WebSocketServer.sendInfo("这是服务端主动推送的消息:"+new Date(),toUserId);
            }else {
                System.out.println("当前没有用户连接,不发送消息");
            }

        }catch (IOException e){
            System.out.println("定时推送消息失败...");
        }

    }

}

5.启动类添加如下配置:

    @Bean
    public ServerEndpointExporter serverEndpointExporter(){
        return new ServerEndpointExporter();
    }

 

你可能感兴趣的:(websocket)