Spring으로 실시간 채팅 서비스 만들기: WebSocket을 활용한 채팅 구축 가이드
채팅 서비스은 어떻게 만들까?
Q&A 플랫폼에 채팅 서비스를 제공하기로 했다. 채팅 서비스는 이왕 만드는 김에 실시간 채팅이 가능하도록 만들려고 한다. 또 회사에서 재택으로 스스로 공부할 수 있도록 며칠을 줘서 채팅 서비스를 한번 구축하는 것을 목표로 교육시간을 보내기로 했다.
우선 지금까지의 나의 지식으로는 채팅 시스템은 이렇게 만들어야 할 것 같았다.
- A라는 사람이 B와의 채팅방을 만든다.
- A라는 사람이 채팅을 보낸다.
- A가 보낸 채팅은 서버를 통해 데이터베이스에 저장된다.
- B라는 사람은 채팅방에 들어와 있다면 주기적으로 서버에 요청을 보내서 새로운 채팅이 있는지 확인한다.
- A가 보낸 채팅이 있다면 B의 화면에 띄워준다
이렇게 구현을 해야할거 같았는데 이렇게 구현을 하면 당연히 문제가 되는 것은
- 서버에 계속 되는 요청은 서버를 힘들게 할 것이다.
- 주기적으로 서버에 요청은 한다는것은 실시간이 아니다. 주기가 n 초라면 최대 n 초 동안은 실시간이 아니니까
뭘까… 다른 채팅 서비스 들은 어떻게 구현이 되어 있는거지??? 라는 생각이 들어 구글링을 시작했다.
Websocket
기존 http통신은 client 로 부터 server 에게 보내는 요청만 있었다면 websocket 은 server가 client 에게도 반대로도 그러니까 양방향으로 통신이 가능하게 한 프로토콜이다! 이런것이 있었다니… 역시 똑똑한 사람들이 많다 라는 생각을 하게 되었다. 그렇다면 아까의 프로세스는 이렇게 변할 수 있을 것이다.
- A 라는 사람이 B와의 채팅방을 만든다.
- A 라는 사람이 채팅을보낸댜ㅏ.
- A가 보낸 채팅은 서버를 통해 데이터 베이스에 저장된다.
- A가 보낸 채팅은 서버에서 client 측으로 현재 채팅방에 접속해 있는 사람들 즉 B에게 채팅을 전달한다. 이렇게 되면 서버에 요청을 계속해서 보낼 필요도 없고 실시간으로 채팅을 주고 받을 수 있게 된다!!
Spring 에서 Websocket 연결하기
우선 client 단에서 server 와 websocket 연결을 시도해야 한다.
1
2
3
var sock = new SockJS("/echo");
sock.onmessage = onMessage; // 메시지가 서버로부터왔을때
sock.onclose = onClose; // 연결 끊길때
그 다음은 server 에서 받아야하니 /echo
를 endpoint로 하도록 하여 다음과 같이 한다
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@RequestMapping("/echo")
@Component
public class EchoHandler extends TextWebSocketHandler {
private List<WebSocketSession> sessions = new ArrayList<WebSocketSession>();
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
sessions.add(session);
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
sessions.remove(session);
}
}
client 가 /echo로 websocket 연결 요청을 보내면 위에서 afterCnnetionEstablished 가 불리고 끊어질때 (웹페이지를 벗어날때) afterConnectionClosed가 불리게 된다.
이제 연결이 완료 되었다. 그렇다면 메시지를 주고 받아야한다.
메시지 주고 받기
1
2
3
4
function sendMessage(msg){
if($("#msg-input").val().trim().length === 0) return;
sock.send("msg:" + $("#msg-input").val());
}
client 측에서 위와 같이 sock 에 send 를 해주면 이제 spring 의 함수가 불린다.
1
2
3
4
5
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
{다른 WebSocketSession}.sendMessage();
}
그럼 다른 websocketsession 에게 그러니까 채팅방에 접속중인 다른 session 에 sendMessage 를 해주면 된다.
그러면 서버로 부터 메세지를 전달 받는것이니 websocket 연결이 되어있는 다른 client 단에서 아래의 코드가 챡실행 되면서 실시간으로 채팅을 받게 된다!
1
2
3
4
function onMessage(msg) {
let data = msg.data;
// 메시지 적당한곳에 끼워넣기
}
간단한 채팅 서비스를 교육중에 만들어 보았고 이것을 토대로 Q&A 플랫폼에 채팅 서비스를 구축해야겠다!
https://github.com/bwbw-kim/chatting