Java websocket + redis realizes multi-person single chat room, multi-person multi-chat room, one-to-one chat

Multiplayer, single chat room version

FEATURE

  1. Multi-person chat, simple and beautiful interface, use ueditor to support sending text and picture information
  2. Group chat member list, log in and log out announcement
  3. Store chat history, view historical messages

technical point

  1. Use CopyOnWriteMap to store websocketServer objects, thread-safe
  2. redis stores message records
  3. ConcurrentLinkedQueue stores chat members

EVERYTHING

  1. High concurrency is not handled, and high concurrency will put great pressure on the server and memory. The solution is to implement distributed
  2. Currently, all members are in one chat room, and it is planned to isolate multiple chat rooms according to the chat room ID (using Redis storage)

main logic code
@ServerEndpoint(value="/websocketServer", configurator=SpringConfigurator.class, encoders = { CommonMessageEncoder.class, SystemMessageEncoder.class, HistoryMessageEncoder.class})
public class WebsocketServer {
	//Store the websocketServer instance and login name map corresponding to each client
    private static CopyOnWriteMap<WebsocketServer, String> webSocketUsernameMap = new CopyOnWriteMap<WebsocketServer, String>();
    
    private MessageDao messageDao = (MessageDao)ContextLoader.getCurrentWebApplicationContext().getBean("messageDao");
    
    // online member
    private static ConcurrentLinkedQueue<String> members = new ConcurrentLinkedQueue<String>();

    //each websocket client talks to the server
    private Session session;
    
    public WebsocketServer() {
    }
    
    @OnOpen
    public void onOpen(Session session) {
        this.session = session;
    }
    
    @OnClose
    public void onClose() {
        String username = webSocketUsernameMap.get(this);
        removeMember(username);
        webSocketUsernameMap.remove(this);
        
        for (WebsocketServer webSocket : webSocketUsernameMap.keySet()) {
            try {
                sendMsg(webSocket, new SystemMessageResponse(MessageType.SYS_MSG, username, "exit", members));
            } catch (Exception e) {
                e.printStackTrace ();
            }
        }
    }
    
    @OnMessage
    public void onMessage(String message, Session session) {
    	JSONObject messageObject = new JSONObject(message);
    	String type = messageObject.getString("messageType");
    	String content = messageObject.getString("message");
    	
    	if (type.equals(MessageType.COM_MSG)) {
            // group message
    		Date time = new Date();
    		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    		
    		for (WebsocketServer item : webSocketUsernameMap.keySet()) {
    			try {
    				sendMsg(item, new CommonMessageResponse(MessageType.COM_MSG, sdf.format(time), webSocketUsernameMap.get(this), content));
    			} catch (Exception e) {
    				e.printStackTrace ();
    			}
    		}
    		ChatMessage msg = new ChatMessage(sdf.format(time), webSocketUsernameMap.get(this), content);
    		messageDao.save(msg);
    	} else if (type.equals(MessageType.SYS_MSG)) {
            //After the link is successful, the client will send the login name to record here
    		webSocketUsernameMap.put(this, content);
            addMember(content);
            
        	for (WebsocketServer webSocket : webSocketUsernameMap.keySet()) {
                try {
                	sendMsg(webSocket, new SystemMessageResponse(MessageType.SYS_MSG, content, "enter", members));
                } catch (Exception e) {
                    e.printStackTrace ();
                }
            }
    	} else {
    		try {
    			List<ChatMessage> historyMessage = messageDao.getList();
            	sendMsg(this, new HistoryMessageResponse(MessageType.HIS_MSG, historyMessage));
            } catch (Exception e) {
                e.printStackTrace ();
            }
    	}
    }
    
    @OnError
    public void onError(Session session, Throwable error) {
        error.printStackTrace();
    }

    private void sendMsg(WebsocketServer webSocket, Object message) throws Exception {
        webSocket.session.getBasicRemote().sendObject(message);
    }
    
    public static int getMembersCount() {
        return members.size();
    }

    public static void addMember(String member) {
    	members.add(member);
    }

    public static void removeMember(String member) {
        members.remove(member);
    }
}

renderings



Multiplayer, multichat room version

FEATURE

  1. Multi-person chat, multi-chat room, independent of each other, simple and beautiful interface, use ueditor to support sending text and picture information
  2. Group chat member list, log in and log out announcement
  3. Store chat history, view historical messages

