관리 메뉴

거니의 velog

(17) 마이 트립 > 만남의 광장 페이지 > 코드 리뷰 본문

대덕인재개발원_최종 포트폴리오

(17) 마이 트립 > 만남의 광장 페이지 > 코드 리뷰

Unlimited00 2024. 2. 16. 15:28

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://tiles.apache.org/tags-tiles" prefix="tiles" %>
<c:set value="${pageContext.request.contextPath }" var="contextPath" />
<!DOCTYPE html>
<html lang="ko">
    <head>
        <meta charset="UTF-8" />
        <meta name="author" content="부루마불" />
        <meta name="description" content="대덕인재개발원 7월반 4조 부루마불의 여기갈래 프로젝트입니다." />
        <meta name="keywords" content="부루마불, 여기갈래, 여행, 통합, 플랫폼" />
        <meta name="copyright" content="대덕인재개발원" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>여기갈래 &gt; 파트너</title>
        
        <!-- 사용자 페이지 > 헤더세팅 영역 -->
        <tiles:insertAttribute name="headerSettings" />
    	
    	<!-- 
    		내부 CSS 
    		- 내부 CSS는 외부 CSS의 스타일링을 건드리지 않기 위해서
    		개별적인 페이지에다 스타일을 적용할 때 종종 쓴다.
    		- 보통 프로토타이핑 테스트용이나, FE Leader의 판단에 따라 여기에
    		추가적인 스타일을 작성한다.
    	-->
    	<style>
    		.msub a {
    			color: #333;
    		}
    	</style>
    	
    	<c:if test="${not empty message }">
		    <script type="text/javascript">
		        //alert("${message}");
		        $(function(){
		        	// 성공시
		        	<c:if test="${msgflag eq 'su'}">
		        		Swal.fire({
		                    title: "성공",
		                    text: "${message}",
		                    icon: "success"
		                });
		        	</c:if>
		        	// 실패시
		        	<c:if test="${msgflag eq 'fa'}">
			        	Swal.fire({
		                    title: "실패",
		                    text: "${message}",
		                    icon: "error"
		                });
		        	</c:if>
		        	// 정보성 메시지
		        	<c:if test="${msgflag eq 'in'}">
			        	Swal.fire({
		                    title: "안내",
		                    text: "${message}",
		                    icon: "info"
		                });
		        	</c:if>
		        }); 
		        <c:remove var="message" scope="request" />
		        <c:remove var="message" scope="session" />
		    </script>
		</c:if>
		
	</head>
    <body>
        
        <!-- 사용자 페이지 > 헤더 영역 -->
        <tiles:insertAttribute name="header" />
        
        <!-- 사용자 페이지 > 파트너 구현 영역 -->
        <tiles:insertAttribute name="userPartnerContainer" />
        
        <!-- 사용자 페이지 > 푸터 영역 -->
		<tiles:insertAttribute name="footer" />
		
		<!-- 사용자 페이지 > 자바스크립트 세팅 영역 -->
		<tiles:insertAttribute name="settings" />

    </body>
</html>

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<!-- 마이 트립 css -->
<link href="${contextPath }/resources/css/myTrip.css" rel="stylesheet" />

