그 동안 채팅에만 빠져있던 내가 드디어 마무리 글을 적을 수 있었다.
....
멋모르고 채팅을 구현해보고 싶은 마음에 이것저것 찾아보니 채팅은 보통 socket.io로 적용하고
자바로는 많이 안하는 느낌이 들었었다.
초반에 Websocket으로만 진행했을 때 채팅이 되는 것을 보고 엄청 신기해하고 뿌듯했었는데
그것도 잠시 한명만 나가면 websocket이 끊겨서 재연결하려고 애를 많이 먹었었다.
java websocket 재연결, websocket 재연결, java 채팅 재연결.. 등등 검색을 해봤는데
어떤 곳은 재연결 때문에 문제가 생겼으니 socket.io로 적용해서 문제를 해결했다! 라는 걸 보고
나도 socket.io로 해야되나.. 잠시 흔들렸었다....
나는 당연히 재연결을 서버에서 해줘야 하는줄알고 back 코드만 주구장창 파헤쳤다.
그런데 막상 해결하고 보니 프론트 문제였고 누군가 나갔을 때 재연결 시켜주면 되는 문제였다,,
setTimeout(function () {
socket = new WebSocket("ws://localhost:8080/websocket");
}, 1000);
문제를 해결하면 보통 뿌듯하고 개운한데 이번 문제만은 화가났다.
왜 이 쉬운걸 나는 빨리 해결못했을까.. 라는 생각에😭
채팅이라는 형식은 완성했으나 내가 원하는 것은 고객센터였다.
고객센터라면 나와 관리자 외에는 해당 채팅방을 들어오지 못한다.
하지만 내가 구현한 것은 모두의 채팅방이였다.
어떻게 하면 채팅방을 따로따로 구현할 수 있을까에 대해서 고민을 했다.
그 과정에서 스터디를 같이 하던 친구가 SSE 방식을 알려줬다.
SSE 방식에 관한 글을 보니 채팅보다는 채팅이 왔다는 알림을 띄워주는 서비스에 맞겠다라는 생각이 들어서
채팅 구현 끝나면 해야겠다라는 생각으로 KEEP 하고 검색을 해봤다.
그러던 중 WebSocket을 좀 더 효율적으로 다룰 수 있다는 프로토콜인 Stomp이 있다라는 것을 알게 되었다.
내가 작성한 WebSocket에서는 (맞게 활용을 잘 못해서 이렇게 적는걸수도 있지만)
Handler로 작성할 때 메세지를 보내면 나 아니면 무조건 상대로 띄워지게 해둬서
고객센터를 구현하는데 한계가 있었다.
(ex. 내가 관리자인데 관리자 구분을 하기 힘들다, 로그인을 하면 어떻게 username을 받고 띄울까? 등등)
그런데 Stomp를 사용했을 때는 header에 여러 정보를 넣어두고
그것을 controller에서 잘 받아서 서비스로 처리하면 끝이니깐 되게 간편했다.
header에 roomId, sender, type을 넣어서 client와 server에서 해당 정보로 고객센터를 구현할 수 있었다.
채팅의 주요 기능 중 또 다른 하나는 채팅기록 가져오기라고 생각했다.
처음에는 client에서 저장해서 띄워주는 걸로 하려고 했다. 그런데 내가 생각한대로 잘 되지 않았다. (뚀륵🥲)
그래서 서버로 옮겼다. db에 저장한 것보다는 파일로 저장하는게 낫다고 생각해서
파일로 저장하려고 하는데 이마저도 쉽지 않았었다.
내가 원하는 방향은 [ {}, {} ] 이렇게 저장하는 방식인데
검색을 해봐도 다들 한번만 실행시키고 끝낸건지 모르겠다,,
그래서 원하는 값을 띄우기 위해서 컴퓨터와 대화를 많이 했다. 하핳😄 왜 안되는거야..?
고객센터 채팅방을 구현하고 보니 뭔가 좀 더 업그레이드한 채팅방을 구현하고 싶은 욕심이 스멀스멀 올라왔다.
채팅 구현한 블로그들을 보다가 어떤 분이 작성한 글을 보니 채팅을 구현할 때 비동기로 구현해야한다고 했다.
그래서 비동기 해봐야쥐! 하고 찾아보다가 랜덤채팅 예제를 보고 구현해봤다.
여기서 thread pool을 사용해봤고 DeferredResult를 알게 되었다.
*DeferredResult란 어떤 요청에 대한 응답 이벤트를 Queue에 저장하고 있다가
DeferredResult.setResult() 가 호출되면 DispatcherServlet으로 응답을 보낸다. https://kmhan.tistory.com/638
2명이서 랜덤채팅을 test하다보니 궁금해졌다. 과연 3명이 동시에 접속하면 몇명이서 채팅하는거지?
그 궁금증은 JMeter로 해결했다.
이제 랜덤채팅도 해보고 고객센터도 구현해봤으니 SSE도 해봐야겠다 라면서 알림 서비스를 구현했다.
SSE는 websocket보다는 코드가 간단했다.
서버에서 보내주는 정보로 클라이언트에서 해당보낼 때 user와 admin을 구분지어서 알림을 띄웠다.
또한 랜덤채팅에서 구현했던 비동기 처리를 활용했다.
여기서는 문제가 없었냐? 그건 아니다.
SSE 코드를 작성하기 전에 SSE의 문제점에 대해서 먼저 봤다.
그래서 그런지 SSE를 문제 없이 사용하는 방법에 대해서 고민했다.
나는 JPA를 사용하고 있었는데 여기에 SSE를 사용하게 되면 Connection 고갈문제가 있다고 했다.
그리고 여기서도 LAZY 로딩에 관해 보게 되었다.
sping.jpa.open-in-view : false 로 설정하고 나면 모든 지연 로딩을 트랜잭션 안에서 처리해야하는 단점이 있다.
→ MainService와 QueryService(읽기 전용)로 나누거나 실시간이 필요없는 경우에는 true로 설정한다고 한다.
아직 분리를 시키지 못했지만 위 문제를 해결하기 위해서 분리가 최선이라면 해야할 것 같다
기능을 다 구현했다고 생각하니 심심해졌다.
그러다가 문득 stomp를 공부했을 때 header에 security를 적용해서 보안을 강화할 수 있다는 글이 생각났다.
그래서 jwt token을 넣기 위해서 security를 적용하려 했다.
이미 본 project인 adme에는 security가 적용되어있는데 다른 방법으로 로그인하는 방법을 구현해보려다가
소셜 로그인이 생각나서 OAuth를 적용했다.
CREATE TABLE IF NOT EXISTS kakao (
kakao_id bigint(5) NOT NULL AUTO_INCREMENT,
username varchar(255) NOT NULL,
password varchar(255) NOT NULL,
email varchar(255) NOT NULL,
role enum('USER', 'ADMIN') not null ,
kakao_idx bigint(5) Not NULL,
PRIMARY KEY (kakao_id)
);
(OAuth + JWT 정리 글은 다듬는 중이라서 올리면 링크 올릴 예정! 쉽게 정리하는 것 너무 어렵,,)
소셜 로그인 후에 index page에서 storage에 token값을 저장하고
고객센터 채팅방에 접속하면 연결 요청 할 때 header에 token을 넣어서 server에 보내고
server에서 해당 header를 받아 처리하는 로직을 작성했다.
...
이렇게 채팅구현을 했고 추가로 기능을 더 추가할지도 모르지만
현재까지는 이렇게 마무리하고 빨리 배포준비,,
'TIL' 카테고리의 다른 글
com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure (0) | 2023.06.27 |
---|---|
[백준] N과 M(1) - 해설 (0) | 2023.04.14 |
socket 채팅방 (0) | 2023.01.23 |
프로젝트 요약 (0) | 2023.01.16 |
security refactoring 코드 정리 (0) | 2023.01.03 |