Java springboot使用webscoket包含心跳机制

在发送消息时候可以将消息类型让前端传过来,根据消息类型找到对应的枚举值,在根据枚举去调用接口信息。枚举中封装公共的server,实现方式进行继承,将会自动寻找到对应的impl方法。
由于很晚了,博主就不写出来了,思路给你们写出来,你们自己去完成。

package com.example.simplepoolsize.cofig;

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

@Configuration
public class WebsocketConfig {

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

package com.example.simplepoolsize;

public enum WebSocketMessageEnum {
    HEART_CHECK("欢迎光临", 1);

    private Object jsonValue;
    private int code;

    public Object getJsonValue() {
        return jsonValue;
    }

    public void setJsonValue(Object jsonValue) {
        this.jsonValue = jsonValue;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    WebSocketMessageEnum(Object jsonValue, int code) {
        this.jsonValue = jsonValue;
        this.code = code;
    }
}

package com.example.simplepoolsize;

public enum WebSocketStatus {
    one(1, "单人聊天"),
    two(2, "多人聊天");
    /*。。。。。。。。。。。。。。。。。。。。。。。。加很多*/

    private Object jsonValue;
    private int code;

    public Object getJsonValue() {
        return jsonValue;
    }

    public void setJsonValue(Object jsonValue) {
        this.jsonValue = jsonValue;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    WebSocketStatus( int code,Object jsonValue) {
        this.jsonValue = jsonValue;
        this.code = code;
    }
}
package com.example.simplepoolsize.server;

import com.example.simplepoolsize.WebSocketMessageEnum;
import com.sun.istack.internal.NotNull;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

@Slf4j
@Service
@ServerEndpoint("/websocket/{uid}")
public class WebSocketServer {

    private static final long sessionTimeout = 50000;
    // 用来存放每个客户端对应的WebSocketServer对象
    private static ConcurrentHashMap<String, WebSocketServer> webSocketMap = new ConcurrentHashMap<>();

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

    // 接收id
    private String uid;

    // 连接建立成功调用的方法
    @OnOpen
    public void onOpen(Session session, @PathParam("uid") String uid) {
        session.setMaxIdleTimeout(sessionTimeout);
        this.session = session;
        this.uid = uid;
        if (webSocketMap.containsKey(uid)) {
            webSocketMap.remove(uid);
        }
        webSocketMap.put(uid, this);
        log.info("websocket连接成功编号uid: " + uid + ",当前在线数: " + getOnlineClients());
        try {
            sendMessage(uid);
        } catch (IOException e) {
            log.error("websocket发送连接成功错误编号uid: " + uid + ",网络异常!!!");
        }
    }

    // 连接关闭调用的方法
    @OnClose
    public void onClose() {
        try {
            if (webSocketMap.containsKey(uid)) {
                webSocketMap.remove(uid);
            }
            log.info("websocket退出编号uid: " + uid + ",当前在线数为: " + getOnlineClients());
        } catch (Exception e) {
            log.error("websocket编号uid连接关闭错误: " + uid + ",原因: " + e.getMessage());
        }
    }

    /**
     * 收到客户端消息后调用的方法
     * @param message 客户端发送过来的消息
     * @param session
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        log.info("websocket收到客户端编号uid消息: " + uid + ", 报文: " + message);
        try {
            if (!StringUtils.isEmpty(message)){
                //JSONObject jsonObject = JSON.parseObject(message);
                //将数据进行转换处理
                this.sendMessage(message);
            }
        }catch (Exception e){
            e.printStackTrace();
            log.error("websocket收到客户端信息错误");
        }

    }

    /**
     * 发生错误时调用
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("websocket编号uid错误: " + this.uid + "原因: " + error.getMessage());
        error.printStackTrace();
    }

    /**
     * 外部接口通过指定的客户id向该客户推送消息
     * @param key
     * @param message
     * @return boolean
     */
    public static boolean sendMessageByWayBillId(@NotNull String key, String message) {
        WebSocketServer webSocketServer = webSocketMap.get(key);
        if (Objects.nonNull(webSocketServer)) {
            try {
                webSocketServer.sendMessage(message);
                log.info("websocket发送消息编号uid为: " + key + "发送消息: " + message);
                return true;
            } catch (Exception e) {
                log.error("websocket发送消息失败编号uid为: " + key + "消息: " + message);
                return false;
            }
        } else {
            log.error("websocket未连接编号uid号为: " + key + "消息: " + message);
            return false;
        }
    }

    // 此为单点消息(多人)
    public static void sendMoreMessage(String[] userIds, String message) {
        for(String userId:userIds) {
                try {
                    log.info("【websocket消息】 单点消息:"+message);
                    WebSocketServer webSocketServer = webSocketMap.get(userId);
                    webSocketServer.sendMessage(message);
                } catch (Exception e) {
                    e.printStackTrace();
                }
        }

    }