technical point

  1. Use CopyOnWriteMap to store Session objects, thread-safe
  2. redis stores message records
  3. redis store chat members
main logic code
@ServerEndpoint(value="/websocketServer/{chatRoomId}", configurator=SpringConfigurator.class, encoders = { CommonMessageEncoder.class, SystemMessageEncoder.class, HistoryMessageEncoder.class})
public class WebsocketServer {
	private ChatRoomDao chatRoomDao = (ChatRoomDao)ContextLoader.getCurrentWebApplicationContext().getBean("chatRoomDao");
    private MessageDao messageDao = (MessageDao)ContextLoader.getCurrentWebApplicationContext().getBean("messageDao");
    private ChatroomMemberDao chatroomMemberDao = (ChatroomMemberDao)ContextLoader.getCurrentWebApplicationContext().getBean("chatroomMemberDao");

//    private Session session;
    
    public WebsocketServer() {
    }
    
    @OnOpen
    public void onOpen(Session session) {
//        this.session = session;
    }
    
    @OnClose
    public void onClose(Session session, @PathParam("chatRoomId") String chatRoomId) {
        String username = chatRoomDao.get(chatRoomId, session);
        chatroomMemberDao.remove(chatRoomId, username);
        chatRoomDao.remove(chatRoomId, session);
        
        for (Session sesion : chatRoomDao.getKeys(chatRoomId)) {
            try {
                sendMsg(sesion, new SystemMessageResponse(MessageType.SYS_MSG, username, "exit", chatroomMemberDao.getAll(chatRoomId)));
            } catch (Exception e) {
                e.printStackTrace ();
            }
        }
    }
    
    @OnMessage
    public void onMessage(String message, Session session, @PathParam("chatRoomId") String chatRoomId) {
    	JSONObject messageObject = new JSONObject(message);
    	String type = messageObject.getString("messageType");
    	String content = messageObject.getString("message");
    	
    	if (type.equals(MessageType.COM_MSG)) {
            // group message
    		Date time = new Date();
    		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    		
    		for (Session sesion : chatRoomDao.getKeys(chatRoomId)) {
    			try {
    				sendMsg(sesion, new CommonMessageResponse(MessageType.COM_MSG, sdf.format(time), chatRoomDao.get(chatRoomId, session), content));
                } catch (Exception e) {
                    e.printStackTrace ();
                }
            }
			ChatMessage msg = new ChatMessage(sdf.format(time), chatRoomDao.get(chatRoomId, session), content);
			messageDao.save(chatRoomId, msg);
    	} else if (type.equals(MessageType.SYS_MSG)) {
    		chatRoomDao.save(chatRoomId, session, content);
            chatroomMemberDao.save(chatRoomId, content);
            
        	for (Session sesion : chatRoomDao.getKeys(chatRoomId)) {
                try {
                	sendMsg(sesion, new SystemMessageResponse(MessageType.SYS_MSG, content, "enter", chatroomMemberDao.getAll(chatRoomId)));
                } catch (Exception e) {
                    e.printStackTrace ();
                }
            }
    	} else {
    		try {
    			List<ChatMessage> historyMessage = messageDao.getList(chatRoomId);
            	sendMsg(session, new HistoryMessageResponse(MessageType.HIS_MSG, historyMessage));
            } catch (Exception e) {
                e.printStackTrace ();
            }
    	}
    }
    
    @OnError
    public void onError(Session session, Throwable error) {
        error.printStackTrace();
    }

    private void sendMsg(Session session, Object message) throws Exception {
        session.getBasicRemote().sendObject(message);
    }
}
renderings


one-on-one chat

technical point

  1. One-to-one relationship maintenance
  2. redis store chat history

TODU

  1. Close associated chats when offline
  2. achieve distributed

main logic code
//Online friend list controller
@ServerEndpoint(value="/websocketServer", configurator=SpringConfigurator.class, encoders = {SystemMessageEncoder.class, CommonMessageEncoder.class, HistoryMessageEncoder.class})//这边的session会被websocket中调用发送commonmessage,所以需要引入CommonMessageEncoder
public class WebsocketServer {
	private ChatRoomDao chatRoomDao = (ChatRoomDao)ContextLoader.getCurrentWebApplicationContext().getBean("chatRoomDao");
    private ChatroomMemberDao chatroomMemberDao = (ChatroomMemberDao)ContextLoader.getCurrentWebApplicationContext().getBean("chatroomMemberDao");

    public WebsocketServer() {
    }
    
