본문 바로가기

국비교육/국비교육

day75 - 1114

웹 소켓(Web Socket)

- HTML5의 표준 기술
- HTTP 환경에서 클라이언트와 서버 사이에 하나의 TCP 연결을 통해 실시간 양방향 통신을 가능하게 하는 통신 프로토콜

 

- interface인 WebSocketHandler을 구현(implements)

- WebSocketHandler의 구현체인 TextWebSocketHandler, BinaryWebSocketHandler를 상속(extends)

 


기본적인 웹 소켓 연결

BasicWebSocketServer

@Slf4j
@Service
public class BasicWebSocketServer extends TextWebSocketHandler {

	@Override
	public void afterConnectionEstablished(WebSocketSession session) throws Exception {
		log.debug("사용자 접속 : {}", session);
	}

	@Override
	public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
		log.debug("사용자 종료 : {}", session);
	}	
}

 

- @Component 또는 @Service로 등록

- 재정의할 메소드

afterConnectionEstablished(WebSocketSession session) 웹 소켓 연결이 만들어진 후 실행되는 메소드
afterConnectionClosed(WebSocketSession session, CloseStatus status) 웹 소켓 연결이 해제된 후 실행되는 메소드

 

WebSocketConfiguration

@Configuration
@EnableWebSocket // 웹소켓 활성화
public class WebSocketServerConfiguration implements WebSocketConfigurer {

	// 의존성 주입
	@Autowired
	private BasicWebsocketServer basicWebsocketServer;
	
	@Override
	public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {

		// 웹소켓 주소 설정
		registry.addHandler(basicWebsocketServer, "/ws/basic");
	}	
}

 

- @Configuration으로 등록 - 모든 웹 소켓 연결 설정

- interface인 WebSocketConfigurer를 구현(implements)

- @EnableWebSocket 어노테이션을 통해 웹소켓을 수동으로 활성화

 

** 웹소켓 주소 설정시 주의사항

- 일반 Controller나 REST Controller의 주소와 겹치지 않도록 설정

 

PageController

@Controller
@RequestMapping("/page")
public class PageController {

	@GetMapping("/basic")
	public String basic() {
		return "basic";
	}
}

 

basic.jsp

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

<h1>웹소켓 연결 예제</h1>

<button class = "btn-connect">연결</button>
<button class = "btn-disconnect">종료	</button>

<!-- JQuery CDN -->
<script src="https://code.jquery.com/jquery-3.6.1.js"></script>

<script>
	$(function(){
		// 초기 웹소켓은 연결 해제 상태
		disconnectState();
		
		// 1. 연결버튼을 누를 때 - 웹소켓 연결 생성
		$(".btn-connect").click(function(){
			
			// 웹소켓 연결 주소 설정
			var uri = "ws://localhost:8888/ws/basic";
			
			// 웹소켓 연결 생성
			//window.socket = new WebSocket(uri);
			socket = new WebSocket(uri); // 변수로 만들지 말고 window에 붙여서 만듬
			
			console.log(socket);
			
			// 웹소켓에 대한 이벤트 설정
			// 1) 웹소켓 연결이 생성될 때
			socket.onopen = function(){
				console.log("open");	
				connectState();	// 연결 상태일 때 connectState() 실행
			};
			
			// 2) 웹소켓 연결 중 연결이 해제될 때
			socket.onclose = function(){
				console.log("close");
				disconnectState(); // 해제 상태일 때 disconnectState() 실행
			};
			
			// 3) 웹소켓 연결 중 연결에 에러가 발생할 때
			socket.onerror = function(){
				console.log("error");
				disconnectState(); // 에러 상태일 때 disconnectState() 실행
			};
			
			// 4) 웹소켓 연결 중 메시지가 수신될 때
			socket.onmessage = function(){
				console.log("message");
			};
			
		});
		
		// 2. 종료 버튼을 누를 때 - 웹소켓 연결 해제
		$(".btn-disconnect").click(function(){
			// 웹소켓 연결 종료
			//window.socket.close();
			socket.close();
		});
		
		// 웹소켓 연결이 만들어진 상태일 때
		function connectState(){
			$(".btn-connect").prop("disabled", true); // 연결버튼 비활성화
			$(".btn-disconnect").prop("disabled", false); // 종료버튼 비활성화 해제
		}
		
		// 웹소켓 연결이 해제된 상태일 때
		function disconnectState(){
			$(".btn-connect").prop("disabled", false); // 연결버튼 비활성화 해제
			$(".btn-disconnect").prop("disabled", true); // 종료버튼 비활성화
		}
	});
