- 일반적으로 채팅방은 다수의 사람이 있고, 앞에서 구현했던 보내는 사람과 받는 사람이 지정되어 있는 경우에 1:1채팅이나 귓속말을 할 때 사용되므로, 채팅방을 구현해보자
Chat클래스 수정
@Data
@Document(collection = "chat")
public class Chat {
@Id
private String id;
private String msg;
private String sender; // 보내는 사람
private String receiver; // 받는 사람
private LocalDateTime createdAt;
private Integer roomNum; // 방 번호
}
ChatRepository 수정
@Tailable
@Query("{roomNum:?0}")
Flux<Chat> mFindByRoomNum(Integer roomNum);
ChatController 수정
@CrossOrigin
@GetMapping(value = "/chat/roomNum/{roomNum}", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<Chat> findByRoomNum(@PathVariable Integer roomNum) {
return chatRepository.mFindByRoomNum(roomNum)
.subscribeOn(Schedulers.boundedElastic());
}
- 이걸로 단체 채팅방을 위한 메서드를 추가하였다.
chat.js 수정
// 로그인 시스템 대신 임시 방편
let username = prompt("아이디를 입력하세요");
let roomNum = prompt("채팅방 번호를 입력하세요");
// SSE 연결하기
//EventSource url은 백틱으로 수정하고 ${roomNum}로 pathvariable을 넣어주자.
const eventSource = new EventSource(`http://localhost:8080/chat/roomNum/${roomNum}`);
eventSource.onmessage = (event) => {
const data = JSON.parse(event.data);
// 만약 로그인한 유저가 보낸 메세지라면
if(data.sender === username){
//파란 박스(오른쪽)를 생성하는 메서드로 연결해주고
initMyMessage(data);
}else{ // 로그인한 유저가 보낸 메세지가 아니라면
//회색박스(왼쪽)를 생성하는 메서드로 연결해주자
initYourMessage(data);
}
}
// 파란박스 만들기
// 기존에 2개의 인자를 받는 대신에 data 객체 자체를 받아서 처리하자
function getSendMsgBox(data){
// 날짜를 처리하기 위한 메서드
let md = data.createdAt.substring(5,10);
let tm = data.createdAt.substring(11,16);
convertTime = tm + " | " + md;
return `<div class="sent_msg">
<p>${data.msg}</p>
<span class="time_date"> ${convertTime} / ${data.sender} </span>
</div>`;
}
// 회색박스 만들기
function getReceiveMsgBox(data){
let md = data.createdAt.substring(5,10);
let tm = data.createdAt.substring(11,16);
convertTime = tm + " | " + md;
return `<div class="received_withd_msg">
<p>${data.msg}</p>
<span class="time_date"> ${convertTime} / ${data.sender} </span>
</div>`;
}
// 최초 초기화될 때 1번방에 3건이 있으면 3건을 다 가져옴
// addMessage()함수 호출시 db에 insert되고, 그 데이터가 자동으로 흘러들어온다(SSE)
// 파란박스 초기화하기
function initMyMessage(data){
let chatBox = document.querySelector("#chat-box");
let sendBox = document.createElement("div");
sendBox.className="outgoing_msg";
sendBox.innerHTML=getSendMsgBox(data);
chatBox.append(sendBox);
// 스크롤을 내려주는 이벤트
document.documentElement.scrollTop = document.body.scrollHeight;
}
// 회색박스 초기화하기
function initYourMessage(data){
let chatBox = document.querySelector("#chat-box");
let receivedBox = document.createElement("div");
receivedBox.className="received_msg";
receivedBox.innerHTML=getReceiveMsgBox(data);
chatBox.append(receivedBox);
// 스크롤을 내려주는 이벤트
document.documentElement.scrollTop = document.body.scrollHeight;
}
// ajax 채팅 메세지를 전송
// await로 이 메서드가 종료되지 않는다면 다른 메서드들도 완료가 되지 않기 떄문에 비동기 메서드로 바꿔줌
async function addMessage(){
let msgInput = document.querySelector("#chat-outgoing-msg");
let chat = {
sender : username,
roomNum : roomNum,
msg: msgInput.value
};
fetch("http://localhost:8080/chat",{ // 통신에 시간이 걸리므로 await를 걸어 대기하게 해줌
method:"post",
body: JSON.stringify(chat), // js -> json으로 변환
headers:{
"Content-Type":"application/json;charset=utf-8"
}
});
msgInput.value="";
}
// 버튼 클릭시 메시지 전송
document.querySelector("#chat-send").addEventListener("click", () => {
addMessage();
})
// 엔터를 치면 메시지 전송
document.querySelector("#chat-outgoing-msg").addEventListener("keydown", (e) => {
if(e.keyCode===13){
addMessage();
}
})
- 이벤트가 발생하면 EventSource가 이를 캐치해 username에 따라 initMyMessage나 initYourMessage를 실행시켜 chatbox에 메세지 내용을 입력해주기 때문에 기존에 addMessage()에서 chatbox에 메세지 내용을 입력하는 부분은 삭제하였다.
- 또 addMessage()에서 chatbox에 메세지 내용을 입력할 필요가 없기 때문에 fetch의 reponse 값을 따로 담아줄 필요가 없다.
- 이제 브라우저 2개를 열어서 확인을 해보면 사용자는 자신이 작성한 메세지만 파란 박스로 뜨고 다른 사람이 쓴 메세지는 회색 박스로 뜨는 것을 확인할 수가 있다!


- 그리고 위의 채팅방은 100번, 아래 채팅방은 101번인데 서로 채팅방에 영향을 미치지 않는다는 것도 확인하였다!
chat.html 수정
- 이제 초기에 설정해뒀던 더미 데이터는 필요 없으므로 chat-box만 남겨두고 다 비워주자. 그리고 채팅 방을 확인해보면 프로필 부분에 더미 데이터가 뜨는것도 수정해주자
<div class="profile_name">
<img src="./img/profile.png" class="mr-3 rounded-circle">
<span id="username"></span></div>
<div class="container-fluid chat_section" id="chat-box">
</div>
- 프로필은 prompt로 정보를 받을 때 초기화할 것이다.
chat.js 수정
// 로그인 시스템 대신 임시 방편
let username = prompt("아이디를 입력하세요");
let roomNum = prompt("채팅방 번호를 입력하세요");
document.querySelector("#username").innerHTML=username;
- 맨 위쪽 username과 roomnum을 받는 코드 바로 아래에 초기화 코드를 넣어주었다. 그러면 아래처럼 username이 뜨는 것을 확인할 수 있다.

- 프로필이나 메세지가 정상적으로 뜨는 것을 확인할 수 있다!

- 마지막으로 받은 메세지만 css를 조금 수정해주자
mystyle.css에서 아래의 클래스를 수정해주자
.received_withd_msg { width: 57%; margin-bottom: 8px;}
.mesgs {
float: left;
padding: 30px 15px 0 25px;
width: 60%;
}