<section class="myTripChatRoomContainer emptySpace">
    <article class="myTripHeadStyle">
        <div class="myTripImgBox">
            <img src="${contextPath }/resources/images/myTripBgImg.jpg" alt="마이 트립 배경 이미지" />
        </div>
        <div>
            <h3>마이 트립</h3>
            <span>MY TRIP</span>
        </div>
    </article>
    <article class="myTripChatRoomContents cen">
        <div class="chatRoomLeft">
            <div class="chatRoomTabbtnBox">
                <div class="tabbtn tactive">현재멤버</div>
                <c:if test="${recruiter.mategroupRecruiter eq sessionInfo.memId }">
		            <div class="tabbtn">신청멤버</div>
                </c:if>
            </div>
            <div class="chatRoomTabcontBox scroll">
                <div class="tabcont">
                    <ul class="currentMemList">
                        <li>
                            <span>이름</span>
                            <span>성별</span>
                            <span>나이</span>
                            <span>ID</span>
                            <span>결제여부</span>
                        </li>
                        <!-- 반복 구간 -->
                        <c:choose>
                        	<c:when test="${not empty recruiter or not empty mateList }">
                        		<li>
                        			<span class="textDrop appendStatus">
                        				<i class="fas fa-crown"></i>
	                                	<span class="chatProfileImgBox">
	                                    	<img src="${recruiter.memProfileimg }" alt="프로필 이미지" />
	                                	</span>
										<span class="kickOutNameTxt">${recruiter.memName }(플래너)</span>
										<i class="fas fa-circle"></i>
		                            </span>
		                            <span>
		                            	<c:if test="${recruiter.memGender eq 'M' }">
		                            		남자
		                            	</c:if>
		                            	<c:if test="${recruiter.memGender eq 'F' }">
		                            		여자
		                            	</c:if>
		                            </span>
		                            <span class="recruitAge">00세</span>
		                            <span class="textDrop detectMemId">${recruiter.memId }</span>
		                            <span>
		                            	<c:if test="${recruiter.mategroupAgree eq '0' }">
		                            		차감 전
		                            	</c:if>
		                            	<c:if test="${recruiter.mategroupAgree eq '1' }">
		                            		차감 완료
		                            	</c:if>
		                            	<c:if test="${recruiter.mategroupAgree eq '2' }">
		                            		결제 완료
		                            	</c:if>
		                            </span>
		                            <script>
		                            	$(function(){
		                            		var ageDate = '${recruiter.memAgedate }';
			                            	var calcAgeTxt = $.ageCalculateFn(ageDate);
			                            	//console.log("calcAgeTxt : ", calcAgeTxt);
			                            	$(".recruitAge").html(calcAgeTxt + "세");
		                            	});
		                            </script>
                        		</li>
                        		<c:forEach items="${mateList }" var="mate" varStatus="stat">
                       				<c:if test="${mate.mategroupApply eq 'Y' }">
								    	<li class="textDropVerticalAlign">
				                            <span class="textDrop appendStatus">
				                                <span class="chatProfileImgBox">
				                                    <img src="${mate.memProfileimg }" alt="프로필 이미지" />
				                                </span>
												<span class="kickOutNameTxt">${mate.memName }</span>
				                                <i class="fas fa-circle"></i>
				                            </span>
				                            <span>
					                            <c:if test="${mate.memGender eq 'M' }">
			                            			남자
				                            	</c:if>
				                            	<c:if test="${mate.memGender eq 'F' }">
				                            		여자
				                            	</c:if>
				                            </span>
				                            <span id="lgj${stat.index}">00세</span>
				                            <span class="textDrop detectMemId">${mate.memId }</span>
				                            <span>
					                            <c:if test="${mate.mategroupAgree eq '0' }">
			                            			차감 전
				                            	</c:if>
				                            	<c:if test="${mate.mategroupAgree eq '1' }">
				                            		차감 완료
				                            	</c:if>
				                            	<c:if test="${mate.mategroupAgree eq '2' }">
				                            		결제 완료
				                            	</c:if>
				                            </span>
				                            <script>
				                            	$(function(){
				                            		var ageDate = '${mate.memAgedate }';
				                            		var calcAgeTxt = $.ageCalculateFn(ageDate);
					                            	//console.log("calcAgeTxt : ", calcAgeTxt);
                                                    $("#lgj${stat.index}").html(calcAgeTxt + "세");
				                            	});
				                            </script>
				                        </li>
                       				</c:if>
							    </c:forEach>
                        	</c:when>
                        	<c:otherwise>
                        		<li>
		                        	<div style="text-align: center; width: 50%; margin: 0px auto; float: none; cursor: auto; background-color: #333; color: white; padding: 20px; border-radius: 4px;">
					    				현재 멤버가 없습니다.
					    			</div>
		                        </li>
                        	</c:otherwise>
                        </c:choose>
                    </ul>
                </div>
                <c:if test="${recruiter.mategroupRecruiter eq sessionInfo.memId }">
	                <div class="tabcont">
	                    <ul class="waitMemList">
	                        <li>
	                            <span>이름</span>
	                            <span>성별</span>
	                            <span>나이</span>
	                            <span>ID</span>
	                            <span>승인/거절</span>
	                        </li>
	                        <!-- 반복 구간 -->
	                        <c:choose>
	                        	<c:when test="${not empty mateList }">
	                        		<c:set value="0" var="memCntFlag" />
	                        		<c:forEach items="${mateList }" var="mate" varStatus="stat">
	                       				<c:if test="${mate.mategroupApply eq 'W' or mate.mategroupApply eq 'E' }">
	                       					<c:set value="${memCntFlag +1  }" var="memCntFlag" />
									    	<li class="textDropVerticalAlign memChk">
					                            <span class="textDrop appendStatus">
					                                <span class="chatProfileImgBox">
					                                    <img src="${mate.memProfileimg }" alt="프로필 이미지" />
					                                </span>
													${mate.memName }
					                                <i class="fas fa-circle"></i>
					                            </span>
					                            <span>
						                            <c:if test="${mate.memGender eq 'M' }">
				                            			남자
					                            	</c:if>
					                            	<c:if test="${mate.memGender eq 'F' }">
					                            		여자
					                            	</c:if>
					                            </span>
					                            <span id="lgj${stat.index}">00세</span>
					                            <span class="textDrop findId detectMemId">${mate.memId }</span>
					                            <span>
													<c:choose>
														<c:when test="${mate.mategroupApply eq 'E' }">
															<button type="button" class="btn btn-secondary">모집 마감</button>
														</c:when>
														<c:otherwise>
															<button class="btn btn-success acceptMemBtn" type="button">승인</button>
															<button class="btn btn-danger rejectMemBtn" type="button">거절</button>
														</c:otherwise>
					                            	</c:choose>
					                            </span>
					                            <script>
					                            	$(function(){
					                            		var ageDate = '${mate.memAgedate }';
					                            		var calcAgeTxt = $.ageCalculateFn(ageDate);
						                            	//console.log("calcAgeTxt : ", calcAgeTxt);
	                                                    $("#lgj${stat.index}").html(calcAgeTxt + "세");
					                            	});
					                            </script>
					                        </li>
	                       				</c:if>
								    </c:forEach>
                       				<c:if test="${memCntFlag eq 0 }">
	                       				<li style="pointer-events: none;">
				                        	<div style="text-align: center; width: 50%; margin: 0px auto; float: none; cursor: auto; background-color: #333; color: white; padding: 20px; border-radius: 4px;">
							    				현재 멤버가 없습니다.
							    			</div>
				                        </li>
                       				</c:if>
	                        	</c:when>
	                        	<c:otherwise>
	                        		<li style="pointer-events: none;">
			                        	<div style="text-align: center; width: 50%; margin: 0px auto; float: none; cursor: auto; background-color: #333; color: white; padding: 20px; border-radius: 4px;">
						    				현재 멤버가 없습니다.
						    			</div>
			                        </li>
	                        	</c:otherwise>
	                        </c:choose>
	                    </ul>
	                </div>
                </c:if>
            </div>
            <div class="chatRoomInfoBox">
                <label for="meetName">1. 모임이름</label>
                <input class="form-control" type="text" id="meetName" name="meetName" readonly value="${recruiter.plTitle }" />
                <label for="groupPoint">2. 그룹포인트</label>
                <input class="form-control" type="text" id="groupPoint" name="groupPoint" readonly value="${recruiter.mategroupPoint } 포인트" />
                <label for="meetStatus">3. 모집상태</label>
                <form action="/partner/groupRecruitEnded.do" method="post" id="groupRecruitEnded" name="groupRecruitEnded">
					<input type="hidden" id="plNo" name="plNo" value="${recruiter.plNo }" />
                </form>
                <c:choose>
                	<c:when test="${recruiter.mategroupStatus eq '1단계' }">
                		<input class="form-control" type="text" id="meetStatus" name="meetStatus" readonly value="모집중" />
                	</c:when>
                	<c:when test="${recruiter.mategroupStatus eq '2단계' }">
                		<input class="form-control" type="text" id="meetStatus" name="meetStatus" readonly value="모집마감" />
                	</c:when>
					<c:when test="${recruiter.mategroupStatus eq '4단계' }">
						<input class="form-control" type="text" id="meetStatus" name="meetStatus" readonly value="여행종료" />
                	</c:when>
                	<c:otherwise>
                		<input class="form-control" type="text" id="meetStatus" name="meetStatus" readonly value="결제완료" />
                	</c:otherwise>
                </c:choose>
				<button class="btn btn-primary mt-3 travelTheEndBtn"<c:if test="${recruiter.mategroupStatus ne '3단계' }">style= "display:none;"</c:if>>여행종료</button>
            </div>
        </div>
        
        <c:if test="${not empty chatRoomInfo }">
			<c:set value="${chatRoomInfo[0].roomNo }" var="roomNo" />
		</c:if>
        
        <div class="chatRoomRight">
            <div class="yogiChatRoomContBox">
                <div class="chatRoomName">
					${recruiter.plTitle } (${mateCnt }명)
                </div>
                <div class="chatRoomContents scroll">
                	<c:if test="${not empty chatInfoList }">
                		<c:forEach items="${chatInfoList }" var="chatInfo">
                			<c:choose>
                				<%-- 내가 쓴 글임 --%>
                				<c:when test="${chatInfo.memId eq sessionInfo.memId }">
                					<c:choose>
                						<%-- 처음 쓴 글임 --%>
                						<c:when test="${chatInfo.chatCnt eq '1' }">
                							<div class="innerTalker">
                								<div class="innerstartDialogContBox">
                									<div class="talkerImgBox">
                										<img src="${chatInfo.memProfileimg }" alt="상대방 프로필 사진" />
                									</div>
                									<div class="boxLeftRight">
											            <div class="innerName"> 
											            	<span class="chatMemName">${chatInfo.memName }</span> 
											            	<span class="chatMemId" style="display: none;">${chatInfo.memId }</span> 
											            </div>
											            <div class="innerStartDialog">
											                <p class="chatMsgTxt" style="display: inline-block; white-space: pre-wrap;">${chatInfo.chatContent }</p>
											                <div class="chatDateInfo" style="height: 34px;">
											                    <div> 
											                    	<span class="yymmdd">${chatInfo.chatYmd }</span> 
											                    	<br> 
											                    	<span class="hhmmss">${chatInfo.chatHms }</span> 
											                    </div>
											                </div>
											            </div>
											        </div>
                								</div>
               									<span class="myChatCnt" style="display: none;">${chatInfo.chatCnt }</span>
               									<span class="sendMemId" style="display: none;">${chatInfo.memId }</span>
                							</div>
                						</c:when>
                						<%-- 나중에 쓴 글임 --%>
                						<c:otherwise>
              							    <div class="innerTalker">
									            <div class="innerLongtakeDialog">
									                <div>
									                    <p class="chatMsgTxt" style="display: inline-block; white-space: pre-wrap;">${chatInfo.chatContent }</p>
									                    <div class="chatDateInfo" style="height: 34px;">
									                        <div> 
									                            <span class="yymmdd">${chatInfo.chatYmd }</span> 
									                            <br> 
									                            <span class="hhmmss">${chatInfo.chatHms }</span> 
									                        </div>
									                    </div>
									                </div>
									            </div>
									            <span class="myChatCnt" style="display: none;">${chatInfo.chatCnt }</span>
									            <span class="sendMemId" style="display: none;">${chatInfo.memId }</span>
									        </div>
                						</c:otherwise>
                					</c:choose>
                				</c:when>
                				<%-- 다른 사람이 쓴 글임 --%>
                				<c:otherwise>
                					<c:choose>
                						<%-- 처음 쓴 글임 --%>
                						<c:when test="${chatInfo.chatCnt eq '1' }">
              							        <div class="outerTalker">
									            <div class="outerstartDialogContBox">
									                <div class="talkerImgBox"> 
									                    <img src="${chatInfo.memProfileimg }" alt="상대방 프로필 사진" /> 
									                </div>
									                <div class="boxLeftRight">
									                    <div class="outerName"> 
									                        <span class="chatMemName">${chatInfo.memName }</span> 
									                        <span class="chatMemId" style="display: none;">${chatInfo.memId }</span> 
									                    </div>
									                    <div class="outerStartDialog">
									                        <p class="chatMsgTxt" style="display: inline-block; white-space: pre-wrap;">${chatInfo.chatContent }</p>
									                        <div class="chatDateInfo" style="height: 34px;">
									                            <div> 
									                                <span class="yymmdd">${chatInfo.chatYmd }</span> 
									                                <br> 
									                                <span class="hhmmss">${chatInfo.chatHms }</span> 
									                            </div>
									                        </div>
									                    </div>
									                </div>
									            </div>
									            <span class="myChatCnt" style="display: none;">${chatInfo.chatCnt }</span>
									            <span class="sendMemId" style="display: none;">${chatInfo.memId }</span>
									        </div>
                						</c:when>
                						<%-- 나중에 쓴 글임 --%>
                						<c:otherwise>
                							<div class="outerTalker">
											    <div class="outerLongtakeDialog">
											        <div>
											            <p class="chatMsgTxt" style="display: inline-block; white-space: pre-wrap;">${chatInfo.chatContent }</p>
											            <div class="chatDateInfo" style="height: 34px;">
											                <div> 
											                    <span class="yymmdd">${chatInfo.chatYmd }</span> 
											                    <br> 
											                    <span class="hhmmss">${chatInfo.chatHms }</span> 
											                </div>
											            </div>
											        </div>
											    </div>
											    <span class="myChatCnt" style="display: none;">${chatInfo.chatCnt }</span>
											    <span class="sendMemId" style="display: none;">${chatInfo.memId }</span>
											</div>
                						</c:otherwise>
                					</c:choose>
                				</c:otherwise>
                			</c:choose>
                		</c:forEach>
                	</c:if>
                	
                </div>
                <div class="chatRoomBtnGroup">
                    <button class="badge bg-primary planShare" type="button">일정 공유</button>
                    <!-- <button class="badge bg-warning chatPointPush" type="button">차감 요청</button> -->
                    <button class="badge bg-info chatContTxtDown" type="button">채팅 내역</button>
                    <button class="badge bg-danger chatContDelete" type="button">이전 채팅 삭제</button>
                </div>
                <div class="chatRoomInputArea">
                    <textarea class="form-control chatInputMsg"></textarea>
                    <div>
                        <button class="sendChatMessage" type="button">
                            <i class="fas fa-arrow-up"></i>
                        </button>
                    </div>
                </div>
            </div>
            <div class="moveBackBtnBox">
            	<button type="button" class="btn btn-primary moveBackList">목록으로 돌아가기</button>
            </div>
        </div>
    </article>