</script>

 


다중 접속 관리

MultipleUserWebSocketServer

@Slf4j
@Service
public class MultipleUserWebsocketServer extends TextWebSocketHandler {
	
	// 웹소켓 사용자 저장소 - Set(중복 방지)
	private Set<WebSocketSession> users = new CopyOnWriteArraySet<>(); // 동기화된 Set 

	@Override
	public void afterConnectionEstablished(WebSocketSession session) throws Exception {
		users.add(session); // 사용자 저장
		log.debug("사용자 접속 : {} 명", users.size());
	}

	@Override
	public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
		users.remove(session); // 사용자 삭제
		log.debug("사용자 종료 : {} 명", users.size());
	}
}

 

- 웹소켓이 연결된 사용자를 저장하기 위해 Set 형태를 사용한다

- thread-safe 속성을 갖는 CopyOnWriteArraySet을 업 캐스팅하여 사용한다

 

** thread-safe

멀티 스레드 프로그래밍에서 일반적으로 어떤 함수나 변수, 혹은 객체가 여러 스레드로부터 동시에 접근이 이루어져도

프로그램의 실행에 문제가 없음을 뜻한다

 

WebSocketConfiguration

@Configuration
@EnableWebSocket // 웹소켓 활성화
public class WebSocketServerConfiguration implements WebSocketConfigurer {

	// 의존성 주입
	@Autowired
	private MultipleUserWebsocketServer multipleUserWebsocketServer;
	
	@Override
	public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {

		registry.addHandler(multipleUserWebsocketServer, "/ws/multiple"));

	}	
}

 

PageController

@Controller
@RequestMapping("/page")
public class PageController {

	@GetMapping("/multiple")
	public String multiple() {
		return "multiple";
	}
}

 

multiple.jsp

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

<h1>다중 사용자 연결 예제</h1>

<button class = "btn-connect">연결</button>
<button class = "btn-disconnect">종료	</button>

<script src="https://code.jquery.com/jquery-3.6.1.js"></script>

<script>
	$(function(){
		// 초기 웹소켓은 연결 해제 상태
		disconnectState();
		
		// 1. 연결버튼을 누를 때 - 웹소켓 연결 생성
		$(".btn-connect").click(function(){
			
			// 웹소켓 연결 주소 설정
			var uri = "ws://localhost:8888/ws/multiple";
			
			// 웹소켓 연결 생성
			//window.socket = new WebSocket(uri);
			socket = new WebSocket(uri); // 변수로 만들지 말고 window에 붙여서 만듬
			
			console.log(socket);
			
			// 웹소켓에 대한 이벤트 설정
			// 1) 웹소켓 연결이 생성될 때
			socket.onopen = function(){
				console.log("open");	
				connectState();	// 연결 상태일 때 connectState() 실행
			};
			
			// 2) 웹소켓 연결 중 연결이 해제될 때
			socket.onclose = function(){
				console.log("close");
				disconnectState(); // 해제 상태일 때 disconnectState() 실행
			};
			
			// 3) 웹소켓 연결 중 연결에 에러가 발생할 때
			socket.onerror = function(){
				console.log("error");
				disconnectState(); // 에러 상태일 때 disconnectState() 실행
			};
			
			// 4) 웹소켓 연결 중 메시지가 수신될 때
			socket.onmessage = function(){
				console.log("message");
			};
			
		});
		
		// 2. 종료 버튼을 누를 때 - 웹소켓 연결 해제
		$(".btn-disconnect").click(function(){
			// 웹소켓 연결 종료
			//window.socket.close();
			socket.close();
		});
		
		// 웹소켓 연결이 만들어진 상태일 때
		function connectState(){
			$(".btn-connect").prop("disabled", true); // 연결버튼 비활성화
			$(".btn-disconnect").prop("disabled", false); // 종료버튼 비활성화 해제
		}
		
		// 웹소켓 연결이 해제된 상태일 때
		function disconnectState(){
			$(".btn-connect").prop("disabled", false); // 연결버튼 비활성화 해제
			$(".btn-disconnect").prop("disabled", true); // 종료버튼 비활성화
		}
	});
