고래씌

[Spring] 10-4. 채팅방 메세지 통신 (F5를 누르지않아도 바로 생성되도록 작업) 본문

Server/Spring

[Spring] 10-4. 채팅방 메세지 통신 (F5를 누르지않아도 바로 생성되도록 작업)

고래씌 2024. 1. 30. 11:38

1. 채팅방 메세지 실시간 전송(F5를 누르지않아도 바로 생성되도록 작업)

 
☞ 메시지를 db에 성공적으로 저장했다면, 전달받은 메시지를 같은방에 접속중인 클라이언트들에게 전달
☞ ChatWebSocket.java에 추가
☞ public void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {} 메소드 안에 추가
 
참여한 인원이 중복되지 않도록 DB에 제약조건 추가

ALTER TABLE CHAT_ROOM_JOIN ADD PRIMARY KEY(USER_NO, CHAT_ROOM_NO);

 
 
 
 
▶ ChatWebSocket.java

 

	/* 클라이언트로부터 메시지(message)가 도착했을 시 실행되는 함수 */
	@Override
	public void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
		// TextMessage : 웹소켓을 이용해 전달된 데이터(텍스트)가 담겨있는 객체
		
		// payload : 전송되는 데이터(JSON객체로 전달받음)
		log.info("전달된 메시지{}", message.getPayload());
		
		// JackSon 라이브러리 : Java에서 JSON을 다루기 위한 라이브러리
		// JackSon-databind : objectMapper를 이용해서 JSON형태로 넘어온 데이터를 특정 VO필드에 맞게 자동으로 매핑시켜줌
		
		ObjectMapper objectMapper = new ObjectMapper();
		ChatMessage chatMessage = objectMapper.readValue(message.getPayload(), ChatMessage.class);  // 값의 타입은 ChatMessage.class
		
		// 전달받은 메세지를 DB에 CHAT_MESSAGE테이블에 추가
		int result = chatService.insertMessage(chatMessage);
		
		// 메시지를 db에 성공적으로 저장했다면, 전달받은 메시지를 같은방에 접속중인 클라이언트들에게 전달
		if(result > 0) {
			for(WebSocketSession s : sessions) {
				// 반복을 진행중인 WebSocketSession에 담겨있는 "방번호" 빼오기
				// 채팅방에 입장을 할 때마다 방번호가 세션스코프에 저장이 될 것임.
				// 세션안에 담겨있는 데이터는 handshake 덕분에 httpSession정보를 WebSocketSession에 넣을 것임.
				int chatRoomNo = (int) s.getAttributes().get("chatRoomNo");  // 반환형이 Object여서 강제형변환
				// chatRoomNo를 꺼내옴
				
				// log.info("접속중인 사용자의 채팅방번호 : {}", chatRoomNo);
				
				// 메시지에 담겨있는 채팅방 번호와, 현재 웹소켓세션에 저장된 채팅방번호를 비교하여 동일한 경우 해당 웹소켓세션에 메세지 전달
				if(chatMessage.getChatRoomNo() == chatRoomNo) {
					// chatMessage의 매개변수로 작성해서 보내야함. 이것도 JSON으로 변환해주는 작업필요 => Gson 이용
					s.sendMessage(new TextMessage(new Gson().toJson(chatMessage)));  
				}
			}
		}
	}

 
☞ 메시지에 담겨있는 채팅방 번호와, 현재 웹소켓세션에 저장된 채팅방번호를 비교하여 동일한 경우 해당 웹소켓세션에 메세지 전달
☞ chatMessage의 매개변수로 작성해서 보내야함. 이것도 JSON으로 변환해주는 작업필요 => Gson 이용
 
 
☞ 메이븐레파지토리 접속하여 Gson 코드 복사하여 pom.xml에 추가

 
▶ pom.xml

		<!-- 챗웹소켓에서 필요한 Gson -->
		<!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.10</version>
        </dependency>

 
 
