Spring 20 - 웹소켓(WebSocket) - 실시간 채팅
1. <!-- 웹소켓 의존성 추가 -->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-websocket -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
<version>${org.springframework-version}</version>
</dependency>
2. 클래스 생성
extends TextWebSocketHandler
Override 메소드 생성
afterConnectionEstablished
afterConnectionClosed
handleTextMessage
handleTransportError
3. servlet-context
맨 위 beans에 추가
xmlns:websocket="http://www.springframework.org/schema/websocket"
schemaLocation =
http://www.springframework.org/schema/websocket
http://www.springframework.org/schema/websocket/spring-websocket.xsd
아래 추가
<websocket:handlers allowed-origins="*" >
<websocket:mapping handler="wsHandler" path="/socket" />
<websocket:handshake-interceptors>
<beans:bean class="org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor"/>
</websocket:handshake-interceptors>
<websocket:sockjs websocket-enabled="true"/>
</websocket:handlers>
<beans:bean id="wsHandler" class="kr.or.ddit.controller.SpringWs" />
* mapping에 handler == beans에 id
* mapping에 path는 소켓 연결path
* beans에 class는 소켓 서버클래스의 패키지경로.클래스명
4. jsp 소켓 연결
var webSocket = new SockJS("/ws/socket");
<ChatController2.java>
package kr.or.ddit.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@RequestMapping("/chat")
@Controller
public class ChatController2 {
private static Logger logger = LoggerFactory.getLogger(ChatController2.class);
// @RequestMapping(value = "/home", method = RequestMethod.GET)
// public String chat () {
// return "multiChatMain";
// }
//
@RequestMapping(value="/room", method=RequestMethod.GET)
public String chatWindow () {
return "chatWindow";
}
}
<webSocket.java>
package kr.or.ddit.controller;
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;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class webSocket extends TextWebSocketHandler {
private List<WebSocketSession> sessionList = new ArrayList<WebSocketSession>();
// 클라이언트가 연결 되었을 때 실행
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
sessionList.add(session);
log.info("{}연결됨",session.getId());
}
// 클라이언트가 웹소켓 서버로 메세지를 전송했을 때 실행
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
log.info("{}로 부터 {} 받음", session.getId(), message.getPayload());
// 모든 유저에게 메세지 출력
//for(WebSocketSession sess : sessionList) {
// sess.sendMessage(new TextMessage(message.getPayload()));
String msg = message.getPayload();
for(WebSocketSession s : sessionList) {
s.sendMessage(new TextMessage(session.getAcceptedProtocol() + msg));
}
}
//}
// 전송에 에러가 났을 때 실행함.
// @Override
// public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
// }
// 클라이언트 연결을 끊었을 떄 실행
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
sessionList.remove(session);
log.info("{} 연결 끊김", session.getId());
}
}
<chatWindow.jsp>
- 엔터를 눌렀을 때 전송
- input에 속성을 준다.
- onkeydown="if(event.keyCode==13){send();}"
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script src="https://cdn.jsdelivr.net/npm/sockjs-client@1/dist/sockjs.min.js"></script>
</head>
<body>
<div id="one">
별명:<input type="text" id="nickname" /> <input type="button"
id="enter" value="입장" />
</div>
<div id="two" style="display: none">
<input type="button" id="exit" value="퇴장" /><br />
<div id="chatarea"
style="width: 400px; height: 600px; border: 1px solid;"></div>
<input type="text" id="message" onkeydown="if(event.keyCode==13){send();}" /> />
<input type="button" id="send"
value="보내기" />
</div>
</body>
<script type="text/javascript">
var websocket = null;
one = document.getElementById("one");
two = document.getElementById("two");
document.getElementById("enter").addEventListener("click", function() {
//웹 소켓 연결해주는 함수 호출
connect();
});
document.getElementById("exit").addEventListener("click", function() {
//연결을 해제해주는 함수 호출
disconnect();
});
document.getElementById("send").addEventListener("click", function() {
//연결을 해제해주는 함수 호출
send();
});
var websocket;
//입장 버튼을 눌렀을 때 호출되는 함수
function connect() {
websocket = new SockJS("/socket");
//websocket = new WebSocket("ws://localhost:80/socket");
//웹 소켓에 이벤트가 발생했을 때 호출될 함수 등록
websocket.onopen = onOpen;
websocket.onmessage = onMessage;
websocket.onclose = onClose;
}
//퇴장 버튼을 눌렀을 때 호출되는 함수
function disconnect() {
msg = document.getElementById("nickname").value;
websocket.send(msg + "님이 퇴장하셨습니다");
websocket.close();
}
//보내기 버튼을 눌렀을 때 호출될 함수
function send() {
nickname = document.getElementById("nickname").value;
msg = document.getElementById("message").value;
websocket.send(nickname + ":" + msg);
document.getElementById("message").value = "";
}
//웹 소켓에 연결되었을 때 호출될 함수
function onOpen() {
console.log("open");
nickname = document.getElementById("nickname").value;
two = document.getElementById("two");
two.style.display = 'block';
websocket.send(nickname + "님 입장하셨습니다.");
}
//웹 소켓에서 연결이 해제 되었을 때 호출될 함수
function onMessage(evt) {
data = evt.data;
chatarea = document.getElementById("chatarea");
chatarea.innerHTML = data + "<br/>" + chatarea.innerHTML
}
function onClose() {
}
</script>
</html>
localhost/chat/room 으로 들어가게 되면
채팅이 실행된다.
참고
https://alswns1201.medium.com/spring-websocket-%EC%B1%84%ED%8C%85-c662b33dcb0b