</script>

 


웹소켓을 이용한 실시간 채팅 구현(1)

기본적인 구조

- 특정 클라이언트에서 웹소켓 서버로 메시지 전송

- 웹소켓 서버에서 특정 클라이언트로부터 받은 메시지를 웹소켓 연결된 모든 사용자에게 전송

 

MessageWebSocketServer

@Slf4j
@Service
public class MessageWebSocketServer extends TextWebSocketHandler {
	
	// 웹소켓 사용자 저장소 - Set (중복 방지)
	private Set<WebSocketSession> users = new CopyOnWriteArraySet<>();
	
	@Override
	public void afterConnectionEstablished(WebSocketSession session) throws Exception {
		users.add(session);
		log.debug("사용자 접속");
	}

	@Override
	public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
		users.remove(session);
		log.debug("사용자 종료");
	}

	@Override
	protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {

		// message의 내용은 payload에 존재하며, 사용자(session)에게 전송할 수 있다
		log.debug("메시지 수신 {}", message);

		// 전송한 메시지 회신
		//session.sendMessage(message); 

		// 웹소켓에 연결된 모든 사용자에게 메시지 전송
		for(WebSocketSession user : users) {
			user.sendMessage(message);
		}
	}
}

 

WebSocketServerConfiguration

@Configuration
@EnableWebSocket // 웹소켓 활성화
public class WebSocketServerConfiguration implements WebSocketConfigurer {

	// 의존성 주입
	@Autowired
	private MessageWebsocketServer messageWebsocketServer;
	
	@Override
	public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {

		registry.addHandler(messageWebsocketServer, "/ws/message");
	}	
}

 

PageController

@Controller
@RequestMapping("/page")
public class PageController {

	@GetMapping("/message")
	public String message() {
		return "message";
	}
}

 

message.jsp

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

<h1>메시지 전송 예제</h1>

<button class = "btn-connect">연결</button>
<button class = "btn-disconnect">종료	</button>

<hr>

<input type = "text" id = "message-input">
<button type = "button" id = "message-send">전송</button>

<hr>

<div id = "message-list"></div>

<script src="https://code.jquery.com/jquery-3.6.1.js"></script>

