본문 바로가기
Java/Spring

Spring) 관리자와 1:1 채팅 - 채팅 로그 DB 저장 및 채팅 내역 가져오기

by 박채니 2022. 10. 11.
안녕하세요, 코린이의 코딩 학습기 채니 입니다.
개인 포스팅용으로 내용에 오류 및 잘못된 정보가 있을 수 있습니다.

 

채팅 로그 DB 저장

 

chat.jsp

<jsp:include page="/WEB-INF/views/common/header.jsp">
	<jsp:param value="관리자와 1:1채팅" name="title"/>
</jsp:include>

<div class="input-group mb-3">
  <input type="text" id="msg" class="form-control" placeholder="관리자에게 보내는 Message">
  <div class="input-group-append" style="padding: 0px;">
    <button id="sendBtn" class="btn btn-outline-secondary" type="button">Send</button>
  </div>
</div>
<div>
	<ul class="list-group list-group-flush" id="data"></ul>
</div>
<script>
setTimeout(() => {
	stompClient.subscribe(`/app/chat/${chatroomId}`, (message) => {
		console.log(`/app/chat/${chatroomId} : `, message);
		
		const {memberId, msg, time} = JSON.parse(message.body);
		const li = `
			<li class="list-group-item" title="\${time}">\${memberId} : \${msg}</li>
		`;
		const wrapper = document.querySelector("#data");
		wrapper.insertAdjacentHTML('beforeend', li);
	});
}, 500);

document.querySelector("#sendBtn").addEventListener('click', (e) => {
	const msg = document.querySelector("#msg").value;
	if(!msg) return;
	
	const chatlog = {
		chatroomId : `${chatroomId}`,
		memberId : '<sec:authentication property="principal.username"/>',
		msg,
		time : Date.now()
	};
	stompClient.send(`/app/chat/${chatroomId}`, {}, JSON.stringify(chatlog));
	
	// 초기화
	document.querySelector("#msg").value = '';
});
</script>
<jsp:include page="/WEB-INF/views/common/footer.jsp"/>

 

Controller

StompController

@Autowired
ChatService chatService;

@MessageMapping("/chat/{chatroomId}")
@SendTo("/app/chat/{chatroomId}")
public ChatLog chatLog(@RequestBody ChatLog chatlog) {
    log.debug("chatlog = {}", chatlog);
    int result = chatService.insertChatLog(chatlog);

    return chatlog;
}

MessageMapping으로 받아서 DB insert 처리 후 다시 '/app/chat/chatroomId'로 넘겨주었습니다.

 

Service (interface 생략)

ChatServiceImpl

@Override
public int insertChatLog(ChatLog chatlog) {
    return chatDao.insertChatLog(chatlog);
}

 

Dao

ChatDao interface

@Insert("insert into chat_log values(seq_chat_log_no.nextval, #{chatroomId}, #{memberId}, #{msg}, #{time})")
int insertChatLog(ChatLog chatlog);

 

하지만 자꾸 채팅로그가 2개씩 나오는 것을 확인할 수 있습니다.

이를 해결해보겠습니다.

네트워크를 확인해보면, content-type이 있고/없고에 대한 차이가 있는 것을 확인할 수 있습니다.

분기처리를 통해 한 번만 출력되도록 하겠습니다.

setTimeout(() => {
	stompClient.subscribe(`/app/chat/${chatroomId}`, (message) => {
		const {'content-type':contentType} = message.headers;
		
		if(!contentType) {
			console.log(`/app/chat/${chatroomId} : `, message);
			
			const {memberId, msg, time} = JSON.parse(message.body);
			const li = `
				<li class="list-group-item" title="\${time}">\${memberId} : \${msg}</li>
			`;
			const wrapper = document.querySelector("#data");
			wrapper.insertAdjacentHTML('beforeend', li);
		}
		
	});
}, 500);

한 번만 출력되는 것을 확인할 수 있습니다.


기존 채팅 내역 불러오기

- 기존 채팅 내역이 있다면, 그대로 가져와 보여줘야 함

 

Controller

ChatController

@GetMapping("/chat.do")
public void chat(Authentication authentication, Model model) {
    // 1. 채팅방 유무 조회
    Member loginMember = (Member)authentication.getPrincipal();
    ChatMember chatMember = chatService.findChatMemberByMemberId(loginMember.getMemberId());
    log.debug("chatMember = {}", chatMember);

    String chatroomId = null;
    if(chatMember == null) {
        // 처음 입장한 경우
        chatroomId = generateChatroomId();
        log.debug("chatroomId = {}", chatroomId);
        // chatmember insert 2행! (관리자/로그인회원)
        List<ChatMember> chatMembers = Arrays.asList(
                    new ChatMember(chatroomId, loginMember.getMemberId()),
                    new ChatMember(chatroomId, "admin") // ROLE로 admin을 구별하지만, 일단 'admin' 아이디로 고정!
                );
        chatService.insertChatMembers(chatMembers);
    } else {
        // 재입장한 경우
        chatroomId = chatMember.getChatroomId();
        List<ChatLog> chatLogs = chatService.findChatlogByChatroomId(chatroomId);
        log.debug("chatLogs = {}", chatLogs);
        model.addAttribute("chatLogs", chatLogs);
    }
    model.addAttribute("chatroomId", chatroomId);
}

 

Service interface 생략

ChatServiceImpl

@Override
public List<ChatLog> findChatlogByChatroomId(String chatroomId) {
    return chatDao.findChatlogByChatroomId(chatroomId);
}

 

Dao

ChatDao interface

@Select("select * from chat_log where chatroom_id = #{chatroomId} order by no")
List<ChatLog> findChatlogByChatroomId(String chatroomId);

 

chat.jsp

<div class="input-group mb-3">
  <input type="text" id="msg" class="form-control" placeholder="관리자에게 보내는 Message">
  <div class="input-group-append" style="padding: 0px;">
    <button id="sendBtn" class="btn btn-outline-secondary" type="button">Send</button>
  </div>
</div>
<div>
	<ul class="list-group list-group-flush" id="data">
		<c:if test="${not empty chatLogs}">
			<c:forEach items="${chatLogs}" var="log">
			<%
				ChatLog chat = (ChatLog) pageContext.getAttribute("log");
				String time = new Date(chat.getTime()).toString();
			%>
				<li class="list-group-item" title="<%= time %>">${log.memberId} : ${log.msg}</li>			
			</c:forEach>
		</c:if>
	</ul>
</div>