Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
Tags
- 한국건설관리시스템
- cursor문
- 대덕인재개발원
- 사용자예외클래스생성
- 참조형변수
- 다형성
- 어윈 사용법
- 인터페이스
- 예외처리
- GRANT VIEW
- 자동차수리시스템
- abstract
- EnhancedFor
- 예외미루기
- 객체 비교
- 생성자오버로드
- exception
- NestedFor
- 추상메서드
- 컬렉션프레임워크
- 환경설정
- 메소드오버로딩
- 컬렉션 타입
- oracle
- Java
- 오라클
- 정수형타입
- 제네릭
- 집합_SET
- 자바
Archives
- Today
- Total
거니의 velog
(17) 마이 트립 > 만남의 광장 페이지 > 코드 리뷰 본문
<%@ 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>여기갈래 > 파트너</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.");
}
}
}
'대덕인재개발원 > 대덕인재개발원_최종 포트폴리오' 카테고리의 다른 글
(19) 게시판 > 공지사항 페이지 > 코드 리뷰 (0) | 2024.02.16 |
---|---|
(18) 마이 트립 > 만남의 광장 페이지 > 화면 설명 (0) | 2024.02.16 |
(16) 마이 트립 > 플래너 리스트 페이지 > 화면 설명 (0) | 2024.02.16 |
(15) 마이 트립 > 플래너 리스트 페이지 > 코드 리뷰 (0) | 2024.02.16 |
(14) 마이 플랜 > 여행 정보 등록 페이지 > 화면 설명 (0) | 2024.02.16 |