<script>
	$(function(){
		// 초기 웹소켓은 연결 해제 상태
		disconnectState();
		
		// 1. 연결버튼을 누를 때 - 웹소켓 연결 생성
		$(".btn-connect").click(function(){
	
			// 웹소켓 연결 주소 설정
			var uri = "ws://localhost:8888/ws/message";
			
			// 웹소켓 연결 생성
			//window.socket = new WebSocket(uri);
			socket = new WebSocket(uri); // 변수로 만들지 말고 window에 붙여서 만듬
			
			console.log(socket);
			
			// 웹소켓에 대한 이벤트 설정
			// 1) 웹소켓 연결이 생성될 때
			socket.onopen = function(){
				console.log("open");	
				connectState();	// 연결 상태일 때 connectState() 실행
			};
			
			// 2) 웹소켓 연결 중 연결이 해제될 때
			socket.onclose = function(){
				console.log("close");
				disconnectState(); // 해제 상태일 때 disconnectState() 실행
			};
			
			// 3) 웹소켓 연결 중 연결에 에러가 발생할 때
			socket.onerror = function(){
				console.log("error");
				disconnectState(); // 에러 상태일 때 disconnectState() 실행
			};
			
			// 4) 웹소켓 연결 중 메시지가 수신될 때
			socket.onmessage = function(e){
				//console.log("message");
				//console.log(arguments); // 모든 매개변수 목록을 배열로 반환
				//console.log(e.data);
				$("<p>").text(e.data).appendTo("#message-list"); // <p> 태그를 생성하여 메시지 표시
			};
			
		});
		
		// 2. 종료 버튼을 누를 때 - 웹소켓 연결 해제
		$(".btn-disconnect").click(function(){
			// 웹소켓 연결 종료
			//window.socket.close();
			socket.close();
		});
		
		// 3. 전송 버튼을 누를 때 - 웹소켓에 연결된 모든 사용자에게 메시지 전달
		$("#message-send").click(function(){
			// 입력창의 값 지정
			var text = $("#message-input").val();
			
			// 입력창이 비어있으면 return
			if(text.length == 0) return;
			
			// 입력창의 값 전송
			// window.socket.send(text);
			socket.send(text);
			
			// 전송 후 입력창 초기화(비우기)
			$("#message-input").val("");
		});
		
		// 웹소켓 연결이 만들어진 상태일 때
		function connectState(){
			$(".btn-connect").prop("disabled", true); // 연결버튼 비활성화
			$(".btn-disconnect").prop("disabled", false); // 종료버튼 비활성화 해제
		}
		
		// 웹소켓 연결이 해제된 상태일 때
		function disconnectState(){
			$(".btn-connect").prop("disabled", false); // 연결버튼 비활성화 해제
			$(".btn-disconnect").prop("disabled", true); // 종료버튼 비활성화
		}
	});
</script>

 


웹소켓을 이용한 실시간 채팅 구현(2) - 메시지에 정보 추가

 

- 서버로 전송하는 JSON에는 내용만 포함되지만 서버로부터 회신하는 JSON에는 요청을 처리 시간을 포함

 

JsonWebSocketServer

@Slf4j
@Service
public class JsonWebsocketServer extends TextWebSocketHandler{
	
	// 웹소켓 사용자 저장소 - Set (중복 방지)
	private Set<WebSocketSession> users = new CopyOnWriteArraySet<>();
	
	@Override
	public void afterConnectionEstablished(WebSocketSession session) throws Exception {
		users.add(session);
	}
	
	@Override
	public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
		users.remove(session);
	}
	
	@Override
	protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
		
		log.debug("메시지 - {}", message.getPayload());
		
		// ObjectMapper의 인스턴스 생성 
		ObjectMapper mapper = new ObjectMapper();
		
		// 1. JSON을 Java Object로 변환 - readValue()
		// 1) JSON을 Map 형태로 변환
		//Map json = mapper.readValue(message.getPayload(), Map.class);
		//log.debug("json = {}", json);
		
		// 2) JSON을 클래스의 인스턴스 형태로 변환
		MessageVO json = mapper.readValue(message.getPayload(), MessageVO.class);
		log.debug("json = {}", json);
		
		// 인스턴스에 시간 설정
		json.setTime(new Date());

		// 2. Java Object를 JSON 형태로 변환 - writeValue()
		// - 클래스의 인스턴스를 JSON 형태로 변환 
		String payload = mapper.writeValueAsString(json);
		TextMessage jsonMessage = new TextMessage(payload);

		// 웹소켓에 연결된 모든 사용자에게 메시지 전송
		for(WebSocketSession user : users) {
			user.sendMessage(jsonMessage);
		}
	}
}

 

MessageVO

- Java Object와 JSON 간의 변환을 위한 VO

