spring boot 集成netty socketIO(聊天室)

1、引入netty-socketio jar包

  
        com.corundumstudio.socketio
        netty-socketio
        1.7.11
  

2、配置文件添加socket监听事件
#socket监听端口
wss.server.port=8081
# socket主机
wss.server.host=localhost

3、NettySocketConfig配置

@Configuration
public class NettySocketConfig {
    @Value("${wss.server.port}")
    private int WSS_PORT;
    @Value("${wss.server.host}")
    private String WSS_HOST;

    @Bean
    public SocketIOServer socketIOServer() {
        com.corundumstudio.socketio.Configuration config = new     com.corundumstudio.socketio.Configuration();
        //不设置主机、默认绑定0.0.0.0 or ::0
        //config.setHostname(WSS_HOST);
        config.setPort(WSS_PORT);
        //该处进行身份验证h
        config.setAuthorizationListener(handshakeData -> {
        //http://localhost:8081?username=test&password=test
        //例如果使用上面的链接进行connect,可以使用如下代码获取用户密码信息
        //String username = data.getSingleUrlParam("username");
        //String password = data.getSingleUrlParam("password");
        return true;
    });
    final SocketIOServer server = new SocketIOServer(config);
    return server;
    }

    @Bean
    public SpringAnnotationScanner springAnnotationScanner(SocketIOServer socketServer) {
        return new SpringAnnotationScanner(socketServer);
    }
}

4、ServerRunner类实现

@Component
public class ServerRunner implements CommandLineRunner {
    private final SocketIOServer server;
    @Autowired
    public ServerRunner(SocketIOServer server) {
        this.server = server;
    }
    @Override
    public void run(String... args) throws Exception {
        server.start();
    }
}

5、MessageEventHandler消息处理类实现

@Component
@Slf4j
public class MessageEventHandler {
     
    //会话集合
private static final ConcurrentSkipListMap webSocketMap = new ConcurrentSkipListMap<>();
//静态变量,用来记录当前在线连接数。(原子类、线程安全)
private static AtomicInteger onlineCount = new AtomicInteger(0);

private final SocketIOServer server;
@Autowired
public MessageEventHandler(SocketIOServer server){
    this.server = server;
}
@Autowired
public MongoTemplate mongoTemplate;

/**
 * connect事件处理,当客户端发起连接时将调用
 * @param client
 */
@OnConnect
public void onConnect(SocketIOClient client){
    String clientId = client.getHandshakeData().getSingleUrlParam("clientid");
    log.info("web socket连接:"+clientId);
    UUID session = client.getSessionId();
    ClientInfo si = webSocketMap.get(clientId);
    // 如果没有连接信息、则新建会话信息
    if (si == null) {
        si = new ClientInfo();
        si.setOnline(true);
        //在线数加1
        log.info("socket 建立新连接、sessionId:"+session+"、clientId:"+clientId+"、当前连接数:"+onlineCount.incrementAndGet());
    }
    // 更新设置客户端连接信息
    si.setLeastSignificantBits(session.getLeastSignificantBits());
    si.setMostSignificantBits(session.getMostSignificantBits());
    si.setLastConnectedTime(new Date());
    //将会话信息更新保存至集合中
    webSocketMap.put(clientId, si);
}
/**
 * disconnect事件处理,当客户端断开连接时将调用
 * @param client
 */
@OnDisconnect
public void onDisconnect(SocketIOClient client)
{
    String clientId = client.getHandshakeData().getSingleUrlParam("clientid");
    webSocketMap.remove(clientId);
    //在线数减1
    log.info("socket 断开连接、sessionId:"+client.getSessionId()+"、clientId:"+clientId+"、当前连接数:"+ onlineCount.decrementAndGet());
}

/**
 * 消息接收入口,当接收到消息后,查找发送目标客户端,并且向该客户端发送消息,且给自己发送消息
 * @param client
 * @param request
 * @param data
 */
@OnEvent(value = "message_event")
public void onEvent(SocketIOClient client, AckRequest request, MessageInfo data){
    SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
    String time = simpleDateFormat.format(new Date());
    Chat chat  = new Chat();
    chat.setUserSendId(data.getTargetClientId());
    chat.setUserReceiveId(data.getSourceClientId());
    chat.setContent(data.getMsg());
    chat.setCreatetime(time);
    mongoTemplate.save(chat);
    String targetClientId = data.getTargetClientId();
    ClientInfo clientInfo = webSocketMap.get(targetClientId);
    if (clientInfo != null && clientInfo.isOnline()){
        UUID target = new UUID(clientInfo.getMostSignificantBits(), clientInfo.getLeastSignificantBits());
        log.info("目标会话UUID:"+target);
        MessageInfo sendData = new MessageInfo();
        sendData.setSourceClientId(data.getSourceClientId());
        sendData.setTargetClientId(data.getTargetClientId());
        sendData.setMsg(data.getMsg());
        // 向当前会话发送信息
        client.sendEvent("message_event", sendData);
        // 向目标会话发送信息
        server.getClient(target).sendEvent("message_event", sendData);
    }
}

/**
 * socket会话信息
 */
public class ClientInfo {
    private String clientId;
    private boolean isOnline;
    private long mostSignificantBits;
    private long leastSignificantBits;
    private Date lastConnectedTime;
    // get/set方法 ....
}
/**
 * 消息对象
 */
public static class MessageInfo {
    //源客户端id
    private String sourceClientId;
    //目标客户端id
    private String targetClientId;
    //消息内容
    private String msg;
    // get/set方法 ....
} 
}

6、页面实现

 




Demo Chat









Netty-socket.io Demo


     

你可能感兴趣的:(spring boot 集成netty socketIO(聊天室))