</section>

<!-- 마이 트립 js -->
<script src="${contextPath }/resources/js/myTrip.js"></script>
<script>
    $(function(){
        // 공통 함수
        var plNo = '${recruiter.plNo}';
        var roomNo = '${roomNo}';
        
        $.myTripChatroomTabbtnFn();
        $.meetNameClickEvent(plNo);
        $.shoppingPlanFn(plNo);
		$.chatContTxtDownFn(plNo);
		$.chatContDeleteFn(plNo);	//df
		$.planShareFn(plNo);		// 일정공유
        
        // 모집 마감은 관리자만 허용해야 함.
        <c:if test="${recruiter.mategroupRecruiter eq sessionInfo.memId }">
        	$.groupRecruitEndedFn();
        </c:if>
        
        $.memBoxEqualChatBoxH();
        $.moveBackListBtnClickFn();
        $.acceptMemBtnClickFn(plNo);
        $.rejectMemBtnClickFn(plNo);
        $.kickOutFn(plNo);
        
        // 채팅 기능
        var chatMemId = '${sessionInfo.memId}';
        var chatMemName = '${sessionInfo.memName}';
        var chatMemProfileimg = '${sessionInfo.memProfileimg}';
        var chatMemObj = {
        	chatMemId : chatMemId,
        	chatMemName : chatMemName,
        	chatMemProfileimg : chatMemProfileimg,
        	chatRoomNo : roomNo
        };
        $.chatingFn(roomNo, chatMemObj);

     	// 채팅방 접속/미접속 감지 웹소켓 기능
        var memId = "${sessionInfo.memId}";
        $.chatInOutDetectWebSocketFn(memId);
        
		// get 기능
        var currentURL = window.location.href;
        
        // get 파라미터값 판정
        var queryStringYN = window.location.search !== '' ? true : false;
        console.log('현재 URL:', currentURL);
        console.log('쿼리스트링 존재 여부:', queryStringYN);
        
        // 승인/거절 메시지 alert 기능
		try {
		    var messageUrlTxt = currentURL.split("message=");
		    if (messageUrlTxt.length > 1) {
		        messageUrlTxt = messageUrlTxt[1].split("&mateCnt=");
		        messageTxt = messageUrlTxt[0];
		        var decodedMessage = decodeURIComponent(messageTxt);
		        //alert(decodedMessage);
		        Swal.fire({
		        	title: "승인/거절",
		        	text: decodedMessage,
		        	icon: "info"
		        }).then((result) => {
		        	location.href = "/partner/meetsquare.do?plNo=" + plNo;
		        });
		    } else {
		        throw new Error('No "message" parameter in the query string');
		    }
		} catch (error) {
		    console.error('Error:', error.message);
		}
		
		// 현재 채팅방 참여자 수 갱신 기능
		var mateCntTxt;
		try {
		    var mateCntUrlTxt = currentURL.split("mateCnt=");
		    if (mateCntUrlTxt.length > 1) {
		        mateCntTxt = mateCntUrlTxt[1];
		        var decodedmateCnt = decodeURIComponent(mateCntTxt);
		        var plTitleTxt = '${recruiter.plTitle}';
		        var insertplTitleTxt = plTitleTxt + " (" + decodedmateCnt + "명)";
		        $(".chatRoomName").html(insertplTitleTxt);
		    } else {
		        throw new Error('No "mateCnt" parameter in the query string');
		    }
		} catch (error) {
		    console.error('Error:', error.message);
		}
        
        // 종횡비 함수
        var myTripImgBox = $(".myTripImgBox");
        var myTripImg = $(".myTripImgBox img");
        $.ratioBoxH(myTripImgBox, myTripImg);
        
        $.eachStartingMemberImgResizeFn();
        
        $.eachChatingMemberImgResizeFn();
    });