@JsonIgnoreProperties // JSON 속성을 무시 - 이 어노테이션을 추가해야 데이터가 없어도 변환해준다
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class MessageVO {
	
	private String text; // 클라이언트가 보내는 정보
	private Date time; // 서버가 추가해야 할 정보
}

 

WebSocketServerConfiguration

@Configuration
@EnableWebSocket // 웹소켓 활성화
public class WebSocketServerConfiguration implements WebSocketConfigurer {

	// 의존성 주입
	@Autowired
	private JsonWebsocketServer jsonWebsocketServer;
	
	@Override
	public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {

		registry.addHandler(jsonWebsocketServer, "/ws/json");
	}	
}

 

PageController

@Controller
@RequestMapping("/page")
public class PageController {

	@GetMapping("/json")
	public String json() {
		return "json";
	}
}

 

json.jsp

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

<h1>JSON 전송 예제</h1>

<button class = "btn-connect">연결</button>
<button class = "btn-disconnect">종료	</button>

<hr>

<input type = "text" id = "message-input">
<button type = "button" id = "message-send">전송</button>

<hr>

<div id = "message-list"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js"></script>
<script src="https://code.jquery.com/jquery-3.6.1.min.js"></script>

<script>
	$(function(){
		// 초기 웹소켓은 연결 해제 상태
		disconnectState();
		
		// 1. 연결버튼을 누를 때 - 웹소켓 연결 생성
		$(".btn-connect").click(function(){
	
			// 웹소켓 연결 주소 설정
			var uri = "ws://localhost:8888/ws/json";
			
			// 웹소켓 연결 생성
			//window.socket = new WebSocket(uri);
			socket = new WebSocket(uri); // 변수로 만들지 말고 window에 붙여서 만듬
			
			//console.log(socket);
			
			// 웹소켓에 대한 이벤트 설정
			// 1) 웹소켓 연결이 생성될 때
			socket.onopen = function(){
				console.log("open");	
				connectState();	// 연결 상태일 때 connectState() 실행
			};
			
			// 2) 웹소켓 연결 중 연결이 해제될 때
			socket.onclose = function(){
				console.log("close");
				disconnectState(); // 해제 상태일 때 disconnectState() 실행
			};
			
			// 3) 웹소켓 연결 중 연결에 에러가 발생할 때
			socket.onerror = function(){
				console.log("error");
				disconnectState(); // 에러 상태일 때 disconnectState() 실행
			};
			
			// 4) 웹소켓 연결 중 메시지가 수신될 때
			socket.onmessage = function(e){
				
				// 문자열을 JSON 형태로 수신 - JSON.parse()
				var data = JSON.parse(e.data);
				//console.log(data);
				
				// 수신한 JSON의 text를 태그 사이의 문자열로 하는 p 태그 지정
				var p = $("<p>").text(data.text);
				
				// 수신한 JSON의 time 형태 변경 
				var time = moment(data.time).format("YYYY-MM-DD hh:mm");
				
				// 변경된 time을 태그 사이의 문자열로 하는 span 태그 지정
				var span = $("<span>").text("(" + time +")");
				
				// p 태그 안에 span 태그 추가
				p.append(span);
				
				// div 태그(id = message-list)에 p태그 추가
				$("#message-list").append(p);
			};
			
		});
		
		// 2. 종료 버튼을 누를 때 - 웹소켓 연결 해제
		$(".btn-disconnect").click(function(){
			// 웹소켓 연결 종료
			//window.socket.close();
			socket.close();
		});
		
		// 3. 전송 버튼을 누를 때 - 웹소켓에 연결된 모든 사용자에게 메시지 전달
		$("#message-send").click(function(){
			// 입력창의 값 지정
			var text = $("#message-input").val();
			
			// 입력창이 비어있으면 return
			if(text.length == 0) return;
			
			// 입력창의 값을 JSON으로 변환하여 전송
			var data = {
				text : text
			}
			
			// 입력창의 값 전송
			// window.socket.send(text);
			socket.send(JSON.stringify(data));
			
			// 전송 후 입력창 초기화(비우기)
			$("#message-input").val("");
		});
		
		// 웹소켓 연결이 만들어진 상태일 때
		function connectState(){
			$(".btn-connect").prop("disabled", true); // 연결버튼 비활성화
			$(".btn-disconnect").prop("disabled", false); // 종료버튼 비활성화 해제
		}
		
		// 웹소켓 연결이 해제된 상태일 때
		function disconnectState(){
			$(".btn-connect").prop("disabled", false); // 연결버튼 비활성화 해제
			$(".btn-disconnect").prop("disabled", true); // 종료버튼 비활성화
		}
	});