▶ chat.js
☞ 서버쪽 웹소켓핸들러에서 클라이언트소켓으로 메세지를 전달(sendMessage)하는 구문을 감지하는 이벤트 핸들러
 
 

 
=> ㅎㅎㅎ 라는 메세지를 보낸다고하면, 이런 데이터가 넘어가는 것을 볼 수 있다.
=> 전달된 메세지는 e.data내부에 (JSON)형태로 보관되어있다!
=> 전달받은 메세지를 JS객체로 변환할 예정
 
 
- 서버쪽 웹소켓핸들러에서 클라이언트소켓으로 메세지를 전달(sendMessage)하는 구문을 감지하는 이벤트 핸들러

// 서버쪽 웹소켓핸들러에서 클라이언트소켓으로 메세지를 전달(sendMessage)하는 구문을 감지하는 이벤트 핸들러
chattingSocket.onmessage = function(e){
	console.log(e);
	// 전달된 메세지는 e.data내부에 (JSON)형태로 보관되어있음
	
	// 전달받은 메세지를 JS객체로 변환
	const chatMessage = JSON.parse(e.data);
	
	const li = document.createElement("li"); // <li>
	
	const p = document.createElement("p"); // <p></p>
	p.classList.add("chat");
	
	// p태그 내부에 글내용추가 및 개행처리
	p.innerHTML = chatMessage.message.replace(/\\n/gm, "<br>"); // <p class="chat">전달받은메세지</p>

    const span = document.createElement("span");
    span.classList.add("chatDate"); // <span class="chatDate">??</span>
    span.innerText = currentTime();  // <span class="chatDate">2024-01-30</span>

    // 내가 쓴 채팅인지, 상대방이 쓴 채팅인지 확인
    if(chatMessage.userNo == userNo){
        // 내가쓴글
        li.classList.add("myChat"); // 내가쓴글에 해당하는 스타일 적용
        li.append(span, p);
    }else {
        // 남이 쓴 글
        li.innerHTML = `<b>${chatMessage.userName}</b>`;
        li.append(p, span)
    }

    // 채팅창 요소가져오기
    const display = document.querySelector(".display-chatting");

    // 채팅창에 채팅내용 추가하기
    display.append(li)

    // 채팅창 맨 아래로 내리기
    display.scrollTop = display.scrollHeight;
    // scrollTop : 스크롤의 위치
    // scrollHeight : 스크롤되는 요소(display)의 전체 높이
}

 
 
- 현재시간 출력 함수  ex) 2024-01-30
 getFullYear: 2024 2025... 연도표시

// 현재시간 출력 함수  ex) 2024-01-30
// getFullYear: 2024 2025... 연도표시
function currentTime(){
    const now = new Date();
    return `${now.getFullYear()}-${now.getMonth()+1 < 10 ? "0"+ (now.getMonth() +1) : now.getMonth() +1}-${now.getDate() < 10 ? "0" +now.getDate() : now.getDate()}`;   
}

 
 
- 페이지 로딩 완료후 => window.onload, 채팅창을 맨 아래로 내리는 작업
=> 즉시실행함수(IIFE, 속도 빠름, 변수명 중복문제도 해결)
=> () 괄호안에 익명함수를 넣어줌. 바로 실행해주기 위해서!
=> 뒤쪽에 함수호출 연산자를 넣음
=> 스크롤이 알아서 맨아래로 내려갈 것임!

(function(){
	const display = document.querySelector(".display-chatting");

	// 채팅창 맨 아래로 내리기
    display.scrollTop = display.scrollHeight;
})();

 
 
 
▶ chat-mapper.xml
=> 날짜 형식대로 뽑혀서 출력하기 위해서 아래와 같이 수정. 

 
 
▶ 결과

 
☞ 다른 브라우저창을 열어서 테스트를 해도 다른 사용자가 메시지를 보내면 바로 전달되는 것도 볼 수 있다!
IP주소:80881/spring 하면 다른사람의 채팅방에도 접속가능하다!