Chatrooms with history conversations, user’s online status, notification of unread messages using Spring Boot, Angular, MySQL

Trang Nguyen
Geek Culture
Published in
4 min readAug 29, 2021

I was doing a forum project, and one of the features is to allow multiple users to chat with each other. I thought it was easy at first because there are so many tutorials about real-time chat apps. However, it turns out that most of the tutorials are about building a basic one-to-one chat app without storing the history conversation, or they use different tech stacks (React, NodeJS, Firebase), or they don’t have all the necessary functionalities of a chat app. It took me a couple of days to find out the solutions and complete these chat features.

Fun fact: When I shared with my teammate that I wanted to have this chat feature in our project, he told me that he hasn’t had much experience with WebSocket and couldn’t help me much. But I insisted on giving it a try. “If we don’t push ourselves to the limit, we won’t be able to learn new things,” — I said. And finally, he let me learn WebSocket and try the features in a week.

My approach is to search for tutorials and read the document; then, I practice the basic concepts. After grasping the fundamentals, I started with the easiest feature of the app and, finally, the most challenging one. However, I still want to improve a couple of things, like sending JSON objects to the frontend instead of text, but it probably requires a more advanced technique like RabbitMQ. I’ll save it for future projects.

When I showed him the completed chat features, he said that: “You’re solid like a rock;”

I want to share my solutions so that some people won’t take as much time as I did. Also, I’m open to any feedback for a better solution and performance.

The features I built include:

  1. Allow multiple users to have private conversations with each other
  2. Show user’s status (online/ offline)
  3. Store history conversations
  4. Get notifications for any unread messages
  5. Prevent anonymous users to connect through WebSocket

Allow multiple users to have private conversations with each other

To send a message to a specific user, I will send the message to a default endpoint that starts with “/user,” “/user/queue/messages” for example.

And my front end will have to map with this endpoint.

Show user’s status (online/ offline)

When a user logs in, they will start to subscribe to the broker. But so far, the server only knows about users when they start sending messages to it. How can the server observe their status and notify the controller when users log in and log out (stop subscribing) and who is doing that subscription?

I found out that WebSocketEventListener can help with this.

Basically, handleWebSocketConnectListener(SessionConnectedEvent event) catches any user subscribes to (“/user”) and extract the headers to get userId and username. Then I created a set of online users and added new users to this. If any user logs out (unsubscribe), handleWebSocketDisconnectListener(SessionDisconnectEvent event) will be invoked and remove that user out of the Set<OnlineUserDto>.
To get a list of online/offline users, I injected WebSocketEventListener to WSUserController and this controller send the list of online and offline users to the front end every 3 seconds.

Store history conversations

I created a chatroom for each conversation between two users and generated a unique id to identify the exchange between two users. The chatroomId is generated by concatenating senderId_recipientId. For each conversation, it will have two entries with the same chatRoomId, one room is between sender and recipient, the other one is between recipient and sender. The reason to create 02 entries is to make sure that both users get the same chatRoomId so that every time one user sends a message, it can find a chat room by senderId and recipientId.

The chatRoomId is then set to the message, and the message is saved to the database and marked as RECEIVED, which means unread.

Get notifications for any unread messages.

The server doesn’t send a message directly to the user but a notification. When the user clicks on the chat area, the client will call an HTTP request to the server to load all messages between sender and recipient and marked as DELIVERED. This gif helps to illustrate my idea better

Prevent anonymous users to connect through WebSocket

The problem is that the security config for HTTP and WebSocket are different. Even though I can set up authentication for HTTP endpoints, I cannot reuse HTTP configuration for WebSocket. To be more specific, every HTTP request to the server must contain the header with “Authorization” to authenticate the user, but StompJs in the client cannot set that custom header in the initial handshake. My current solution is to let the WebSocket server accept the handshake without any authentication check; standard HTTP headers are available at this stage. Besides, the client checks if a user is authenticated, then the chatbox is available for chatting.

These chat features are part of my forum website project. I put all these websocket codes in here and Angular codes are integrated in the chatbox and chatpanel components.

Source code of the forum project:
Backend: https://github.com/trangntt-016/seneca-forum-backend
Frontend: https://github.com/trangntt-016/senecaforum-frontend

If you enjoy this article, please clap it up 👏 and share it so that others can find it! 😄.

--

--

Trang Nguyen
Geek Culture

Computer Programming Student @Seneca. Writing to share solutions and encourage my sister to write.