Spring WebFlux를 이용한 chat 프로그램 - 다듬기
2025. 5. 12. 11:15ㆍJAVA/Spring Boot
우선 앞서 진행했던 것들 중 몇가지를 수정했다.
1. localhost:5173/ 로 접근했을 때 Login 화면으로 이동 처리
App.jsx 부분 수정
import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom';
return (
<Router>
<Routes>
<Route path="/" element={<Navigate to="/login" replace />} />
{/* 3. Route 목록을 Loof 돌리면서 route의 componentName에 해당하는 component를 조회한다. */}
{routeList.length === 0 ? (
<Route path="*" element={<div>라우트 불러오는 중...</div>} />
) : (
routeList.map((route, index) => {
const Component = components[route.componentName];
if (!Component) return null;
return (
<Route
key={index}
path={route.path}
element={<Component />}
/>
);
})
)}
</Routes>
</Router>
);
<Route path="/" element={<Navigate to="/login" replace />} /> 이 부분에서 자동으로 login 페이지로 리디렉션 수행한다.
2. 채팅 시 사용자 nickname 처리 방식 및 좌측 채팅방 이동 처리
ChatMessage.jsx 부분 수정
export default function ChatMessage() {
...
// userState('myUsername') -> userState({})로 변경
// 로그인한 user 객체를 담아야 하기 때문에 변경
const [currentUser, setCurrentUser] = useState({});
...
/**
* 채팅방 목록을 조회한다.
*/
async function loadRooms() {
...
// 로그인한 사용자 정보 추가
const user = localStorage.getItem('user')
setCurrentUser(JSON.parse(user))
// 채팅방에 입장 중인 참여자 정보를 조회한다.
const participantsRes = await chatRoomService.selectParticipants(selected.id)
if (participantsRes.data.success) {
/*
* 기존에는
* const names = participantsRes.data.data.map(u => u.nickname); // 또는 username
* 이런 식으로 nickname만 저장했었지만 nickname은 바뀔 수 있기 때문에
* 사용자의 id로 변경하도록 처리 하기 위해 user Object로 변경
*/
const participants = participantsRes.data.data; // 참여자 목록
setParticipants(participants);
}
...
}
// 메시지를 전송한다.
const handleSend = () => {
if (input.trim()) {
const msg = {
sender: currentUser.id, //currentUser에서 currentUser.id로 변경
content: input,
avatar: '/avatar.png',
};
socketRef.current.send(JSON.stringify(msg));
setInput('');
}
};
// sender id로 nickname 찾기 함수 추가
const getNickname = (senderId) => {
const found = participants.find(p => p.id === senderId);
return found ? found.nickname : `사용자(${senderId})`;
};
...
return (
...
{/* 메시지 영역 */}
<div className="flex flex-col flex-1">
...
{messages.map((msg, idx) => {
// msg.sender === currentUser -> msg.sender === currentUser.id로 변경
const isMine = msg.sender == currentUser.id; // 메시지의 발신자가 현재 사용자와 같은지 확인
return (
<div key={idx} className={`flex ${isMine ? 'justify-end' : 'justify-start'}`}>
<div className={`flex items-end gap-2 ${isMine ? 'flex-row-reverse' : ''}`}>
<img src={msg.avatar} alt={msg.sender} className="w-8 h-8 rounded-full border shadow" />
<div className="flex flex-col max-w-[66%]">
<p className={`
text-xs text-gray-500 mb-1
${isMine ? 'text-right' : 'text-left'}`}
>{getNickname(msg.sender)}</p> {/* nickname 조회를 위해 getNickname 처리*/}
<div
className={`
px-4 py-2 rounded-xl shadow inline-block min-w-[10rem] break-words whitespace-normal
${isMine ? 'bg-blue-500 text-white self-end' : 'bg-gray-100 text-black self-start'}
`}
>
{msg.content}
</div>
</div>
</div>
</div>
);
})}
...
)
기존에 myUsername이라고 테스트 했던 항목을 실제로 사용하는 사용자들의 id를 통해 nickname를 가져오도록 처리 했다.
이렇게 하면 나중에 nickname가 변경되더라도 변경된 nickname를 보여 줄 수 있다.
3. 좌측 채팅방 클릭 시 이동 처리
ChatMessage.jsx 부분 수정
import { useNavigate, useParams } from 'react-router-dom'; //useNavigate 추가
export default function ChatMessage() {
...
const navigate = useNavigate()
...
// 채팅방 이동 처리 함수 추가
const handlerMoveRoom = (roomId) => {
navigate(`/chat/${roomId}`)
}
return (
<div className="flex h-screen">
{/* 채팅방 목록 */}
<div className="w-1/5 border-r bg-gray-100 p-4 overflow-y-auto">
<h2 className="text-lg font-bold mb-4">채팅방</h2>
<ul className="space-y-2">
{rooms.map((room) => (
<li
key={room.id}
className="p-2 rounded bg-white shadow"
onClick={() => handlerMoveRoom(room.id)} {/* 채팅방 클릭 시 이동 */}
>
🗨️ {room.name}
</li>
))}
</ul>
</div>
...
)
4. 방 이동 시 메시지 깜빡 거리는 현상
이유는 WebSocket가 이전 채팅방의 메시지를 계속 수신하고 있는 상태에서 새로운 채팅방으로 이동했기 때문에 발생하는 현상이다. 이런 현상을 방지하기 위해 수정해야 한다.
ChatMessage.jsx 부분 수정
/**
* WebSocket 연결을 초기화한다.
*/
async function initWebSocket() {
// 이전 WebSocket 연결이 있다면 닫도록 추가한다.
if (socketRef.current) {
socketRef.current.close();
}
// WebSocket 연결을 초기화한다.
const socket = new WebSocket(`ws://localhost:8080/ws/chat/${roomId}`);
socketRef.current = socket;
socket.onopen = () => {
console.log('WebSocket 연결 성공');
};
// WebSocket 메시지 전달 받은 경우
socket.onmessage = (e) => {
const msg = JSON.parse(e.data);
// roomId가 없는 경우 무시하도록 추가
if( !msg.roomId ) return;
// 메시지 수신 시 메시지 목록에 추가한다.
if (msg.roomId.toString() != roomId.toString()) return;
setMessages((prev) => [...prev, msg]);
};
}
useEffect(() => {
if (!roomId) return;
// 🔁 채팅방이 바뀔 때 메시지 초기화
setMessages([]);
...
}, [roomId]);
여기까지...
이제 방장의 경우 사용자를 관리할 수 있는 기능을 만들어야 겠다.
'JAVA > Spring Boot' 카테고리의 다른 글
Spring WebFlux를 이용한 chat 프로그램 - 채팅(2) (0) | 2025.05.10 |
---|---|
Spring WebFlux를 이용한 chat 프로그램 - 채팅(1) (0) | 2025.05.09 |
Spring WebFlux를 이용한 chat 프로그램 - 채팅방생성(2) (0) | 2025.05.09 |
Spring WebFlux를 이용한 chat 프로그램 - 채팅방생성(1) (0) | 2025.05.08 |
Spring WebFlux를 이용한 chat 프로그램 - WebSocket 설정 (0) | 2025.05.08 |