</script>

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<script>
    $(function(){
    	// 공통 변수
    	var sessionMemid = "${sessionInfo.memId}";
    	sessionMemid = sessionMemid.trim();
    	console.log("sessionMemid : ", sessionMemid);
    	
        // 공통 함수
        $.mLnbClickEvent();
        $.footerRelatedSiteFn();
        $.mmainClickEvent700();
        
     	// 로그인/로그아웃 감지 기능
        $.loginDetectWebSocketFn(sessionMemid);
        
     	// 실시간 알림 기능 > 전역으로 실시간 알림 뿌리기
     	// 1. 먼저 ajax로 실시간 알림 메시지를 가져온다.
     	$.ajaxRtSenderGetMsgFn(function(result){
     		console.log("result : ", result);
     		
     		// 2. 실시간 알림이 있다면, 최신 1건만 뿌려라!
     		if(result.journeySender != "" && result.journeySender != null && result.journeySender != undefined){
     			console.log("실시간 알림이 최신 1건 있음!");
     			console.log("result.journeySender > ", result.journeySender);
     			
     			console.log("현재 로그인한 멤버와 수신자 아이디가 같음!");
     				
     			var realsenId = result.journeySender.realsenId; // 발신자 아이디
   		        var realsenName = result.journeySender.realsenName; // 발신자 이름
   		        var realsenTitle = result.journeySender.realsenTitle; // 실시간 알림 제목
   		        var realsenContent = result.journeySender.realsenContent; // 실시간 알림 내용
   		        var realsenType = result.journeySender.realsenType; // 여행정보 타입 알림
   		        var realsenReadyn = result.journeySender.realsenReadyn; // 안 읽음
   		        var realsenUrl = result.journeySender.realsenUrl; // 여행 정보 페이지로 이동
    		        
   		        var dbSaveFlag = false; // db에 저장하지 않고 알림만 발송.
   		        var userImgSrc = result.journeySender.realsenPfimg; // 발신자 프로파일 이미지 정보
   		        var realrecNo = result.journeySender.realrecNo;
    		        
   		        var rtAlert = {
      		        "realsenId": realsenId,
      		        "realsenName": realsenName,
      		        "realsenTitle": realsenTitle,
      		        "realsenContent": realsenContent,
      		        "realsenType": realsenType,
      		        "realsenReadyn": realsenReadyn,
      		       	"realsenUrl": realsenUrl,
      		        "realsenPfimg": userImgSrc
      		    };
       		    console.log("플래너 등록 알림 > rtAlert : ", rtAlert);
       		        
    		    $.realTimeAlertWebSocketFn(rtAlert, dbSaveFlag, userImgSrc, realrecNo);
    		        
    		  	// 바로 가기 클릭 시 안 본 실시간 알림을 본 것으로 처리
    	        $(document).on("click", ".rtAlertFadeBtn a", function(e){
    	            e.preventDefault();
    	            console.log("실시간 알림 본 것으로 처리 > realrecNo : ", realrecNo);
    	            $.ajax({
    	                type: "post",
    	                url: "/readRtAlert.do",
    	                data: JSON.stringify(realrecNo),
    	                contentType: "application/json",
    	                dataType: "text",
    	                success: function(res){
    	                	console.log("res : ", res);
    	                }
    	            });
    	            var oriAHref = $(this).attr("href");
    	            location.href = oriAHref;
    	        });
       		  		
     		}
     		
     		// 실시간 알림이 없다면 알림 카운트 숨겨라!
     		if(result.journeyCnt == 0) {
         		$(".alarmIcon span").hide();
         	}
         	
     		// 알림 카운트가 1건 이상 있다면 실행해라!
         	if(result.journeyCnt != "" && result.journeyCnt != null && result.journeyCnt != undefined){
         		// 3. 실시간 알림이 1건 이상 있다면, 카운트를 세서 딸랑이를 울려라!
            	var loginOutIconA = $(".alarmIcon");
            	var loginOutIcon = $(".alarmIcon i");
            	
            	function animateAlert() {
            		loginOutIconA.css("padding-top", "15px");
            		loginOutIcon.css("color", "gold");
            	    loginOutIcon.animate({
            	        rotation: 45,  // 목표 회전 각도
            	        lineHeight : "0px"
            	    }, {
            	        step: function (now, fx) {
            	            if (fx.prop === 'rotation') {
            	                loginOutIcon.css('transform', 'rotate(' + now + 'deg)');
            	            }
            	        },
            	        duration: 500,  // 애니메이션 지속 시간 (0.5초)
            	        complete: function () {
            	            // 두 번째 애니메이션 시작
            	            loginOutIcon.animate({
            	                rotation: -45,  // 초기 회전 각도
            	                lineHeight : "0px"
            	            }, {
            	                step: function (now, fx) {
            	                    if (fx.prop === 'rotation') {
            	                        loginOutIcon.css('transform', 'rotate(' + now + 'deg)');
            	                    }
            	                },
            	                duration: 500,  // 애니메이션 지속 시간 (0.5초)
            	                complete: function () {
            	                    // 세 번째 애니메이션 시작
            	                    loginOutIcon.animate({
            	                        rotation: 0, // 초기 회전 각도
            	                        lineHeight : "0px"
            	                    }, {
            	                        step: function (now, fx) {
            	                            if (fx.prop === 'rotation') {
            	                                loginOutIcon.css('transform', 'rotate(' + now + 'deg)');
            	                            }
            	                        },
            	                        duration: 500  // 애니메이션 지속 시간 (0.5초)
            	                    });
            	                }
            	            });
            	        }
            	    });
            	}

                // 페이지 로드 후 애니메이션 시작
                animateAlert();
                
        	    $(".alarmIcon").find("span").text(result.journeyCnt);
     		} 
         	
     	});
     	
     	// 로그인 알림 1번만 받고 바로 끄는 기능 구현, 1초 뒤에 삭제
     	setTimeout(function(){
        	$.ajaxLoginRtAlertRemove();
     	}, 50);
     	
     	// 딸랑이 클릭하면 마이 페이지 > 알림 목록으로 이동하고, 모두 읽음 처리 하기
     	$.rtAlertClickInitFn(sessionMemid);
	    
        // 종횡비 함수
        var pcgnbMainProfileImgCont = $(".pcgnb .mainProfileImgCont");
        var pcgnbMainProfileImg = $(".pcgnb .mainProfileImgCont img")
        $.ratioBoxH(pcgnbMainProfileImgCont, pcgnbMainProfileImg);
        
        var mgnbMainProfileImgCont = $(".mgnb .mainProfileImgCont");
        var mgnbMainProfileImg = $(".mgnb .mainProfileImgCont img");
        $.ratioBoxH(mgnbMainProfileImgCont, mgnbMainProfileImg);
        
        // 실시간 알림 모달창 기능
        var rtImgBox = $("header .rtImgBox");
        var rtImg = $("header .rtImgBox img")
        $.ratioBoxH(rtImgBox, rtImg);
        
        var rtCloseBtn = $(".rtCloseBtn");
        var rtAlertBox = $(".rtAlertBox");
        rtCloseBtn.click(function(){
            rtAlertBox.hide();
        });
    });