    // 全体消息
    public static void sendInfo(String message) {
        webSocketMap.forEach((k, v) -> {
            WebSocketServer webSocketServer = webSocketMap.get(k);
            try {
                webSocketServer.sendMessage(message);
                log.info("websocket群发消息编号uid为: " + k + ",消息: " + message);
            } catch (IOException e) {
                log.error("群发自定义消息失败: " + k + ",message: " + message);
            }
        });
    }

    /**
     * 服务端群发消息-心跳包
     * @param message
     * @return int
     */
    public static synchronized int sendPing(String message) {
        if (webSocketMap.size() <= 0) {
            return 0;
        }
        StringBuffer uids = new StringBuffer();
        AtomicInteger count = new AtomicInteger();
        webSocketMap.forEach((uid, server) -> {
            count.getAndIncrement();
            if (webSocketMap.containsKey(uid)) {
                WebSocketServer webSocketServer = webSocketMap.get(uid);
                try {
                    webSocketServer.sendMessage(message);
                    if (count.equals(webSocketMap.size() - 1)) {
                        uids.append("uid");
                        return; // 跳出本次循环
                    }
                    uids.append(uid).append(",");
                } catch (IOException e) {
                    webSocketMap.remove(uid);
                    log.info("客户端心跳检测异常移除: " + uid + ",心跳发送失败,已移除!");
                }
            } else {
                log.info("客户端心跳检测异常不存在: " + uid + ",不存在!");
            }
        });
        log.info("客户端心跳检测结果: " + uids + "连接正在运行");
        return webSocketMap.size();
    }

    // 实现服务器主动推送
    public void sendMessage(String message) throws IOException {
        this.session.getBasicRemote().sendText(message);
    }


    // 获取客户端在线数
    public static synchronized int getOnlineClients() {
        if (Objects.isNull(webSocketMap)) {
            return 0;
        } else {
            return webSocketMap.size();
        }
    }

    /**
     * 连接是否存在
     * @param uid
     * @return boolean
     */
    public static boolean isConnected(String uid) {
        if (Objects.nonNull(webSocketMap) && webSocketMap.containsKey(uid)) {
            return true;
        } else {
            return false;
        }
    }

}
@Component
@Slf4j
@EnableScheduling
class WebSocketTask {

    /**
     * 每1秒进行一次websocket心跳检测
     */
    //这里可以写成线程去监听,但是太晚了,本人困了。剩下你们来操作
    @Scheduled(cron = "0/4 * * * * ?")
    public void clearOrders() {
        int num = 0;
        try {
            Object jsonObject = WebSocketMessageEnum.HEART_CHECK.getJsonValue();
            num = WebSocketServer.sendPing(jsonObject.toString());
        } finally {
            log.info("websocket心跳检测结果,共【" + num + "】个连接");
        }
    }
}

```bash
package com.example.simplepoolsize.coll;

import com.example.simplepoolsize.server.WebSocketServer;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class WebSocketController  {
    @Value("${mySocket.myPwd}")
    private String myPwd;

    @Value("${mySocket.myPassword}")
    private String myPassword;


    //这里其实还可以在加上时间搓和token进行校验

    /**
     * webSocket链接是否成功
     * @param webSocketId
     * @return Res<Boolean>
     */
    @GetMapping("/webSocketIsConnect/{webSocketId}")
    public Res<Boolean> webSocketIsConnect(@PathVariable("webSocketId") String webSocketId) {
        return Res.success(WebSocketServer.isConnected(webSocketId));
    }

    /**
     * webSocket发送客户端消息
     * @param webSocketId
     * @param message
     * @param myPassword
     * @return Res<Boolean>
     */
    @GetMapping("/sendMessageByWayBillId")
    public Res<Boolean> sendMessageByWayBillId(String webSocketId, String message, String pwd,String myPassword) {
        boolean flag = false;
        if (myPwd.equals(pwd)&&myPwd.equals(myPassword)) {
            flag = WebSocketServer.sendMessageByWayBillId(webSocketId, message);
        }
        return Res.success(flag);
    }

    /**
     * 多人消息
     * @param message
     * @param pwd
     * @param myPassword
     */
    @GetMapping("/sendMoreMessage")
    public void sendInfo(String message, String pwd,String myPassword,String [] userIDs) {
        if (myPwd.equals(pwd)&&myPwd.equals(myPassword)) {
            WebSocketServer.sendMoreMessage(userIDs,message);
        }
    }

    /**
     * 广播消息
     * @param message
     * @param pwd
     * @param myPassword
     */
    @GetMapping("/sendInfo")
    public void sendInfo(String message, String pwd,String myPassword) {
        if (myPwd.equals(pwd)&&myPwd.equals(myPassword)) {
            WebSocketServer.sendInfo(message);
        }
    }
}



```bash
server:
  port: 8080

mySocket:
  myPwd: trench
  myPassword: 231231231231231
 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>
       

你可能感兴趣的:(java,spring,boot,开发语言)