    @OnOpen
    public void onOpen(Session session) {
    }
    
    @OnClose
    public void onClose(Session session) {
        String username = chatRoomDao.getUname(session);
        chatroomMemberDao.remove(username);
        chatRoomDao.remove(session);
        
        for (Session sesion : chatRoomDao.getSessionKeys()) {
            try {
                sendMsg(sesion, new SystemMessageResponse(MessageType.SYS_MSG, username, "exit", chatroomMemberDao.getAll()));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    
    @OnMessage
    public void onMessage(String message, Session session) {
    	JSONObject messageObject = new JSONObject(message);
        String content = messageObject.getString("message");
    	String messageType = messageObject.getString("messageType");
    	
        if (messageType.equals(MessageType.SYS_MSG)) {
    		chatRoomDao.save(session, content);
            chatroomMemberDao.save(content);
            
        	for (Session sesion : chatRoomDao.getSessionKeys()) {
                try {
                	sendMsg(sesion, new SystemMessageResponse(MessageType.SYS_MSG, content, "enter", chatroomMemberDao.getAll()));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    @OnError
    public void onError(Session session, Throwable error) {
        error.printStackTrace();
    }

    private void sendMsg(Session session, Object message) throws Exception {
        session.getBasicRemote().sendObject(message);
    }
}

一对一逻辑处理
//一对一聊天控制器
@ServerEndpoint(value="/chatServer", configurator=SpringConfigurator.class, encoders = {SystemMessageEncoder.class, CommonMessageEncoder.class, HistoryMessageEncoder.class})
public class ChatServer {
	private ChatRoomDao chatRoomDao = (ChatRoomDao)ContextLoader.getCurrentWebApplicationContext().getBean("chatRoomDao");
    private ChatSessionStorageDao chatSessionStorageDao = (ChatSessionStorageDao)ContextLoader.getCurrentWebApplicationContext().getBean("chatSessionStorageDao");
    private HistoryMessageDao historyMessageDao = (HistoryMessageDao)ContextLoader.getCurrentWebApplicationContext().getBean("historyMessageDao");
    
    public ChatServer() {
    }
    
    @OnOpen
    public void onOpen(Session session) {
    }
    
    @OnClose
    public void onClose(Session session) {
    	chatSessionStorageDao.closeSession(session);
    }
    
    @OnMessage
    public void onMessage(String message, Session session) {
    	JSONObject messageObject = new JSONObject(message);
    	String messageType = messageObject.getString("messageType");
    	String from = messageObject.getString("from");
    	String to = messageObject.getString("to");
    	
        if (messageType.equals(MessageType.SYS_MSG)) {
            chatSessionStorageDao.save(from, to, from, session);
            List<ChatMessage> historyMessages = historyMessageDao.get(from, to);
            if (historyMessages.size() > 0) {
            	try {
					sendMsg(session, new HistoryMessageResponse(MessageType.HIS_MSG, historyMessages));
				} catch (Exception e) {
					e.printStackTrace();
				}
            }
        } else if (messageType.equals(MessageType.COM_MSG)) {
        	String sendMessage = messageObject.getString("message");
        	
        	//先从一对一session存储Map中查找session
        	Session toSession = chatSessionStorageDao.getSession(from, to, to);
        	
        	if (toSession == null) {
        		//没找到就从所有的session列表中查找
        		toSession = chatRoomDao.getSession(to);
        	}
        	
        	if (toSession == null) {
        		try {
					sendMsg(session, new SystemMessageResponse(MessageType.SYS_MSG, to, "", null));
				} catch (Exception e) {
					e.printStackTrace();
				}
        	} else {
        		Date time = new Date();
        		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        		
        		try {
        			historyMessageDao.save(from, to, new ChatMessage(sdf.format(time), from, sendMessage));
        			sendMsg(session, new CommonMessageResponse(MessageType.COM_MSG, sdf.format(time), from, sendMessage));
        			sendMsg(toSession, new CommonMessageResponse(MessageType.COM_MSG, sdf.format(time), from, sendMessage));
        		} catch (Exception e) {
        			e.printStackTrace();
        		}
        	}
        }
    }
    
    @OnError
    public void onError(Session session, Throwable error) {
        error.printStackTrace();
    }

    private void sendMsg(Session session, Object message) throws Exception {
        session.getBasicRemote().sendObject(message);
    }
}


效果图


Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325827437&siteId=291194637
Recommended