</script>

package kr.or.ddit.utils.websocket;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {

	@Autowired
	@Qualifier("chatHandler")
	private ChatHandler chatHandler;
	
	@Autowired
	@Qualifier("loginDetectHandler")
	private LoginDetectHandler loginDetectHandler;
	
	@Autowired
	@Qualifier("realTimeAlertHandler")
	private RealTimeAlertHandler realTimeAlertHandler;
	
	@Autowired
	@Qualifier("chatInOutHandler")
	private ChatInOutHandler chatInOutHandler;
	
	@Autowired
	@Qualifier("realTimeAlertHandlerChansVer")
	private RealTimeAlertHandlerChansVer realTimeAlertHandlerChansVer;
	
	@Override
	public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
		registry.addHandler(chatHandler, "/chat").setAllowedOrigins("*");
		registry.addHandler(loginDetectHandler, "/logindetect").setAllowedOrigins("*");
		registry.addHandler(chatInOutHandler, "/chatinoutdetect").setAllowedOrigins("*");
		registry.addHandler(realTimeAlertHandler, "/alert").setAllowedOrigins("*");
		registry.addHandler(realTimeAlertHandlerChansVer, "/alertForChan").setAllowedOrigins("*");
	}
	
}

package kr.or.ddit.utils.websocket;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import kr.or.ddit.users.login.vo.MemberVO;
import kr.or.ddit.vo.ChatMembers;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Component
public class ChatHandler extends TextWebSocketHandler {

