WebSocket은 웹 상에서 쉽게 소켓통신을 하게 해주는 라이브러리로 실시간 채팅 서비스등 여러 유용한 서비스의 기반이 된다.스프링 환경에서는 이러한 서비스를 구현하기 위해서 필요한 2가지가 있는데 WebSocket의 기능을 보완해주고 향상시켜주는 SockJS라이브러리와 메시징전송을 좀 더 효율적으로 지원해주기 위한 STOMP 프로토콜이 존재한다. 일반 WebSocket 환경에서는 핸들러만 구현해주고 직접 호출했지만 STOMP를 이용하면 핸들러와 브로커 라는 개념을 이용해서 서로간의 통신을 하게 된다.
- STOMP
STOMP는 Simple/Streaming Text Oriented Messaging Protocol의 약자이며 텍스트 기반의 메시징 프로토콜 이다.
TCP나 WebSocket과 같은 신뢰성있는 양방향 streaming network protocol상에 사용될 수 있다. HTTP에 모델링된 frame 기반 프로토콜이다.
위의 구조에서 중요한 개념은 브로커와 Subscribe의 개념이다. STOMP는 구독이라는 개념을 통해 내가 통신 하고자 하는 주체(topic)를 판단하여 실시간 , 지속적으로 관심 을 가지며 해당 요청이 들어오면 처리하게 된다. 이러한 과정은 MessageHandler를 구현하여 처리한다.
1. Connect
<<<CONNECTED
version:1.1
heart-beat:0.0
user-name:user1
연결에 관한 구조이다. 버전정보와 현재의 세션정보를 가져온다.
2. Subscribe
>>> SUBSCRIBE
id : sub-0
destination:/topic/roomId
>>> SUBSCRIBE
id : sub-1
destination:/topic/out
>>> SUBSCRIBE
id : sub-2
destination:/topic/in
구독이라는 개념을 이용하여 현재 메세지에 대한 목적지를 설정한다. 구조를 보면 각각의 destination이 있다. connect 이후에 subscribe를 설정 하게 된다. 등록되지 않은 subscribe를 호출 시 찾을 수 없기에 정확한 통신이 되지 않는다.
3. Message
<<<MESSAGE
destination : /topic/roomId
content-type:application/json;charset=UTF-8
subscription:sub-0
message-id:2oy02l5d-71
content-length:43
{"senderName : "user1" , "sendMessage":"hi?"}
메시지 전송시 구조이다. 메시지의 전달지(destination)와 해당 메세지의 정보들이 출력 된다. 현재 위의 구조는 데이터의 타입은 JSON으로 전송하였고 목적지는 /topic/roomId이다. 메시지의 길이는 43이고 body부분은 데이터가 정의되어 있다. 데이터는 JSON구조로 key, value로 되어있다. 다양한 데이터 타입을 가질 수 있다.
4. Disconnect
>>>DISCONNECT
연결을 종료했을 시 구조이다.
Websocket설정에서는 bean생성과 handler 매핑을 xml파일로했지만
Stomp연동에서는 xml이아닌 java파일로 설정파일로 구성할것이다.
config파일인 WebSocketConfig.java와 핸들러를 담당할 MessageHandler.java를 생성해준다.
WebSocketConfig.java
package com.dongho.won;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.slf4j.Logger; import org.slf4j.LoggerFactory;
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
private static Logger logger = LoggerFactory.getLogger(WebSocketConfig.class);
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
//메시지 브로커가 /topic/이 들어가는 구독자들에게 메시지를 전달해준다.
config.enableSimpleBroker("/topic/");
//클라이언트가 서버에게 /app 을 붙이고 메시지를 전달할 주소
config.setApplicationDestinationPrefixes("/app");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
//클라이언트가 서버에 접속할 Endpoint를설정한다.엔드포인트는 여러개 추가가능하다 .
//client에서 Websocket대신 향상된 SockJS로 접속하려면 .withSockJS.()를 붙여준다.!
registry.addEndpoint("/websocketHandler").withSockJS();
logger.info("{}","세션접속");
}
}
MessageHandler.java
package com.dongho.won;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import com.dongho.vo.MemberVO;
@RestController public class MessageHandler {
@Autowired RestTemplate rest;
private static Logger logger = LoggerFactory.getLogger(MessageHandler.class);
//WebSocketConfig에서 설정한 destinationprefix + 클라이언트가 전송할 mapping주소
//클라이언트가 /app/in 을 붙여 서버로 메시지를 전송한다.
@MessageMapping("/in/tt")
// /topic/in을 구독하고있는 클라이언트에게 데이터를 전송한다.
@SendTo("/topic/in")
public MemberVO in(MemberVO membervo) throws Exception{
//String test=rest.getForObject("http://localhost:8080/won/register", String.class);
rest.postForObject("http://localhost:8080/won/register2", membervo, String.class);
logger.info("{}",membervo + "클라이언트에게 전송");
return membervo;
}
}
chat.jsp
function connect() {
var text="abc";
var text2="def";
var socket = new SockJS('/won/websocketHandler');
//websocket이아닌 SockJS로 접속한다.
stompClient = Stomp.over(socket);
//stompClient에 socket을 넣어준다.
stompClient.connect({}, function() {
//접속
stompClient.send('/app/in/tt', {}, JSON.stringify({'id':text, 'pw':text2}));
stompClient.subscribe('/topic/in', function(msg) {
alert(msg);
});
});
}
connect();
'Framework > Spring Framework' 카테고리의 다른 글
[SpringFramework] RESTFul Web Service - GET, POST, PUT, DELETE 개념 (0) | 2018.08.06 |
---|---|
[SpringFramework] RESTful방식의 @RestController 와 @ResponseBody란? (13) | 2018.08.05 |
[Spring Framework] redirect(리다이렉트) vs forward(포워드) (2) | 2018.07.26 |
[Spring Framework] @RequestMapping 파라미터 (0) | 2018.07.25 |
[Spring Framework] Form 데이터(폼 데이터) 데이터(커맨드) 객체 (0) | 2018.07.25 |
댓글