관리 메뉴

거니의 velog

(21) 웹 소켓 세팅 본문

대덕인재개발원_final project

(21) 웹 소켓 세팅

Unlimited00 2024. 2. 1. 14:19

(1) servlet-context.xml

<!-- 채팅 관련 핸들러 등록 -->
<beans:bean id="chatHandler" class="kr.or.ddit.utils.websocket.ChatHandler" />
<beans:bean id="loginDetectHandler" class="kr.or.ddit.utils.websocket.LoginDetectHandler" />

<!-- <websocket:handlers allowed-origins="*"> -->
<websocket:handlers>
    <websocket:mapping handler="chatHandler" path="/chat" />
    <websocket:handshake-interceptors>
        <beans:bean class="org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor" />
    </websocket:handshake-interceptors>
    <websocket:sockjs />
</websocket:handlers>
<websocket:handlers>
    <websocket:mapping handler="loginDetectHandler" path="/logindetect" />
    <websocket:handshake-interceptors>
        <beans:bean class="org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor" />
    </websocket:handshake-interceptors>
    <websocket:sockjs />
</websocket:handlers>

(2) WebSocketConfig.java

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;
	
	@Override
	public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
		registry.addHandler(chatHandler, "/chat").setAllowedOrigins("*");
		registry.addHandler(loginDetectHandler, "/logindetect").setAllowedOrigins("*");
	}
	
}

(3) LoginDetectHandler.java

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 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>();
	
	// 1. 클라이언트 연결 이후에 실행되는 메소드
	@Override
	public void afterConnectionEstablished(WebSocketSession session) throws Exception {
		log.info("##################### 누군가 접속");
		
		loginSessionList.add(session);
		log.info("세션 정보 : {}", session.getAttributes());
		log.info("로그인 이후 연결된 세션 갯수 : {} 개 세션이 연결됨", loginSessionList.size());
		
		Map<String, Object> loginSessionMap = session.getAttributes();
		MemberVO loginMember = (MemberVO) loginSessionMap.get("sessionInfo");
		
		if(loginMember == null) { // 웹소켓 아이디를 가져옴
			log.info("웹소켓 아이디 : {}", session.getId());
		}else { // 로그인한 사용자 아이디를 가져옴
			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");
		
		// 로그인한 아이디와 클라이언트로부터 서버로 보낸 메시지를 받음
		log.info("아이디 "+loginMember.getMemId()+" 로 부터 이름이 "+loginMember.getMemName()+" 인 사람이 로그인/로그아웃을 시도함.");
		
		// 공통 변수 선언
		String preLoginTxt = message.getPayload();
		
		log.info("preLoginTxt 내용 : {}", preLoginTxt);
		
	}
	
	// 3. 클라이언트의 연결이 끊겼을 때 실행되는 메소드
	@Override
	public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
		
		loginSessionList.remove(session);
		log.info("로그아웃 이후 연결된 세션 갯수 : {} 개 세션", loginSessionList.size());
		
		Map<String, Object> loginMapSession = session.getAttributes();
		MemberVO loginMember = (MemberVO) loginMapSession.get("sessionInfo");
		String userId = loginMember.getMemId();
		
		log.info("##################### 누군가 로그아웃");
		log.info("{} 연결 끊김", userId);
		log.info("로그아웃 한 사람 : {}", userId);
		
	}
	
}

(4) util.js

// 로그인/로그아웃 감지 웹소켓 기능
$.loginDetectWebSocketFn = function({loginMemId, loginMemName}){
	var loginDetectWebSocket; // 페이지가 바뀌지 않도록 주의!

	var loginEndpoint = "/logindetect";

	// 공통 함수 선언
	function loginConnect(){
		loginDetectWebSocket = new SockJS(loginEndpoint); // 엔드 포인트
		
		loginDetectWebSocket.onopen = function(event) {
			console.log("WebSocket connection opened:", event);
			loginDetectWebSocket.send("웹 소켓 시작"); // 기존 chatOpen 함수와 합침
		};
		
		loginDetectWebSocket.onmessage = function(event) {
			console.log("WebSocket message received:", event.data);
			loginDetectMessage(event); // event 매개변수를 loginDetectMessage 함수에 전달
		};
		
		loginDetectWebSocket.onclose = function(event) {
			console.log("WebSocket connection closed:", event);
		};
		
		loginDetectWebSocket.onerror = function(event) {
			console.error("WebSocket error:", event);
		};
	}

	function loginDetectMessage(event){
		var loginData = event.data;
		console.log("loginData : ", loginData);
	}

	function logOutDisconnect(){
		loginDetectWebSocket.send("웹 소켓 종료");
		loginDetectWebSocket.close();
	}

	// 연결
	loginConnect();

};

(5) headerSettings.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>

<link href="${contextPath }/resources/images/favicon.ico" rel="shoutcut icon" />
<!-- 공통 css -->
<link href="${contextPath }/resources/css/userCommon.css" rel="stylesheet" />
<!-- 제이쿼리 -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<!-- 공통 js -->
<script defer src="${contextPath }/resources/js/util.js"></script>
<script defer src="${contextPath }/resources/js/userCommon.js"></script>
<!-- 부트스트랩 모듈 -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
<!-- 폰트어썸, 구글 아이콘 디자인 -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.9.0/css/all.min.css" rel="stylesheet" />
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<!-- 스위트 얼럿 모듈 -->
<link href="${contextPath }/resources/css/sweetalert2.min.css" rel="stylesheet" />
<script defer src="${contextPath }/resources/js/sweetalert2.all.min.js"></script>
<!-- sockjs -->
<script src="${contextPath }/resources/js/sockjs.min.js"></script>

(6) settings.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<script>
    $(function(){
        // 공통 함수
        $.mLnbClickEvent();
        $.footerRelatedSiteFn();
        $.mmainClickEvent700();
        
     	// 로그인/로그아웃 감지 기능
        $.loginDetectWebSocketFn();
        
        // 종횡비 함수
        var pcgnbMainProfileImgCont = $(".pcgnb .mainProfileImgCont");
        var pcgnbMainProfileImg = $(".pcgnb .mainProfileImgCont img")
        $.ratioBoxH(pcgnbMainProfileImgCont, pcgnbMainProfileImg);
        
        var mgnbMainProfileImgCont = $(".mgnb .mainProfileImgCont");
        var mgnbMainProfileImg = $(".mgnb .mainProfileImgCont img");
        $.ratioBoxH(mgnbMainProfileImgCont, mgnbMainProfileImg);
    });
</script>

 

'대덕인재개발원_final project' 카테고리의 다른 글

(23) 리눅스  (0) 2024.02.13
(22) 토요일 수업 5  (0) 2024.02.03
(20) 토요일 수업 4  (0) 2024.01.13
(19) 보강 12  (0) 2024.01.08
(18) 토요일 수업 3  (0) 2024.01.08