	// 전체 채팅
	private static List<WebSocketSession> chatSessionList = new ArrayList<WebSocketSession>();
	
	// 락 걸기
	private static final Lock lock = new ReentrantLock();

	// 1. 클라이언트 연결 이후에 실행되는 메소드
	@Override
	public void afterConnectionEstablished(WebSocketSession session) throws Exception {
		log.info("## 누군가 접속");
		
		chatSessionList.add(session);
		log.info("세션 정보 : {}", session.getAttributes());
		
		Map<String, Object> chatSessionMap = session.getAttributes();
		MemberVO chatMember = (MemberVO) chatSessionMap.get("sessionInfo");
		
		if(chatMember == null) { // 웹소켓 아이디를 가져옴
			log.info("웹소켓 아이디 : {}", session.getId());
		}else { // 로그인한 사용자 아이디를 가져옴
			log.info("로그인한 사용자 아이디 : {}", chatMember.getMemId());
		}
	}

	boolean flag = false;
	String chatUser = "";
	
	// 2. 클라이언트가 웹소켓 서버로 메시지를 전송했을 때 실행되는 메소드
	@Override
	protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
		
		Map<String, Object> chatMapSession = session.getAttributes();
		MemberVO chatMember = (MemberVO) chatMapSession.get("sessionInfo");
		
		if (chatMember != null) {
			// 로그인한 아이디와 클라이언트로부터 서버로 보낸 메시지를 받음
			log.info("아이디 "+chatMember.getMemId()+" 로 부터 이름이 "+chatMember.getMemName()+" 인 사람에게 메세지 '"+message.getPayload()+"' 받음");
			
			// 공통 변수 선언
			String preChatTxt = message.getPayload();
			String[] splitChatTxt = preChatTxt.split(",");
			
			String chatMessage = splitChatTxt[0].trim(); // 채팅 내용
			
			String chatCnt = splitChatTxt[1].trim(); // 채팅 횟수
			int intChatCnt = Integer.parseInt(chatCnt);
			String cntTxt = "<span class='myChatCnt' style='display:none;'>"+chatCnt+"</span>";
			
			log.info("채팅 내용 : {}", chatMessage);
			log.info("채팅한 횟수 : {} 회", chatCnt);
			
			String chatMemid = "";
			String chatMemName = "";
			String chatMemProfileimg = "";
			String chatRoomNo = "";
			
			if(intChatCnt == 0) { // 입장/퇴장할 때
				for(WebSocketSession sess : chatSessionList) {
					sess.sendMessage(new TextMessage(chatMessage + "" + cntTxt));
				}
			}
			
			if(intChatCnt >= 1) { // 처음 채팅할 때
				chatMemid = splitChatTxt[2].trim(); // 채팅자 아이디
				if(splitChatTxt[2].equals("empty")) {
					chatMemid = "";
				}
				chatMemName = splitChatTxt[3].trim(); // 채팅자 이름
				if(splitChatTxt[3].equals("empty")) {
					chatMemName = "";
				}
				chatMemProfileimg = splitChatTxt[4].trim(); // 채팅자 프로필 사진 경로
				if(splitChatTxt[4].equals("empty")) {
					chatMemProfileimg = "";
				}
				chatRoomNo = splitChatTxt[5].trim(); // 채팅방 번호
				
				ChatMembers chatmembers = new ChatMembers();
				chatmembers.setChatMemid(chatMemid);
				chatmembers.setChatMemName(chatMemName);
				chatmembers.setChatMessage(chatMessage);
				chatmembers.setChatMemProfileimg(chatMemProfileimg);
				chatmembers.setChatRoomNo(chatRoomNo);
				
				// lock 획득
				lock.lock();
				try {
					// 동시에 실행하면 안되는 코드
					for(WebSocketSession sess : chatSessionList) {
						StringBuffer result = messageSetting(sess, intChatCnt, chatmembers);
						sess.sendMessage(new TextMessage(result));
					}
				} catch (Exception e) {
					e.printStackTrace();
				} finally {
					// lock 해제
					lock.unlock();
				}
				
				chatUser = chatmembers.getChatMemid();
			}
		}
		
	}
	
	private StringBuffer messageSetting(WebSocketSession sess, int intChatCnt, ChatMembers chatmembers) {
		StringBuffer sb = new StringBuffer();
		
		if(!chatUser.equals(chatmembers.getChatMemid())) {
			flag = true;
			System.out.println("######################## 새로운 채팅 유저가 메세지 남김");
			intChatCnt = 1;
		}
		
		// 초기화된 카운트를 채팅에 담아서 보낸다. DB 저장용.
		String cntTxt = "<span class='myChatCnt' style='display:none;'>"+intChatCnt+"</span>";
		log.info("cntTxt : {}", cntTxt);
		
		String memIdTxt = "<span class='sendMemId' style='display: none;'>"+chatmembers.getChatMemid()+"</span>";
		
		String roomNoTxt = "<span class='roomChkFlg' style='display: none;'>"+chatmembers.getChatRoomNo()+"</span>";
		
		String type = "outer";
		Map<String, Object> chatMembers = sess.getAttributes();
		MemberVO memberVO = (MemberVO) chatMembers.get("sessionInfo");
		if(chatmembers.getChatMemid().equals(memberVO.getMemId())) {
			type = "inner";
		}
		
		sb.append("<div class='"+type+"Talker'>");
		
		if(intChatCnt == 1) {
			sb.append("		<div class='"+type+"startDialogContBox'>");
			sb.append("			<div class='talkerImgBox'>");
			sb.append("				<img src='"+chatmembers.getChatMemProfileimg()+"' alt='상대방 프로필 사진' />");
			sb.append("			</div>");
			sb.append("			<div class='boxLeftRight'>");
			sb.append("				<div class='"+type+"Name'>");
			sb.append("					<span class='chatMemName'>"+chatmembers.getChatMemName()+"</span>");
			sb.append("					<span class='chatMemId' style='display: none;'>"+chatmembers.getChatMemid()+"</span>");
			sb.append("				</div>");
			sb.append("				<div class='"+type+"StartDialog'>");
			sb.append("					<p class='chatMsgTxt' style='display: inline-block; white-space: pre-wrap;'>"+chatmembers.getChatMessage()+"</p>");
			sb.append("					<div class='chatDateInfo'>");
			sb.append("						<div>");
			sb.append("							<span class='yymmdd'>"+getCurrentDate()+"</span>");
			sb.append("							<br />");
			sb.append("							<span class='hhmmss'>"+getCurrentTime()+"</span>");
			sb.append("						</div>");
			sb.append("					</div>");
			sb.append("				</div>");
			sb.append("			</div>");
			sb.append("		</div>");
		}
		if(intChatCnt > 1) {
			sb.append("		<div class='"+type+"LongtakeDialog'>");
			sb.append("			<div>");
			sb.append("				<p class='chatMsgTxt' style='display: inline-block; white-space: pre-wrap;'>"+chatmembers.getChatMessage()+"</p>");
			sb.append("				<div class='chatDateInfo'>");
			sb.append("					<div>");
			sb.append("						<span class='yymmdd'>"+getCurrentDate()+"</span>");
			sb.append("						<br />");
			sb.append("						<span class='hhmmss'>"+getCurrentTime()+"</span>");
			sb.append("					</div>");
			sb.append("				</div>");
			sb.append("			</div>");
			sb.append("		</div>");
		}
		
		sb.append(cntTxt);
		sb.append(memIdTxt);
		sb.append(roomNoTxt);
		
		sb.append("</div>");
		
		return sb;
	}
	
	private String getCurrentDate() {
	    SimpleDateFormat dateFormat = new SimpleDateFormat("yy/MM/dd");

	    Date now = new Date();
	    String dateStr = dateFormat.format(now);

	    return dateStr;
	}
	
	private String getCurrentTime() {
		SimpleDateFormat timeFormat = new SimpleDateFormat("a hh:mm");
		
		Date now = new Date();
		String timeStr = timeFormat.format(now);
		
		return timeStr;
	}

	// 3. 클라이언트의 연결이 끊겼을 때 실행되는 메소드
	@Override
	public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
		
		chatSessionList.remove(session);
		
		Map<String, Object> chatMapSession = session.getAttributes();
		MemberVO chatMember = (MemberVO) chatMapSession.get("sessionInfo");
		String userId = chatMember.getMemId();
		
		log.info("## 누군가 퇴장");
		log.info("{} 연결 끊김", userId);
		log.info("채팅방 퇴장한 사람 : {}", userId);
		
	}

}

