today_is

[ websocket ] 메모장 본문

spring

[ websocket ] 메모장

ye_rang 2024. 3. 3. 18:45

 오늘의 목표 

웹소켓으로 간단한 메모장을 만들어보자

 

 


Ajax 와 Web socket 의 차이 

: 연결의 지속성에 따라 둘을 구분한다 

 

 

 

클라이언트와 서버가 통신할 때 HTTP 통신을 주로 사용한다.

 

HTTP 통신은 다음과 같은 특징이 있다.

 

  1. 비연결성 (connectionless) : 연결을 맺고 요청을 하고 응답을 받으면 연결을 끊어버린다.
  2. 무상태성 (stateless) : 서버가 클라이언트의 상태를 가지고 있지 않는다.
  3. 단방향 통신이다.

이러한 HTTP 통신의 경우 채팅과 같은 실시간 통신에 적합하지 않다.

 

물론 HTTP 통신으로 실시간 통신을 흉내낼 수는 있으나 완벽하지는 않다.

 

실시간 통신이 필요할 때 사용하는 통신을 소켓 통신이라고 한다.

 

HTTP 통신과 다르게 연결을 맺고 바로 끊어버리는 게 아니라 계속 유지를 하기 때문에 실시간 통신에 적합하다.

 

 

 Ajax 

자바스크립트를 이용해 서버와 브라우저가 비동기 방식으로 데이터를 교환할 수 있는 통신기능

데이터를 '주고 받는' 형식 
요청과 응답이 존재
HTTP을 이용한 요청과 응답 
클라이언트의 요청이 없으면 서버의 응답도 없다 

 

 Web socket 

 

사용자의 브라우저와 서버 사이의 인터액티브 통신 세션을 설정할 수 있게 하는 고급 기술

클라이언트의 요청이 없어도 서버의 응답이 존재할 수 있음
웹소켓 연결을 끊어버리기 전까지는 자유롭게 요청, 응답이 오고갈 수 있다

  

 

 

 

 home.jsp 

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:set var="cpath" value="${pageContext.request.contextPath }" />

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>

<script src="https://cdn.jsdelivr.net/sockjs/1/sockjs.min.js"></script>

<style>
	#notepad {
		box-sizing: border-box;
		width: 700px;
		height: 400px;
		padding: 10px;
		margin: 10px 0;
		border: 2px solid black;
		font-size: 17px;
		overflow-y: auto;
	}
	form > p {
		box-sizing: border-box;
		width: 700px;
		display: flex;
		justify-content: space-between;
	}
	input[name="input"] {
		padding: 5px;
		font-size: 20px;
		flex: 5;
		margin-right: 5px;
	}
	input[type="submit"] {
		flex: 1;
	}
	
</style>

</head>
<body>

<h1>websocket 을 이용한 메모장 (sockJS)</h1>
<hr>


<div id="notepad">
</div>

	<form>
		<p><input type="text" name="input" placeholder="글을 입력">
			<input type="submit">
		</p>
			
	</form>

<script>
	//	변수선언
	const cpath = '${cpath}'
	const form = document.forms[0]
	const ws = new SockJS(cpath + '/chat')
	const notepad = document.getElementById('notepad')
	
	
	//	함수정의
	function messageHandler(event) {
		notepad.innerHTML = '<p>' + event.data + '</p>'
		notepad.scroll({
			top : notepad.scrollHeight,
			behavior : 'smooth',
		})	
	}
	
	function submitHandler(event) {
		event.preventDefault()
		const input = event.target.querySelector('input[name="input"]')
		
		
		ws.send(input.value)
		input.value = ''
		input.focus()
	}
	
	//	이벤트 연결
	ws.onmessage = messageHandler
	ws.onopen = function(msg) {}
	ws.onclose = function(msg) {}
	ws.onerror = function(msg) {}
	form.onsubmit = submitHandler
	
	
</script>


</body>
</html>

 

 

 ChatComponent 

package com.itbank.component;

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

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;

public class ChatComponent extends TextWebSocketHandler {

	
	List<WebSocketSession> sessionList = new ArrayList<>();
	

	//	저장 - source - Override/Implements method
	
	@Override	//	연결이 성립된 이후 실행되는 함수
	public void afterConnectionEstablished(WebSocketSession session) throws Exception {
		System.out.println("연결 생성 확인 : " + session);
		sessionList.add(session);
	}

	
	@Override	//	텍스트 메시지를 전달받았을 때 실행되는 함수 
	protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
		System.out.printf("메시지 받음 : [%s] : %s\n", session, message);
		
		for(WebSocketSession ws : sessionList) {	//	세션리스트에 들어가있는 모든 웹 소켓에게
			ws.sendMessage(message);		//	받은 메시지를 다시 보낸다 (== 클라이언트가 응답을 받았을 것이다)
		}
	}
	
	
	@Override	//	연결이 끊어졌을 때 실행되는 함수 
	public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
		System.out.println("연결 종료 : " + session);
		sessionList.remove(session);
	}
	
}

 

 

 에러 기록하기 ( 콘솔 에러 ) 

만약 경로를 지정하지 않았다면 에러가 뜬다 

GET http://localhost:8080/ws01/chat/info?t=1709514852080 404 (Not Found)   

 

component 클래스에 경로 지정을 하자 

 

 

[ 접속 이동 경로 살펴보기 ]

 

함수 작성 없이 먼저 연결부터 확인해보기 

 

 web.xml 에서 버전은 3.0 이상이어야한다 (web socket 지원여부)

 

1)  home.jsp 에서 script 태그 

const ws = new SockJS(cpath + '/chat')

 

2)  chatComponent 에서

afterConnectionEstablished 가 작동하면

 

3) 콘솔창에서 연결확인 메시지가 뜬다 

 

 

 콘솔창 결과 

연결이 잘되었는지 콘솔로 확인

 

 

 

 

 결과 

 


 

study_review

 

이번에는 혼자 메모장처럼 메시지를 남기는 실습을 연습했다

 

다음번엔 웹소켓을 이용한 채팅을 구현해볼 것이다!!

 

 

또한 스프링빈 등록이 제대로 되었는지 확인을 자주해야겠다.. (파일 옆에 S 가 떠있는지 확인!!)

 

가끔 스프링빈 등록이 안되어있을때도 있다. 

 

그럴때마다 설정파일 내용을 전체 선택해서 새로 붙여넣기 하거나,

alt + F5 를 한번 더 해주는 중이다...