실시간 채팅 기능이 어느정도 구현되었으니 다듬기를 들어간다.
원하는건 채팅의 구분이 안되는것과 안내와 같은 부분이 부족하다.
카톡과 비슷하게 구현해보고싶다. 구현된 모습은 우선 다음과 같다. 다른 브라우저를 통해서 로그인된 유저와 로그인되지 않은 유저의 상황을 연출했다.
chatting.js
전반적으로 코드가 복잡해지긴한다. 로그인시 생성되는 클라이언트 쿠키로부터 사용자 이름을 받아오도록했다. 다른 방법들로 user의 Authentication을 받아오는 것을 구현해보고 싶다.
const client = new StompJs.Client({
brokerURL: 'ws://192.168.0.2:8080/websocket'
// 브로커주소를 서버 IP로 수정해야한다.
// brokerURL: 'ws://localhost:8080/websocket'
});
client.onConnect = (frame) => {
setConnected(true);
console.log('Connected: ' + frame);
client.subscribe('/chatMessage', (chatting) => {
showChatting(JSON.parse(chatting.body).content);
});
};
client.onWebSocketError = (error) => {
console.error('Error with websocket', error);
};
client.onStompError = (frame) => {
console.error('Broker reported error: ' + frame.headers['message']);
console.error('Additional details: ' + frame.body);
};
function setConnected(connected) {
$("#chatConnect").prop("disabled", connected);
$("#chatDisconnect").prop("disabled", !connected);
$("#message").html("");
// 연결 상태에 따라 메시지 추가
var message = connected ? "[System] 채팅방에 연결되었습니다." : "[System] 채팅방에서 나갔습니다.";
showChatting(message);
}
function connect() {
client.activate();
}
function disconnect() {
client.deactivate();
setConnected(false);
console.log("Disconnected");
}
// 클라이언트에서 토큰을 추출하는 함수 정의
function extractUsernameFromToken(token) {
try {
const base64Url = token.split('.')[1];
const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
const jsonPayload = decodeURIComponent(atob(base64).split('').map(function(c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join(''));
const payload = JSON.parse(jsonPayload);
return payload.sub; // 토큰에서 유저 이름 추출
} catch (error) {
console.error('Error extracting username from token:', error);
return null;
}
}
// 토큰 가져오기 함수 정의
function getJwtToken() {
// 여기에서 실제로 토큰을 가져오는 로직을 작성해야 함
// 예시로 쿠키에서 토큰을 가져오는 방식 사용
const name = "Authorization=";
const decodedCookie = decodeURIComponent(document.cookie);
const cookieArray = decodedCookie.split(';');
for (let i = 0; i < cookieArray.length; i++) {
let cookie = cookieArray[i].trim();
if (cookie.indexOf(name) === 0) {
return cookie.substring(name.length, cookie.length);
}
}
return null;
}
// 토큰이 없을 경우 "[Unknown]" 반환하는 함수
function getUsernameOrUnknown() {
const token = getJwtToken();
return token ? extractUsernameFromToken(token) : "Unknown";
}
// 채팅 메시지 전송 시 유저 이름을 함께 전송
function sendMessage() {
const chattingMessage = $("#chattingMessage").val();
const username = getUsernameOrUnknown(); // 수정: getUsernameOrUnknown 사용
if (username) {
const messageToSend = `[${username}] ${chattingMessage}`;
// 전송할 메시지 구성
client.publish({
destination: "/app/chat",
body: JSON.stringify({'chattingMessage': messageToSend})
});
// 텍스트 입력 부분으로 커서 이동 및 내용 비우기
$("#chattingMessage").val('').focus();
} else {
console.error('Username not available.');
}
}
function showChatting(message) {
// 메시지를 추가할 div 요소 선택
var conversationDiv = $("#conversation");
// 메시지를 담을 새로운 div 생성
var messageDiv = $("<div>").addClass("chat-message").text(message);
// 현재 유저인지 확인
const isCurrentUser = message.includes(`[${getUsernameOrUnknown()}]`);
// 오른쪽 정렬이면 클래스 추가
if (isCurrentUser) {
messageDiv.addClass("current-user");
}
// conversationDiv에 messageDiv 추가
conversationDiv.append(messageDiv);
// 스크롤을 최하단으로 이동 (새 메시지가 보이도록)
conversationDiv.scrollTop(conversationDiv.prop("scrollHeight"));
}
$(function () {
$("#chatConnect").click(() => connect());
$("#chatDisconnect").click(() => disconnect());
$("#messageSend").click(() => sendMessage());
// textarea에서 엔터 키 감지
$("#chattingMessage").keydown(function (e) {
if (e.which === 13 && !e.shiftKey) {
e.preventDefault(); // 엔터 키 기본 동작 방지
$("#messageSend").click(); // 전송 버튼 클릭
// 텍스트 입력 부분으로 커서 이동 및 내용 비우기
$(this).val('').focus();
}
});
});
Java
복사
CSS를 통해 카톡like 메신저 색상을 입혀보았다.
/* CSS 스타일 추가 */
.chat-container {
height: 300px;
min-height: 300px;
max-height: 300px; /* 채팅 창의 최대 높이 설정 (스크롤이 생길 경우) */
overflow-y: auto; /* 스크롤이 필요한 경우 스크롤이 나타나도록 설정 */
border: 1px solid #ccc; /* 창 테두리 추가 */
border-radius: 8px; /* 테두리 모서리를 더 부드럽게 만듦 */
background-color: #dcecff; /* 창 배경 색상 변경 */
}
.chat-message {
padding: 5px;
margin-bottom: 5px;
background-color: #efefef;
border-radius: 5px;
}
.current-user {
text-align: right;
background-color: #ffe11e; /* 오른쪽으로 정렬된 메시지의 배경색 */
}
Java
복사
chatting.html
html은 그대로이다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="shortcut icon" href="#">
<link rel="stylesheet" type="text/css" href="/assets/23_HP010_iLanD-main/nav.css">
<link rel="stylesheet" type="text/css" href="/assets/23_HP010_iLanD-main/chatting.css">
<link href="/css/style.css" rel="stylesheet" />
<script src="https://code.jquery.com/jquery-3.6.4.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script src="/assets/23_HP010_iLanD-main/nav.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@stomp/stompjs@7.0.0/bundles/stomp.umd.min.js"></script>
<script src="/assets/23_HP010_iLanD-main/chatting.js"></script>
<title> Chatting Room </title>
</head>
<body>
<!-- Navigation -->
<nav class="navbar navbar-expand-xxl navbar-dark bg-white">
<div class="container px-9">
<a href="#"><img width="32" height="32" src="/assets/23_HP010_iLanD-main/icon/iLanD_logo.png" onclick="openPage('/')"></a>
<h5> Chatting Room </h5>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"><span class="navbar-toggler-icon"></span></button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav ms-auto mb-2 mb-lg-0">
<li class="nav-item"><a class="nav-link" aria-current="page" href="/">Home</a></li>
<li class="nav-item"><a class="nav-link" href="/movies&tv">Movies&TV</a></li>
<li class="nav-item"><a class="nav-link" href="/game">Game</a></li>
<li class="nav-item"><a class="nav-link" href="/chatting">Chatting</a></li>
<li class="nav-item"><a class="nav-link" href="/announcement">Announcement</a></li>
<li class="nav-item"><a class="nav-link" href="/aboutus_page">About Us</a></li>
<li class="nav-item"><a class="nav-link" href="/service_guide">Service Guide</a></li>
<li class="nav-item"><a class="nav-link" href="/login">Login(Staffs&Admin)</a></li>
</ul>
</div>
</div>
</nav>
<div class="card mb-4">
<div class="card-header" style="background-color: #EFF4F9"> 채팅 페이지 </div>
<div class="card-body watch_area d-flex justify-content-center">
<!-- 컨텐츠(여기부터 삽입 됩니다.) -->
<div id="main-content" class="container">
<div class="d-flex justify-content-between" style="padding: 10px">
<button id="chatConnect" class="btn btn-primary" type="button" style="padding: 10px">채팅방 입장</button>
<button id="chatDisconnect" class="btn btn-danger" type="button" disabled="disabled" style="padding: 10px">채팅방 나가기</button>
</div>
<div class="col-md-12">
<div id="conversation" class="chat-container">
<!-- 채팅 내용이 동적으로 추가될 곳 -->
</div>
</div>
<div class="d-flex justify-content-between" style="padding-top: 10px">
<input type="text" id="chattingMessage" class="form-control" placeholder="메시지를 입력하세요...">
<button id="messageSend" class="btn btn-success" type="button" style="width: 70px">전송</button>
</div>
</div>
</div>
</div>
<!-- 컨텐츠(여기까지 삽입 됩니다.) -->
</body>
</html>
Java
복사