package kr.or.ddit.utils.websocket;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import com.fasterxml.jackson.databind.ObjectMapper;

import kr.or.ddit.users.login.vo.MemberVO;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Component
public class ChatInOutHandler extends TextWebSocketHandler {

	// 전체 로그인한 멤버 리스트, 여러 개의 웹소켓 세션을 담도록 리스트를 생성한다.
	private static List<WebSocketSession> loginSessionList = new ArrayList<WebSocketSession>();
	
	// 로그인 정보 정제
	List<String> loginMembersId = new ArrayList<String>();
	
	// 1. 클라이언트 연결 이후에 실행되는 메소드
	@Override
	public void afterConnectionEstablished(WebSocketSession session) throws Exception {
	    log.info("##################### 누군가 접속");

	    Map<String, Object> loginSessionMap = session.getAttributes();
	    MemberVO loginMember = (MemberVO) loginSessionMap.get("sessionInfo");

	    if (loginMember == null) {
	        // WebSocket ID is present, do not add to the list
	        log.info("웹소켓 아이디 : {}", session.getId());
	    } else {
	        // Login user is present, add the session to the list
	        loginSessionList.add(session);
	        log.info("세션 정보 : {}", session.getAttributes());
	        log.info("채팅방 접속 이후 연결된 세션 갯수 : {} 개 세션이 연결됨", loginSessionList.size());
	        log.info("채팅방 접속한 사용자 아이디 : {}", loginMember.getMemId());
	    }
	}
	
	// 2. 클라이언트가 웹소켓 서버로 메시지를 전송했을 때 실행되는 메소드
	@Override
	protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
		
		Map<String, Object> loginMapSession = session.getAttributes();
		MemberVO loginMember = (MemberVO) loginMapSession.get("sessionInfo");
		
