Chanho_Park
[WebSoket] 스프링 웹소켓 사용하여 실시간 채팅 구현 본문
저번 프로젝트에서 스프링버전이 낮아 사용하지 못해서
ajax으로 reload 시켜서 새로고침으로 실시간 되는 것처럼 진행했었는ㄷ네
이번 프로젝트에는 스프링을 5.x.x 버전 으로 올려서 웹소켓 사용이 가능하게 되었다.
먼저
http 통신
- Client 가 server에게 받고 싶은 정보를 request에 담아 전송
- server는 client의 request에 따라 response로 응답
- Client 는 server에게 받은 response의 데이터를 사용 ( Client가 자신이 어떤 데이터를 받고싶은지 server에 요청해야 데이터를 제공해주는 방식 )
실시간 채팅이라하면 1번이 서버에 메세지를 전송 server는 2에게 전송 2는 그 메세지를 받는 것이다.
기본적으로 http 통신이란 client 가 요청을 해야 server가 응답하는 방식
server 가 메세지를 도착했다는 것을 알리려해도 2번의 request가 없기 때문에 response가 없음
그래서 저는 저번에 그런 2번의 request가 없었기에 request를 다시해서 오는 새로고침을 통해 reload하여 요청을 했었다.
그 요청을 받고 response 가 왔기 때문에 실시간 통신처럼 보이는 것이었다.
웹소켓은 http 와 다르게 전 이중 통신을 지원, 1번의 요청이 없어도 server에서 먼저 1번에게 정보를 전송한다.
[ 구현 ]
먼저 Spring의 버전은 3.x.x 이상이어야 에러가 안나기 때문에 업그레이드 하는 것을 추천
버전 확인 법 pom.xml 에 맨 위쪽에 존재
먼저 pom.xml 에 의존성 추가 해준다.
Spring-websocket은 웹소켓 기능을 사용할 수 있게 해줌.
Jackson-databind는 웹소켓이 json형식으로 데이터를 주고 받기 때문에 추가
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
<version>${org.springframework-version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
그 다음 bean 객체 등록 및 xsi 스키마 수정
src-main-webapp-WEB-INF-spring-appServlet에 있는 Servlet-context.xml
밑 부분에 Namespaces 를 눌러
websocket을 클릭하여 추가해준다.(알림창이 뜰 경우 무시)
다시 namespaces 옆 source 를 누르고 아래와 같은 코드 추가
* handler="echoHandler"와 id = "echoHandler"부분을 일치시켜 맵핑
* class="com.sp.ex.EchoHandler" 부분의 class는 실제적으로 어떤 클래스에서 웹소켓을 컨트롤할 것인지에 대한 명세
그렇기에 class 부분은 EchoHandler.java를 넣을 패키지로 지정
<websocket:handlers>
<websocket:mapping handler="echoHandler" path="/echo" />
<websocket:sockjs />
</websocket:handlers>
<beans:bean id="echoHandler" class="com.spring.echohandler.EchoHandler"></beans:bean>
그런 다음 package 를 생성해주고
채팅을 할 jsp or html 로 갈 Controller를 작성해주고
그 통신을 가운데서 연결해줄 EchoHandler를 작성
* EchoController 작성
package com.spring.echohandler;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class EchoController {
@RequestMapping("/chat")
public String echo() {
System.out.println("여긴옴?");
return "Chat/Chat";
}
}
* EchoHandler 작성
package com.spring.echohandler;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
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;
@RequestMapping("/echo")
public class EchoHandler extends TextWebSocketHandler{
//세션 리스트
private List<WebSocketSession> sessionList = new ArrayList<WebSocketSession>();
private static Logger logger = LoggerFactory.getLogger(EchoHandler.class);
//클라이언트가 연결 되었을 때 실행
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
sessionList.add(session);
logger.info("{} 연결됨", session.getId());
}
//클라이언트가 웹소켓 서버로 메시지를 전송했을 때 실행
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
logger.info("{}로 부터 {} 받음", session.getId(), message.getPayload());
//모든 유저에게 메세지 출력
for(WebSocketSession sess : sessionList){
sess.sendMessage(new TextMessage(message.getPayload()));
}
}
//클라이언트 연결을 끊었을 때 실행
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
sessionList.remove(session);
logger.info("{} 연결 끊김.", session.getId());
}
}
* TextWebSocketHandler 클래스를 상속받아서 사용함
* 클라이언트가 접속할 때, 메세지를 보낼 때, 접속을 끊었을 때 각각 override된 메소드가 동작
* JSP 작성
Controller에서 return "/Chat/Chat" 으로 하였으니 WEB-INF 의 Chat폴더 안의 Chat.jsp 생성하여 작성
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.js"></script>
<!-- 소켓 라이브러리 추가해주는 코드 -->
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/sockjs-client/1.1.5/sockjs.min.js"></script>
</head>
<body>
<input type="text" id="message" />
<input type="button" id="sendBtn" value="submit"/>
<div id="messageArea"></div>
</body>
<script type="text/javascript">
$("#sendBtn").click(function() {
sendMessage();
$('#message').val('')
});
let sock = new SockJS("http://localhost:8080/echo");
sock.onmessage = onMessage;
sock.onclose = onClose;
// 메시지 전송
function sendMessage() {
sock.send($("#message").val());
}
// 서버로부터 메시지를 받았을 때
function onMessage(msg) {
var data = msg.data;
$("#messageArea").append(data + "<br/>");
}
// 서버와 연결을 끊었을 때
function onClose(evt) {
$("#messageArea").append("연결 끊김");
}
</script>
</html>
테스트를 할 때에는 다른 edge나 explorer 를 틀어서 확인하는 것이 좋음
브라우저 유형마다 한개의 session 이 가능하기 때문
이걸 이용하여 다른 사이트에도 있는 실시간채팅구현 가능
'Spring' 카테고리의 다른 글
[Spring] github push/pull 시 한글깨짐 현상 (0) | 2022.12.15 |
---|---|
[JSTL] jsp 상에서 소수점 버리기 (0) | 2022.11.21 |
[eclipse] lombok 설치 후 Eclipse 실행 안될 때 (1) | 2022.11.20 |
[Spring] Maven Update 시 Updating Maven Project 에러 (0) | 2022.11.16 |
[JAVA] Controller에서 Redirect 객체 넘기기 (0) | 2022.11.13 |