프로젝트/공연 예약 플랫폼

[Spring] 웹소켓으로 채팅방 만들기 - 1. 채팅방 목록

sm_leaf25 2025. 3. 13. 17:14

 

 

1. 채팅방 목록 페이지  - JSP(Java Server Pages) 파일 생성

(1) style 

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
    
    
    <style>
         .a {
            text-align: left;
            width: 70%;
            margin: 0px auto;
            background-color: white;
            /*padding: 3% 5%;*/
            border: 1px solid lightgray;
            border-radius: 0px 0px  10px 10px;
			border-top : none;
			z-index: 2;
        }

        #pagingArea {width:fit-content; margin:auto;}
        #searchForm>* {
            float:left;
            margin:5px;
            
        }
        .select {width:20%;}
        .text {width:53%;}
        
        .searchBtn {
            width:20%; 
            background-color: #597c9b;
            
        }

		#searchForm{
			width: 50%;
			margin-left: 51%;
			
		}
        
        
       	#chatList{
        	text-align: center;
        	
        }
        
        .pageBtn{
        	border : 1px solid lightgray;
        	background-color : white;
        	padding: 5px 10px;
        	border-radius: 8px;
        	
        }
        
        .joinBtn{
        	border : 1px solid gray;	
        	background-color : white;
        	padding: 3px 10px;
        	border-radius: 8px;
        	
        }
        
        .joinBtn:hover{
        	background-color : #597c9b;
        	padding: 3px 10px;
			cusor: pointer;
			border : 1px solid #597c9b;	
			color: white;
        }
        

    </style>
</head>

 

(2) 채팅방 목록 및 검색바 

- EL 표기법 사용

- ${변수명} 형태로 표기 

<%@ include file="/WEB-INF/views/common/menubar2.jsp" %>
<div class="a" style="padding:5% 10%;">
    <h2 align="center">공연·전시 톡톡</h2>


    <br><br>
    <form id="searchForm" action="${contextPath}/chat/chatSearch" method="get" align="center">
        <div class="select">
            <select class="custom-select" name="condition">
                <option value="total">전체</option>
                <option value="writer">작성자</option>
                <option value="title">제목</option>
            </select>
        </div>

        <div class="text">
            <input type="text" class="form-control" name="keyword" value="${map.keyword}">
        </div>

        <button type="submit" class="searchBtn btn btn-secondary">검색</button>
    </form>

    <br>
    <br><br>
    <table id="chatList" class="table"  align="center">
        <thead>
            <tr>
                <th>번호</th>
                <th>제목</th>
                <th>작성자</th>
                <th>입장정원수</th>
                <th>생성일</th>
                <th>입장</th>
            </tr>
        </thead>
        <tbody>
            <c:choose>
                <c:when test="${empty chatList}">
                    <tr>
                        <td colspan="6" style="text-align: center;" id="noting" >조회된 채팅방이 없습니다.</td>	
                    </tr>
                </c:when>
                <c:otherwise>
                    <c:forEach var="cl" items="${chatList}">
                        <tr>
                            <td>${cl.chatNo}</td>
                            <td>${cl.chatTitle}</td>
                            <td>${cl.memList[0].userId}</td>
                            <td>${cl.joinCount}/${cl.chatUserCount}</td>
                            <td>${cl.createDate}</td>
                            <td><button type="button" class="joinBtn" value="${cl.chatNo}">입장</button></td>
                        </tr>
                    </c:forEach>
                </c:otherwise>
            </c:choose> 
        </tbody>
    </table>
    <br>

    <button type="button" onclick="location.href='${contextPath}/chat/chatView'" class="btn btn-secondary" style="float:right; background-color: #597c9b;">채팅방 만들기</button>

 

 

(3) 페이징 처리

- JSTL(JSP Standard Tag Library) 표기법 사용 

   : Java 코드 최소화, XML 과 유사한 태그를 사용하여 JSP에서 논리를 구현하는 방식

- 이전/다음 버튼
  : 시작/마지막 페이지일때는 비활성화
- 페이지 버튼 
   : 클릭 했을 때 현재 페이지 버튼은 비활성화 
<div id="pagingArea">
<c:choose> 
    <c:when test="${pi.currentPage == 1}">
        <button class="pageBtn" disabled>이전</button>
    </c:when>
    <c:otherwise>
        <button class="pageBtn" onclick="location.href='${contextPath}/chat/list?currentPage=${pi.currentPage - 1}'">이전</button>
    </c:otherwise>
</c:choose>