		if (loginMember != null) {
			// 파싱된 메시지
		    String receivedMessage = message.getPayload();
			
			// 로그인한 아이디와 클라이언트로부터 서버로 보낸 메시지를 받음
			log.info("아이디 "+loginMember.getMemId()+" 로 부터 이름이 "+loginMember.getMemName()+" 인 사람이 채팅방 접속을 시도함.");
			
			// 중복 체크
		    if (!loginMembersId.contains(loginMember.getMemId())) {
		        loginMembersId.add(loginMember.getMemId());
		        log.info("loginMembersId : {}", loginMembersId);

		        ObjectMapper objectMapper = new ObjectMapper();
		        try {
		            String jsonStr = objectMapper.writeValueAsString(loginMembersId);
		            for (WebSocketSession sess : loginSessionList) {
		                sess.sendMessage(new TextMessage(jsonStr));
		            }
		        } catch (Exception e) {
		            e.printStackTrace();
		        }
		    } else {
		        log.info("이미 채팅방에 들어온 아이디입니다. 중복 처리를 하지 않습니다.");
		    }

	    } else {
	        log.warn("Received a message from a session without a valid loginMember.");
	    }
		
	}
	
	// 3. 클라이언트의 연결이 끊겼을 때 실행되는 메소드
	@Override
	public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
	    Map<String, Object> loginMapSession = session.getAttributes();
	    MemberVO loginMember = (MemberVO) loginMapSession.get("sessionInfo");
	    
	    if (loginMember != null) {
	        String userId = loginMember.getMemId();

	        // 세션을 먼저 제거
		    loginSessionList.remove(session);
		    
		    if (loginMembersId.contains(userId)) {
		        loginMembersId.remove(userId);
		        log.info("채팅방 나간 후 loginMembersId에서 {} 제거됨", userId);
		        log.info("loginMembersId : {}", loginMembersId);
		        ObjectMapper objectMapper = new ObjectMapper();

		        try {
		            String jsonStr = objectMapper.writeValueAsString(loginMembersId);
		            for (WebSocketSession sess : loginSessionList) {
		                if (sess.isOpen()) {
		                    sess.sendMessage(new TextMessage(jsonStr));
		                }
		            }
		        } catch (Exception e) {
		            e.printStackTrace();
		        }

		    } else {
		        log.info("채팅방 나간 아이디가 loginMembersId에 없습니다. 처리하지 않습니다.");
		    }

	        log.info("채팅방 나간 이후 연결된 세션 갯수 : {} 개 세션", loginSessionList.size());
	        log.info("##################### 누군가 로그아웃");
	        log.info("{} 연결 끊김", userId);
	        log.info("채팅방 나간 사람 : {}", userId);
	    } else {
	        log.warn("Connection closed for a session without a valid loginMember.");
	    }

	}
	
}

package kr.or.ddit.utils.websocket;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import com.fasterxml.jackson.databind.ObjectMapper;

import kr.or.ddit.users.login.vo.MemberVO;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Component
public class LoginDetectHandler extends TextWebSocketHandler {

	// 전체 로그인한 멤버 리스트, 여러 개의 웹소켓 세션을 담도록 리스트를 생성한다.
	private static List<WebSocketSession> loginSessionList = new ArrayList<WebSocketSession>();
	
	// 로그인 정보 정제
	List<String> loginMembersId = new ArrayList<String>();
	
	// 1. 클라이언트 연결 이후에 실행되는 메소드
	@Override
	public void afterConnectionEstablished(WebSocketSession session) throws Exception {
	    log.info("##################### 누군가 접속");

	    Map<String, Object> loginSessionMap = session.getAttributes();
	    MemberVO loginMember = (MemberVO) loginSessionMap.get("sessionInfo");

	    if (loginMember == null) {
	        // WebSocket ID is present, do not add to the list
	        log.info("웹소켓 아이디 : {}", session.getId());
	    } else {
	        // Login user is present, add the session to the list
	        loginSessionList.add(session);
	        log.info("세션 정보 : {}", session.getAttributes());
	        log.info("로그인 이후 연결된 세션 갯수 : {} 개 세션이 연결됨", loginSessionList.size());
	        log.info("로그인한 사용자 아이디 : {}", loginMember.getMemId());
	    }
	}
	
	// 2. 클라이언트가 웹소켓 서버로 메시지를 전송했을 때 실행되는 메소드
	@Override
	protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
		
		Map<String, Object> loginMapSession = session.getAttributes();
		MemberVO loginMember = (MemberVO) loginMapSession.get("sessionInfo");
		
		if (loginMember != null) {
			// 파싱된 메시지
		    String receivedMessage = message.getPayload();
			
			// 로그인한 아이디와 클라이언트로부터 서버로 보낸 메시지를 받음
			log.info("아이디 "+loginMember.getMemId()+" 로 부터 이름이 "+loginMember.getMemName()+" 인 사람이 로그인/로그아웃을 시도함.");
			
			// 중복 체크
		    if (!loginMembersId.contains(loginMember.getMemId())) {
		        loginMembersId.add(loginMember.getMemId());
		        log.info("loginMembersId : {}", loginMembersId);

		        ObjectMapper objectMapper = new ObjectMapper();
		        try {
		            String jsonStr = objectMapper.writeValueAsString(loginMembersId);
		            for (WebSocketSession sess : loginSessionList) {
		                sess.sendMessage(new TextMessage(jsonStr));
		            }
		        } catch (Exception e) {
		            e.printStackTrace();
		        }
		    } else {
		        log.info("이미 로그인한 아이디입니다. 중복 처리를 하지 않습니다.");
		    }

	    } else {
	        log.warn("Received a message from a session without a valid loginMember.");
	    }
		
	}
	
	// 3. 클라이언트의 연결이 끊겼을 때 실행되는 메소드
	@Override
	public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
	    Map<String, Object> loginMapSession = session.getAttributes();
	    MemberVO loginMember = (MemberVO) loginMapSession.get("sessionInfo");
	    
	    if (loginMember != null) {
	        String userId = loginMember.getMemId();

	        // 세션을 먼저 제거
		    loginSessionList.remove(session);
		    
		    if (loginMembersId.contains(userId)) {
		        loginMembersId.remove(userId);
		        log.info("로그아웃 후 loginMembersId에서 {} 제거됨", userId);
		        log.info("loginMembersId : {}", loginMembersId);
		        ObjectMapper objectMapper = new ObjectMapper();

		        try {
		            String jsonStr = objectMapper.writeValueAsString(loginMembersId);
		            for (WebSocketSession sess : loginSessionList) {
		                if (sess.isOpen()) {
		                    sess.sendMessage(new TextMessage(jsonStr));
		                }
		            }
		        } catch (Exception e) {
		            e.printStackTrace();
		        }

		    } else {
		        log.info("로그아웃한 아이디가 loginMembersId에 없습니다. 처리하지 않습니다.");
		    }

	        log.info("로그아웃 이후 연결된 세션 갯수 : {} 개 세션", loginSessionList.size());
	        log.info("##################### 누군가 로그아웃");
	        log.info("{} 연결 끊김", userId);
	        log.info("로그아웃 한 사람 : {}", userId);
	    } else {
	        log.warn("Connection closed for a session without a valid loginMember.");
	    }

	}
	
}