websocket을 이용한 채팅만들기
pom.xml 에 라이브러리를 추가한다.
채팅, 푸시알림 등을 받으려면 지속적인 연결이 필요하다. 이때 사용하는 기술이 websocket
websocket을 지원안하는 브라우저가 있다. websocket을 지원안하는 브라우저를 위한 기술이 필요하다.
sockjs (스프링이 지원), socket.io 와 같은 라이브러리가 있다.
<!-- websocket -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<!-- 프론트단에서 사용하는 sockjs 라이브러리 -->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>sockjs-client</artifactId>
<version>1.0.2</version>
</dependency>
websocket을 사용하려면 몇가지 설정이 필요하다.
로그인을 한 사용자만 채팅을 하도록 할 예정.
/chatrooms
/ws <– 웹 소켓 엔드포인트 URL (웹소켓은 브라우저가 http로 요청을 보낸후, 서버가 웹소켓을 지원해주면 웹 소켓연결로 바뀐다.)
다음의 클래스와 파일을 작성한다.
설명은 주석을 참고
WebSocketConfig
@Configuration
@EnableWebSocket // 웹소켓에 대해 대부분 자동설정을 한다.
public class WebSocketConfig implements WebSocketConfigurer {
// WebSocketConfigurer를 구현하여 추가적인 설정을 한다.
// WebSocketHandler를 추가한다.
// 1. 클라이언트가 접속을 했을 때 특정 메소드가 호출
// 2. 클라이언트가 접속을 close했을 때 특정 메소드가 호출
// 3. 클라이언트가 메시지를 보냈을 때 특정 메소드 호출
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry webSocketHandlerRegistry) {
webSocketHandlerRegistry.addHandler(new ChatSocketHandler(), "/ws").withSockJS();
}
}
ChatMessage
@Data
public class ChatMessage {
private String name;
private String message;
}
ChatSocketHandler
// TextWebSocketHandler인터페이스를 구현한다.
public class ChatSocketHandler extends TextWebSocketHandler {
ObjectMapper objectMapper = new ObjectMapper();
List<WebSocketSession> list = Collections.synchronizedList(new ArrayList<>());
// 웹 소켓에 연결될 때 호출되는 메소드
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
System.out.println("접속===========================");
System.out.println(session.getId());
System.out.println("접속===========================");
list.add(session);
}
// 메시지를 전송받았을때 호출되는 메소드
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
System.out.println("메시지가 왔어요...");
System.out.println(session.getId() + ", " + message.getPayload());
System.out.println("메시지가 왔어요...");
AbstractAuthenticationToken principal = (AbstractAuthenticationToken)session.getPrincipal();
BlogSecurityUser securityUser = (BlogSecurityUser)principal.getPrincipal();
ChatMessage clientMessage = objectMapper.readValue(message.getPayload(), ChatMessage.class);
ChatMessage chatMessage = new ChatMessage();
chatMessage.setName(securityUser.getName());
chatMessage.setMessage(clientMessage.getMessage());
String json = objectMapper.writeValueAsString(chatMessage);
for(WebSocketSession wss : list){
wss.sendMessage(new TextMessage(json));
}
}
// 웹 소켓이 연결이 클로즈될때 호출되는 메소드
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
System.out.println("접속 close===========================");
System.out.println(session.getId());
System.out.println("접속 close===========================");
list.remove(session);
}
}
ChatController
@Controller
public class ChatController {
@GetMapping("/chatrooms")
public String chatrooms(){
return "chatrooms";
}
}
chatrooms.js
// sockjs 를 이용한 서버와 연결되는 객체
var ws = null;
function setConnected(connected) {
}
function showMessage(message) {
console.log(message);
var jsonMessage = JSON.parse(message);
$("#chatArea").append(jsonMessage.name + ' : ' + jsonMessage.message + '\n');
var textArea = $('#chatArea');
textArea.scrollTop( textArea[0].scrollHeight - textArea.height() );
}
function connect() {
// SockJS라이브러리를 이용하여 서버에 연결
ws = new SockJS('/ws');
// 서버가 메시지를 보내주면 함수가 호출된다.
ws.onmessage = function(message) {
showMessage(message.data);
}
}
function disconnect() {
if (ws != null) {
ws.close();
}
setConnected(false);
console.log("Disconnected");
}
function send() {
// 웹소켓 서버에 메시지를 전송
ws.send(JSON.stringify({'message': $("#chatInput").val()}));
// 채팅입력창을 지우고 포커싱하라.
$("#chatInput").val('');
$("#chatInput").focus();
}
// $(함수(){ 함수내용 }); // jquery에서 문서가 다 읽어들이면 함수()를 호출한다.
$(function () {
connect();
// 채팅입력창에서 키가 눌리면 함수가 호출
// 엔터를 입력하면 send()함수가 호출
$("#chatInput").keypress(function(e) {
if (e.keyCode == 13){
send();
}
});
$( "#sendBtn" ).click(function() { send(); });
});
chatrooms.html
<!DOCTYPE html>
<html lang="ko" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"/>
<script type="text/javascript" src="/webjars/jquery/3.3.1-2/jquery.min.js"></script>
<script type="text/javascript" src="/webjars/sockjs-client/1.0.2/sockjs.min.js"></script>
<script src="/js/chatroom.js"></script>
<title>chat room</title>
</head>
<body>
<div class="jumbotron">
<h1>chat room</h1>
</div>
<div class="container">
<div class="col-sm-12 col-md-12">
<textarea cols="80" rows="15" id="chatArea" class="form-control"></textarea>
</div>
<div class="col-sm-12 col-md-12">
<input type="text" id="chatInput" class="form-control"/>
<input type="button" id="sendBtn" value="전송" class="btn btn-primary btn-small"/>
</div>
</div>
</body>
</html>