</script>

 


웹소켓을 이용한 실시간 채팅 구현(3) - SockJS

SockJS

- 웹소켓을 지원하지 않는 브라우저에서 Streaming, Long-Polling과 같은 다른 HTTP 기반의 기술을 통해 연결을 제공

- 주소를 http 또는 https로 시작하게 해줌

 

SockJSWebsocketServer

@Slf4j
@Service
public class SockJSWebsocketServer extends TextWebSocketHandler {
	
	// 웹소켓 사용자 저장소 - Set(중복 방지)
	private Set<WebSocketSession> users = new CopyOnWriteArraySet<>();
	
	@Override
	public void afterConnectionEstablished(WebSocketSession session) throws Exception {
		users.add(session);
	}
	
	@Override
	public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
		users.remove(session);
	}
	
	@Override
	protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
		
		log.debug("메시지 - {}", message.getPayload());
		
		// ObjectMapper의 인스턴스 생성 
		ObjectMapper mapper = new ObjectMapper();
		
		// 1. JSON을 Java Object로 변환 - readValue()
		// 1) JSON을 Map 형태로 변환
		//Map json = mapper.readValue(message.getPayload(), Map.class);
		//log.debug("json = {}", json);
		
		// 2) JSON을 클래스의 인스턴스 형태로 변환
		MessageVO json = mapper.readValue(message.getPayload(), MessageVO.class);
		log.debug("json = {}", json);
		
		// 인스턴스에 시간 설정
		json.setTime(new Date());
		
		// 2. Java Object를 JSON 형태로 변환 - writeValue()
		// - 클래스의 인스턴스를 JSON 형태로 변환 
		String payload = mapper.writeValueAsString(json);
		TextMessage jsonMessage = new TextMessage(payload);
		
		// 웹소켓에 연결된 모든 사용자에게 메시지 전송
		for(WebSocketSession user : users) {
			user.sendMessage(jsonMessage);
		}
	}
}

 

WebSocketConfiguration

- SockJS 사용시 .withSockJS()를 붙인다

@Configuration
@EnableWebSocket // 웹소켓 활성화
public class WebSocketServerConfiguration implements WebSocketConfigurer {

	// 의존성 주입
	@Autowired
	private SockJSWebsocketServer sockJSWebsocketServer;
	
	@Override
	public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {

		registry.addHandler(sockJSWebsocketServer, "ws/sockjs").withSockJS();
	}	
}

 

PageController

@Controller
@RequestMapping("/page")
public class PageController {
	
	@Autowired
	private SqlSession sqlSession;
	
	@GetMapping("/sockjs")
	public String sockjs() {
		return "sockjs";
	}
}

 

sockjs.jsp

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

<h1>SockJS 예제</h1>

<button class = "btn-connect">연결</button>
<button class = "btn-disconnect">종료	</button>

<hr>

<input type = "text" id = "message-input">
<button type = "button" id = "message-send">전송</button>

<hr>

<div id = "message-list"></div>

<!-- Moment CDN -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js"></script>

<!-- SockJS CDN -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/sockjs-client/1.6.1/sockjs.min.js"></script>

<!-- JQuery CDN -->
<script src="https://code.jquery.com/jquery-3.6.1.js"></script>

