안녕하세요!
프뚜(프로그래머 뚜)입니다!
[Brower > Server] 기존에 통신 방법의 HTTP는 사용자 요청(Client Request) > 서버 응답(Server Response)을 받으면 이어져있던 연결이 끊어집니다. 또한 항상 페이지 이동을 합니다.
[XMLHttpRequest > Server] XMLHttpRequest객체가 서버에 요청하는 방식으로 서버와의 연결을 잡아둡니다. Json이나 xml형태로 필요한 데이터만 주고 받을 수 있습니다. 조그만한 변경이 필요할 때, 해당 페이지 내에서 변경이 가능합니다.
[WebSocket]은 HTTP와 달리 Stateful Protocol이기 때문에 서버와 클라이언트 간의 연결을 항상 유지해야 하며 만약 비정상적으로 연결이 끊어졌을때 적절하게 대응해야 합니다. 이는 기존의 HTTP 사용시와 비교했을때 코딩의 복잡성을 가중시키는 요인이 될 수 있습니다.
Spring Boot에서 Websocket을 사용한 채팅을 구현해 보려고 합니다. WebSocket을 사용하기 위한 @ServerEndpoint Anntation이 선언 되어있는 클래스와 WebSocket에 관한 환경 설정 파일로 구현할 수 있습니다.
[개발 환경]
- OS: windows 10 64bit
- JAVA: v1.8
1. websocket dependency 추가하기
2. WebSocketConfig > Bean 생성하기
@Component
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
/*
2022.10.26[프뚜]:
Spring에서 Bean은 싱글톤으로 관리되지만,
@ServerEndpoint 클래스는 WebSocket이 생성될 때마다 인스턴스가 생성되고
JWA에 의해 관리되기 때문에 Spring의 @Autowired가 설정된 멤버들이 초기화 되지 않습니다.
연결해주고 초기화해주는 클래스가 필요합니다.
*/
return new ServerEndpointExporter();
}
}
3. WebSocket 구현하기
@ServerEndpoint(value = "/chatt")
@Service
public class WebSocketChatting {
private static Set<Session> CLIENTS = Collections.synchronizedSet(new HashSet<>());
@OnOpen
public void onOpen(Session session) {
System.out.println(session.toString());
if (CLIENTS.contains(session)) {
System.out.println("[프뚜] 이미 연결된 세션입니다. > " + session);
} else {
CLIENTS.add(session);
System.out.println("[프뚜] 새로운 세션입니다. > " + session);
}
}
@OnClose
public void onClose(Session session) throws Exception {
CLIENTS.remove(session);
System.out.println("[프뚜] 세션을 닫습니다. : " + session);
}
@OnMessage
public void onMessage(String message, Session session) throws Exception {
System.out.println("[프뚜] 입력된 메세지입니다. > " + message);
for (Session client : CLIENTS) {
System.out.println("[프뚜] 메세지를 전달합니다. > " + message);
client.getBasicRemote().sendText(message);
}
}
}
@ServerEndpoint, @Service > WebSocketChatting 클래스를 서비스(WebSocket)로 등록합니다.
사용자를 관리할 수 있는 Set 전역변수를 선언합니다.
@OnOpen > 사용자가 접속하면 session을 추가합니다.
@OnClose > 사용자가 종료되면 session을 제거합니다.
@OnMessage > 사용자가 입력한 메세지를 받고 접속되어있는 사용자에게 메세지를 보냅니다.
4. webSocket과 연동되는 js 구현하기
let ws;
const mid = getId('mid');
const btnLogin = getId('btnLogin');
const btnSend = getId('btnSend');
const talk = getId('talk');
const msg = getId('msg');
// 2022.10.26[프뚜]: 전송 데이터(JSON)
const data = {};
function getId(id) {
return document.getElementById(id);
}
btnLogin.onclick = function() {
// 2022.10.26[프뚜]: 서버와 webSocket 연결
ws = new WebSocket("ws://" + location.host + "/chatt");
// 2022.10.26[프뚜]: 서버에서 받은 메세지 처리
ws.onmessage = function(msg) {
const data = JSON.parse(msg.data);
let css;
if (data.mid === mid.value) {
css = 'class=me';
} else {
css = 'class=other';
}
const item = `<div ${css} >
<span><b>${data.mid}</b></span> [ ${data.date} ]<br/>
<span>${data.msg}</span>
</div>`;
talk.innerHTML += item;
// 2022.10.26[프뚜]: 스크롤바 하단으로 이동
talk.scrollTop=talk.scrollHeight;
}
}
msg.onkeyup = function(ev) {
if (ev.keyCode === 13) {
send();
}
}
btnSend.onclick = function() {
send();
}
function send() {
if (msg.value.trim() !== '') {
data.mid = getId('mid').value;
data.msg = msg.value;
data.date = new Date().toLocaleString();
const temp = JSON.stringify(data);
ws.send(temp);
}
msg.value = '';
}
@ServerEndpoint의 value값으로 연결합니다. 프뚜는 ws://localhost:8080/chatt로 되어있습니다.
Server에서 sendText를 받을 수 있는 function을 선언합니다.
사용자가 server에 메세지를 보내는 send function을 선언합니다.
5. 정상 작동 확인하기
프뚜와 먹뚜로 로그인을 시도합니다. > @OnOpen 메서드 호출
정상적으로 새로운 세션이 감지되었습니다.
안녕하세요 프뚜입니다.
안녕하세요 먹뚜입니다.
로 메세지를 주고 받았습니다. > @OnMessage 메서드 호출
입력된 메세지 > 2명의 사용자에게 메세지 전달됩니다.
전체적인 소스코드는 github에 공유되어있습니다.
(제목과 git history는 1:1 매칭입니다.)
'프로그램 > JAVA' 카테고리의 다른 글
[JPA] Spring boot JPA 연결 및 사용하기 (1) | 2022.10.30 |
---|---|
[Spring] Spring boot에서 PostgreSQL 연동하기 (0) | 2022.10.29 |
[Windows 10] JAVA 1.8 설치 & JAVA_HOME 세팅하기 (3) | 2022.10.26 |
[JAVA] 파일 이름, 경로, 확장자명 나누기 (1) | 2022.10.03 |
[Spring] JAVA 파일 압축하기 (ZIP, ARCHIVE) (10) | 2022.09.02 |