1. pom.xml 설정
<!-- 웹 소캣 설정 -->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-websocket -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
<version>${org.springframework-version}</version>
</dependency>
<!-- 이 부분은 httpsession을 사용할 때 작성
<dependency>
<groupId>javax.websocket</groupId>
<artifactId>javax.websocket-api</artifactId>
<version>1.1</version>
<scope>provided</scope>
</dependency>
-->
2. servlet-context.xml 설정
1) namespace websocket 체크하기
2) 코드 작성 (servlet-context.xml)
<beans:bean id="replyEchoHandler" class="org.socket.socket.ReplyEchoHandler"></beans:bean>
<websocket:handlers>
<websocket:mapping handler="replyEchoHandler" path="/replyEcho"/>
<!-- 이 부분은 http세션을 사용할 때 작성
<websocket:handshake-interceptors>
<beans:bean class="org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor">
</beans:bean>
</websocket:handshake-interceptors>
-->
</websocket:handlers>
웹 소켓 통신 경로는 “replyEcho”이고 이를 replyEchoHandler가 관리한다는 의미와 같다.
웹 소켓 통신을 관리(?)하기 위해서 replyEchoHandler를 작성해주면 된다.
또 여러 개의 웹 소켓을 사용하고싶다면
<websocket:mapping handler="replyEchoHandler" path="/replyEcho2"/>와 같이 생성해주면 된다.
이제 jsp페이지에서 아래 경로를 통해서 통신할 수 있다.
주의할 점은 http통신이 아니라 웹 소켓의 약자인 ws통신이다.
var was = new WebSocket("ws://localhost:8080/controller/replyEcho");
웹 소켓에서는 세션을 따로 저장한다. 소켓에서 http세션을 사용하기 위해서는 pom.xml에 설정해둔 websocket-api를 이용해서 가져올 수 있다. pom,xml에 설정한 내용을 사용하기 위해서 HttpSessionHandshakeInterceptor클래스를 빈으로 등록한다. 필자는 시큐리티 로그인을 해서 회원정보를 가져올 때는 httpSession을 사용할 필요가 없어서 주석처리 하겠다.
3. ReplyEchoHandler 작성하기 (서버)
이 replyEchoHandler에서는 TextWebSocketHandler를 상속받아서 사용한다. 웹 소켓 통신으로 문자만 받기 위해서
이다. 다른 형식으로 주고받기 위해서는 다른 핸들러를 상속받으면 된다.
afterConnectionEstablished(), handleTextMessage(), afterConnectionClosed() 등의 메소드를 Override 해서 사용하면 된다.
public class ReplyEchoHandler extends TextWebSocketHandler {
// 커넥션이 연결된 후
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
System.out.println("연결 후 : " + session)
}
// 소켓에 메세지를 보냈을 때 ((서버입장에서 메시지를 받았을 때))
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message)
throws Exception {
}
// 커넥션이 닫혔을 때
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
}
}
소켓 통신을 제어하기 위해서 이 메소드들을 작성해주면 된다.
이제 각 메소드들을 하나하나 작성해보겠다.
먼저 필드에 접속한 클라이언트들의 정보를 저장하기 위해서 리스트를 만들었다.
public class SocketHandler extends TextWebSocketHandler{
List<WebSocketSession> sessionList = new ArrayList<WebSocketSession>()
(...이하 생략)
}
1) afterConnectionEstablished
연결이 된 후 sessionList에 접속한 세션을 담아준다. 또 session.getId()를 해주면 연결된 세션의 id를 볼 수 있다.
시큐리티 로그인을 한 경우 session.getPrincipal().getName()을 통해 로그인한 사용자의 id를 가져올 수 있다.
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
sessionList.add(session);
log.info("연결된 세션 : " + session.getId());
log.info("채팅방 입장 아이디 : " + session.getPrincipal().getName());
System.out.println("afterConnectionEstablished : " + session);
}
2) handleTextMessage
이 메소드는 메시지를 받았을 때 작동하는 메소드이다.
소켓 통신으로 받은 메시지를 가져와서 연결된 모든 사용자들한테 전송함
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
for(WebSocketSession sess : sessionList) {
log.info(sess.getPrincipal().getName() + "에게" + message.getPayload()+"전달함");
sess.sendMessage(new TextMessage(session.getPrincipal().getName()+"|"
+message.getPayload()));
}
}
3) afterConnectionClosed
이 메소드는 커넥션이 끊어졌을 때 작동하는 메소드이다. 특정 사용자가 연결을 끊었을 때
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
sessionList.remove(session);
log.info(session.getPrincipal().getName() + "와의연결이끊김!")
System.out.println("채팅방 퇴장자: "+ session.getPrincipal().getName());
}
4) jsp작성 (클라이언트)
1) 웹 소켓 커넥션
jsp에서 아래 코드를 실행하면 자동으로 커넥션을 요청한다.
var was = new WebSocket("ws://localhost:8080/controller/replyEcho");
2) 웹 소켓 제어
javascript의 다음 함수로 웹 소켓을 제어할 수 있다.
was.onopen() = function(){}; : 소켓이 열렸을 때 실행할 메소드를 정의
was.onclose() = function(){}; : 소켓 연결이 종료된 순간에 작동할 내용을 작성
was.onmessage() = function(){}; : 메시지를 받은 순간에 작동할 내용을 작성
was.onerror() = function(){} : 에러가 발생한 경우에 작동할 내용 작성
was.close() ; 소켓 연결을 종료, 종료했으므로afterConnectionClosed() 를 실행
was.send("msg") : 소켓 통신으로 메시지를 보냄
이 보낸 메시지는 handleTextMessage()에서 받아서 처리하는데 여기서 접속된 클라이언트에 다시 보내주면 채팅방이 형성된다.
was.onmessage = function(e){e.data}: 서버로부터 메시지를 받았을 때 실행할 메소드를 작성, 받은 메시지를 꺼내기 위해서 e.data를 사용한다.
3) 코드 작성
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</head>
<body>
<input type="text" id="msg" class="form-control">
<button id="btn">Send Message</button>
<script type="text/javascript">
let inputValue = $("input#msg").val();
$("document").ready(function() {
var socket = null;
connect();
});
function connect() {
var was = new WebSocket("ws://localhost:8080/controller/replyEcho");
socket = was;
socket.onopen = function() {
console.log('info: connection opened!');
socket.onmessage = function(event) {
var rawMessage = event.data;
var messageArr = rawMessage.split("|");
var messageSender = null;
var originMessage = null;
if (messageArr.length == 2) {
messageSender = messageArr[0];
originMessage = messageArr[1];
console.log(messageSender + "가 [" + originMessage
+ "] 보냄");
} else {
socket.close();
console.log("커넥션 닫음");
}
}
socket.onclose = function(event) {
console.log("Info : connection closed");
setTimeout(function() {
connect();
}, 1000);
}
socket.onerror = function(err) {
console.log("Error : connection error");
}
}
};
$("#btn").on("click", function(e) {
if (!socket) {
return;
}
let msg = $("input#msg").val();
// 소캣 메세지 전송
socket.send(msg);
});
</script>
</body>
</html>
5) 테스트 결과
크롬과 인터넷 익스플로어를 사용해서 각각 로그인을 했다.
각 브라우저에서 메시지를 보냈다.
콘솔창에서의 결과이다. 동시에 사용자 간의 통신을 하는 것을 알 수 있다.
아래 사진은 웹 소켓 통신의 큰 흐름이다.. 참고하면 이해하는데 도움이 될 것이다!
'Spring > 공부' 카테고리의 다른 글
웹 소켓 채팅 방 구현 (중간 점 채팅 방 구현 (중간 점검) (0) | 2021.04.17 |
---|---|
웹 소켓 시연 영상 (미완성) (0) | 2021.04.07 |
[Spring MVC] XML을 통한 API 다루기 (0) | 2021.02.19 |
[Spring MVC] 파일 업로드(multipart) (0) | 2021.02.17 |
[Spring MVC] 로깅 알아보기 (0) | 2021.02.17 |