<script>
	$(function(){
		// 초기 웹소켓은 연결 해제 상태
		disconnectState();
		
		// 1. 연결버튼을 누를 때 - 웹소켓 연결 생성
		$(".btn-connect").click(function(){
	
			// 웹소켓 연결 주소 설정
			// - SockJS를 사용하면 주소를 http로 시작하도록 할 수 있다
			var uri = "${pageContext.request.contextPath}/ws/sockjs";
			
			// 웹소켓 연결 생성
			// - 접속시 WebSocket이 아닌 SockJS 객체를 생성
			socket = new SockJS(uri); // 변수로 만들지 말고 window에 붙여서 만듬
			
			//console.log(socket);
			
			// 웹소켓에 대한 이벤트 설정
			// 1) 웹소켓 연결이 생성될 때
			socket.onopen = function(){
				console.log("open");	
				connectState();	// 연결 상태일 때 connectState() 실행
			};
			
			// 2) 웹소켓 연결 중 연결이 해제될 때
			socket.onclose = function(){
				console.log("close");
				disconnectState(); // 해제 상태일 때 disconnectState() 실행
			};
			
			// 3) 웹소켓 연결 중 연결에 에러가 발생할 때
			socket.onerror = function(){
				console.log("error");
				disconnectState(); // 에러 상태일 때 disconnectState() 실행
			};
			
			// 4) 웹소켓 연결 중 메시지가 수신될 때
			socket.onmessage = function(e){
				
				// 문자열을 JSON 형태로 수신 - JSON.parse()
				var data = JSON.parse(e.data);
				//console.log(data);
				
				// 수신한 JSON의 text를 태그 사이의 문자열로 하는 p 태그 지정
				var p = $("<p>").text(data.text);
				
				// 수신한 JSON의 time 형태 변경 
				var time = moment(data.time).format("YYYY-MM-DD hh:mm");
				
				// 변경된 time을 태그 사이의 문자열로 하는 span 태그 지정
				var span = $("<span>").text("(" + time +")");
				
				// p 태그 안에 span 태그 추가
				p.append(span);
				
				// div 태그(id = message-list)에 p태그 추가
				$("#message-list").append(p);
			};
			
		});
		
		// 2. 종료 버튼을 누를 때 - 웹소켓 연결 해제
		$(".btn-disconnect").click(function(){
			// 웹소켓 연결 종료
			//window.socket.close();
			socket.close();
		});
		
		// 3. 전송 버튼을 누를 때 - 웹소켓에 연결된 모든 사용자에게 메시지 전달
		$("#message-send").click(function(){
			// 입력창의 값 지정
			var text = $("#message-input").val();
			
			// 입력창이 비어있으면 return
			if(text.length == 0) return;
			
			// 입력창의 값을 JSON으로 변환하여 전송
			var data = {
				text : text
			}
			
			// 입력창의 값 전송
			// window.socket.send(text);
			socket.send(JSON.stringify(data));
			
			// 전송 후 입력창 초기화(비우기)
			$("#message-input").val("");
		});
		
		// 웹소켓 연결이 만들어진 상태일 때
		function connectState(){
			$(".btn-connect").prop("disabled", true); // 연결버튼 비활성화
			$(".btn-disconnect").prop("disabled", false); // 종료버튼 비활성화 해제
		}
		
		// 웹소켓 연결이 해제된 상태일 때
		function disconnectState(){
			$(".btn-connect").prop("disabled", false); // 연결버튼 비활성화 해제
			$(".btn-disconnect").prop("disabled", true); // 종료버튼 비활성화
		}
	});
</script>

'국비교육 > 국비교육' 카테고리의 다른 글

day77 - 1116  (0) 2022.11.16
day76 - 1115  (0) 2022.11.16
day73 - 1110  (0) 2022.11.12
day72 - 1109  (0) 2022.11.12
day71 - 1108  (0) 2022.11.08