2024. 8. 7. 18:22ㆍFCB2O4
기존에 쓰던 자동 스크롤 내리기 때문에 엔터키를 누를 때마다 웹페이지 전체의 스크롤이 아래로 내려가는 현상이 발생
useEffect(() => {
if (messagesContainerRef.current) {
messagesContainerRef.current.scrollTop = messagesContainerRef.current.scrollHeight;
}
}, [messages]);
scrollTop : 요소의 수직 스크롤 위치. 숫자가 클 수록 스크롤이 아래에 있음
scrollHeight : 요소의 전체 콘텐츠 높이
messagesContainerRef.current.scrollTop = messagesContainerRef.current.scrollHeight
채팅창의 스크롤이 가장 아래로 이동
-> 요소의 스크롤 위치를 전체 콘텐츠의 높이로 설정하여, 새로운 메시지가 추가될 때 자동으로 스크롤을 아래쪽으로 이동
이제 DB와 연결할 시간.
먼저 DTO, Mapper, Service, Mapper.xml 등을 작성
ChatLog(DTO)
package b2o4.dto;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class ChatLog {
private int msgNo;
private int memberNo;
private String memberId;
private String msgContent;
}
ChatMapper
package b2o4.mapper;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.web.bind.annotation.RequestBody;
import b2o4.dto.ChatLog;
@Mapper
public interface ChatMapper {
//채팅 기록 저장
void recordChatMessage(@RequestBody ChatLog log);
//채팅 기록 삭제
void deleteChatMessage(int msgNo);
}
ChatService + ChatServiceImpl
package b2o4.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import b2o4.dto.ChatLog;
import b2o4.mapper.ChatMapper;
@Service
public class ChatServiceImpl implements ChatService{
@Autowired
private ChatMapper mapper;
@Override
public void recordChatMessage(ChatLog log) {
System.out.println(log.toString());
mapper.recordChatMessage(log);
}
@Override
public void deleteChatMessage(int msgNo) {
System.out.println("삭제할 채팅 번호" + msgNo);
mapper.deleteChatMessage(msgNo);
}
}
ChatMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="b2o4.mapper.ChatMapper">
<!-- 채팅 기록 DB에 넣기 -->
<insert id="recordChatMessage" parameterType="b2o4.dto.ChatLog" useGeneratedKeys="true" keyProperty="msgNo">
INSERT INTO LiveChatMessage(memberNo, msgContent, msgAt) VALUES (#{memberNo}, #{msgContent}, now())
</insert>
<!-- 채팅 삭제 -->
<delete id="deleteChatMessage" parameterType="int">
DELETE FROM LiveChatMessage WHERE msgNo = #{msgNo}
</delete>
</mapper>
ChatController
package b2o4.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import b2o4.dto.ChatLog;
import b2o4.service.ChatService;
import b2o4.vo.ChatMessage;
@RestController
public class ChatController {
@Autowired
private ChatService chatService;
//채팅 주고받게 하기
@MessageMapping("/chat.send")
@SendTo("/topic/messages")
public ChatMessage send(ChatMessage message) {
ChatLog log = new ChatLog();
log.setMemberNo(1);
log.setMsgContent(message.getContent());
System.out.println("리액트에서 들어온 메시지 : " + message.getContent());
System.out.println("임시 멤버 번호 : " + log.getMemberNo());
System.out.println("로그로 들어온 메시지 : " + log.getMsgContent());
chatService.recordChatMessage(log);
return message;
}
//채팅 DB에 넣기
@PostMapping("/chat")
public void recordChatMessage(@RequestBody ChatLog log) {
chatService.recordChatMessage(log);
}
//채팅 내역 불러오기
//삭제할 채팅
@DeleteMapping("/chat")
public void deleteChatMessage(@RequestParam("msgNo") int msgNo) {
chatService.deleteChatMessage(msgNo);
}
}
일단 로그인 정보를 가져온 게 아니기 때문에 멤버 번호를 1로 임시로 지정하고
log.setMsgContent(message.getContent()) 를 통해 채팅 메시지를 dto의 msgContent에 저장.
삭제 기능은 아직 임시로 구현했고, DB에 있는 메시지 삭제 기능은 아직 미구현.
추가로 모든 채팅창 동결 기능 구현
LiveChat.js
//const client .. onConnect function에 다음 구문 추가
client.subscribe('/topic/freezeChat', (response) => {
console.log(freezeChat);
setFreezeChat(JSON.parse(response.body));
});
//handleFreezeChat 함수 수정
const handleFreezeChat = () => {
if (stompClient) {
stompClient.publish({
destination: '/app/chat.freezeChat'
});
stompClient.subscribe('/topic/freezeChat', (response) => {
const newFreezeChatState = JSON.parse(response.body);
setFreezeChat(newFreezeChatState);
});
}
}
그리고 Controller에 다음 구문을 추가하면 끝.
// 채팅 동결
@MessageMapping("/chat.freezeChat")
@SendTo("/topic/freezeChat")
public boolean chatFreezing() {
freezeChat = !freezeChat;
return freezeChat;
}
// 채팅창 동결 상태 가져오기
@GetMapping("/chat/freezeChat")
public boolean getChatFreezing() {
return freezeChat;
}
메시지를 주고 받는 것 처럼 동결 상태도 주고 받는 것처럼 구현하는 것이었다.
이는 나중에 스트리밍 시작 / 종료도 모든 사용자들에게 영향을 주도록 할 때 다시 응용할 예정.