<c:forEach var="i" begin="${pi.startPage}" end="${pi.endPage}">
    <c:choose>
        <c:when test="${empty map}"> 
            <c:choose>
                <c:when test="${i != pi.currentPage}">
                    <button class="pageBtn" onclick="location.href='${contextPath}/chat/list?currentPage=${i}'">${i}</button>
                </c:when>
                <c:otherwise>
                    <button class="pageBtn" disabled>${i}</button>
                </c:otherwise>
            </c:choose>
        </c:when>

        <c:otherwise>
            <c:url var="searchUrl" value="/chat/list">
                <c:param name="currentPage" value="${i}"/>
                <c:param name="condition" value="${map.condition}"/>
                <c:param name="keyword" value="${map.keyword}"/>
            </c:url>
            <c:choose>
                <c:when test="${i != pi.currentPage}">
                    <button class="pageBtn" onclick="location.href='${searchUrl}'">${i}</button>
                </c:when>
                <c:otherwise>
                    <button class="pageBtn" disabled>${i}</button>
                </c:otherwise>
            </c:choose>
        </c:otherwise>
    </c:choose>
</c:forEach>

<c:choose> 
    <c:when test="${pi.currentPage == pi.maxPage}">
        <button class="pageBtn" disabled>다음</button>
    </c:when>
    <c:otherwise>
        <button class="pageBtn" onclick="location.href='${contextPath}/chat?currentPage=${pi.currentPage + 1}'">다음</button>
    </c:otherwise>
</c:choose>

</div>

 

(4) Script 영역 

- 채팅방 정원이 가득찬 경우 채팅방 입장을 막기 위한 코드

 

  • JavaScript & jQuery 사용
    • $() → jQuery 문법으로 HTML 요소를 선택하고 조작
    • on("click", function() {...}) → 버튼 클릭 이벤트 처리
    • $.ajax({...}) → AJAX 요청을 사용해 서버와 비동기 통신
  • EL(Expression Language) 사용
    • ${map.condition}, ${loginUser.userId} → JSP에서 전달된 데이터(서버 값)를 JavaScript에서 사용
  • AJAX 통신 (서버와 데이터 주고받기)
    • "chatting"과 "joinUser" URL로 AJAX 요청을 보내 서버에서 응답을 받음

 

<script>
    $("option[value='${map.condition}']").attr("selected", true);


    $("#chatList tbody").on("click", "button", function(){
        // 해당 chatNo에 해당하는 joinCount, chatUserCount만 가져와야 한다. chatList
        // button.parent() 만하면 button의 td만 가져오기 때문에 tr을 찾고 td를 찾아야 tr에 있는 모든 td 값을 가져올 수 있다.
        // eq() == 인덱스 
        // td에서 /를 기준으로 잘라 값을 가져와야 한다. 해당 값은 index로 나눠진다.    split : 문자열을 나누어 배열로 반환 
        var button = $(this);

        var tr = button.parent().parent();
        var td = tr.children();

        var join = td.eq(3).text().split("/");


        // 문자열 비교로 되기 떄문에 parseInt를 사용하여 문자열 타입의 매개변수를 정수로 변환한다. : 10은 10진수로 변환한다는 뜻.
        var joinCount = parseInt(join[0], 10);
        var chatUserCount = parseInt(join[1], 10);

        // 입장 인원 수 > 참여 인원 수인 경우에만 채팅방 참여 가능 
        // 회원 id, 채팅방 번호  => count는 리스트에서만 확인 가능하면 된다. (오라클 sql 구문 작성해둠)
        var chatNo = td.eq(0).text();

        // 백틱이 없는 경우 undifind가 뜬다. 왜? 확인 필요함. 이전에는 문제 없었음. 
        // var meetingCount= ${meDetail.meetingCount}; 해당값은 가져와짐. int라 그런건가? 문자열이여서 안되는건가? 
        var userId = `${loginUser.userId}`;

        var userNo = `${loginUser.userNo}`;

        var chatTitle = td.eq(1).text();

        if(chatUserCount > joinCount){ // 채팅방 정원이 차지 않아 입장이 가능할 때
            $.ajax({
                url: "chatting",
                data :{
                    chatNo: chatNo,
                    userId : userId
                },
                success : function(data){
                    console.log(data);
                    if((userId != null) && (userId != "")){
                        location.href="${contextPath}/chat/chatting?chatNo="+chatNo+"&userId="+userId;
                        alert(chatTitle + " 채팅방 입장");
                    }else{
                        alertify.alert("요청 실패","회원만 이용 가능한 서비스 입니다.");
                    }

                }
            });


          }else{ // 채팅방 정원이 가득 차 입장 불가능
              // 정원이 찼지만 이미 참여되어 있는 회원인 경우에는 채팅방 입장 가능
              $.ajax({
                 url: "joinUser",
                 type : "POST",
                 data: {
                    chatNo: chatNo,
                    userNo : userNo
                 },
                 success : function(joinUser){
                     if(joinUser){
                         location.href="${contextPath}/chat/chatting?chatNo="+chatNo+"&userId="+userId;
                     } else{
                         // 입장 인원수와 현재 입장한 인원수가 같은 경우 채팅방 입장 불가능
                         alert("채팅방 정원이 모두 차 입장이 불가능합니다.");
                     }
                 },
                 error : function(){
                    conole.log("에러 발생");
                 }
              });
          }
    });

</script>