일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- CD
- 스프링
- sql
- 네트워크
- Xcode
- CI
- 42seoul
- 프로그래밍언어론
- 인공지능
- 스프링부트
- swift
- Dining philosopher problem
- 스프링부트 웹 소켓
- JPA
- DBMS
- jenkins
- 오라클
- 다이어리
- springboot
- 밥먹는 철학자
- MySQL
- libasm
- IOS
- 리눅스
- Spring
- javascript
- 소켓
- 아이패드다이어리
- 데이터베이스
- AI
- Today
- Total
Hi yoahn 개발블로그
[SpringBoot] Web Socket 사용하기 (STOMP 메시지 프로토콜) 본문
[SpringBoot] Web Socket 사용하기 (STOMP 메시지 프로토콜)
hi._.0seon 2021. 6. 24. 23:05https://spring.io/guides/gs/messaging-stomp-websocket/
build.gradle
plugins {
id 'org.springframework.boot' version '2.5.1'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-websocket'
implementation 'org.webjars:webjars-locator-core'
implementation 'org.webjars:sockjs-client:1.0.2'
implementation 'org.webjars:stomp-websocket:2.3.3'
implementation 'org.webjars:bootstrap:3.3.7'
implementation 'org.webjars:jquery:3.1.1-1'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
test {
useJUnitPlatform()
}
빌드 시스템 구축이 다 되었으니 이제 STOMP 메시지 서비스를 만들 수 있다.
서비스 상호 작용을 고려하여 프로세스를 시작한다.
서비스는 STOMP 메세지에 이름이 포함된 메시지를 수락한다. 이름이 Fred 인 경우 다음과 유사할 수 있다.
{
"name": "Fred"
}
이름을 전달하는 메시지를 모델링하려면 이름 속성 및 해당 getName() 메서드를 사용하여 다음과 같은 Java 객체 생성
package com.example.messagingstompwebsocket;
public class HelloMessage {
private String name;
public HelloMessage() {
}
public HelloMessage(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
메시지를 수신하고 이름을 추출하면, 서비스는 인사말을 생성하고 클라이언트가 가입한 별도의 대기열에 인사말을 게시하여 메시지를 처리한다. 인사말은 다음 목록과 같이 JSON 객체로도 표시된다.
{
"content": "Hello, Fred!"
}
STOMP 메시지 프로토콜
: 웹 상에서 텍스트 송,수신을 위해 미리 정의된 특정한 규칙
텍스트 기반 프로토콜이어서 개발자가 읽기 쉽고 사용하기 좋다.
STOMP에 정의한 규칙만 잘 지키면 여러 언어, 여러 플랫폼간에서 메세지를 상호 운영할 수 있다.
전송 방식
STOMP 는 메시지를 수신할 대상 집합을 관리하는 일을 한다. STOMP는 메시지에 대한 스펙만을 정의하고 있기 때문에 기능 구현은 전적으로 서버에 맡긴다.
Frame 구조
명령과 추가적인 헤더, 추가적인 바디로 구성된다.
Frame: 몇개의 텍스트 라인으로 지정된 구조. 첫번째 라인은 텍스트(명령어)이고 이후 key:value 형태로 헤더 정보를 포함한다.
header 이후에 공백 줄을 하나 더 추가하는 것으로 header의 끝을 설정할 수 있다.
header 이후에는 Payload(Body)가 존재한다.
Payload = 전송되는 데이터 (JSON data 부분)
COMMAND
header1:value1
header2:value2
Body^@
COMMAND 명령어 리스트
- CONNECT
- SEND
- SUBSCRIBE
- UNSUBSCRIBE
- BEGIN
- COMMIT
- ABORT
- ACK
- NACK
- DISCONNECT
인사말 표현을 모델링하려면 컨텐츠 속성 및 해당하는 getContent() 메서드가 있는 기존의 평범한 Java 개체를 다음 목록과 같이 추가하십시오
package com.example.messagingstompwebsocket;
public class Greeting {
private String content;
public Greeting() {
}
public Greeting(String content) {
this.content = content;
}
public String getContent() {
return content;
}
}
스프링은 Jackson JSON 라이브러리를 사용하여 `Greeting`유형의 인스턴스를 JSON으로 자동 정렬
다음은, hello 메시지를 받고 greeting 메시지를 보내는 컨트롤러를 생성한다.
Spring의 STOMP 메시징 작업 방식에서 STOMP 메시지는 @Controller 클래스로 라우팅 될 수 있다.
package com.example.messagingstompwebsocket;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.stereotype.Controller;
import org.springframework.web.util.HtmlUtils;
@Controller
public class GreetingController {
@MessageMapping("/hello")
@SendTo("/topic/greetings")
public Greeting greeting(HelloMessage message) throws Exception {
Thread.sleep(1000); // simulated delay
return new Greeting("Hello, " + HtmlUtils.htmlEscape(message.getName()) + "!");
}
}
@MessageMapping 어노테이션은 만약 /hello 목적지로 메시지가 전송되는 경우 greeting() 메소드가 호출된다. 메시지의 페이로드가 HelloMessage 개체에 바인딩되어 greeting()으로 전달된다.
내부적으로, 이 방법의 구현은 스레드를 1초 동안 절전 상태로 만들어 처리 지연을 시뮬레이션합니다. 이는 클라이언트가 메시지를 보낸 후 서버가 비동기식으로 메시지를 처리해야 하는 한 시간이 걸릴 수 있음을 보여주기 위한 것입니다. 고객은 응답을 기다리지 않고 필요한 모든 작업을 계속할 수 있습니다.
1초 지연 후 greeting() 메소드는 Greeting 객체를 생성하고 반환합니다. 반환 값은 @SendTo 주석에 지정된 대로 /topic/greetings 의 모든 구독자에게 브로드캐스트됩니다. 입력 메시지의 이름은 삭제되므로 클라이언트 측의 브라우저 DOM에서 다시 반향되고 렌더링됩니다.
Configure Spring for STOMP messaging
이제 서비스의 필수 구성 요소가 생성되었으므로 WebSocket 및 STOMP 메시징을 사용하도록 Spring을 구성할 수 있습니다.
WebSocketConfig
package com.example.messagingstompwebsocket;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/app");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/gs-guide-websocket").withSockJS();
}
}
@Configuration : 이 클래스가 스프링 설정 클래스라는 것을 나타냄
@EnableWebSocketMessageBroker 는 메시지 브로커를 통해 WebSocket 메시지 처리를 활성화 한다.
`configureMessageBroker()` 메소드는 메시지 브로커를 구성하는 WebSocketMessageBrokerConfigurer의 기본 메소드를 구현한다. 간단한 메모리 기반 메시지 브로커가 /topic이 앞에 붙은 대상의 클라이언트로 greeting 메시지를 전달할 수 있도록 enableSimpleBroker()를 호출하는 것으로 시작된다. 또한 @MessageMapping 어노테이션이 붙은 메소드에 바인딩된 메시지에 /app 접두사를 지정한다. 이 접두사는 모든 메시지 매핑을 정의하는데 사용된다.
ex) /app/hello => GreetingController.greeting()메서드가 처리하도록 매핑된 엔드포인트
`registerStompEndpoints()` 메소드는 `/gs-guide-websocket` Endpoint를 등록하여 웹 소켓을 사용할 수 없는 경우 대체 전송을 사용할 수 있도록 SockJS fallback 옵션을 사용하도록 설정한다. SockJS 클라이언트는 `/gs-guide-websocket`에 연결하고 사용 가능한 최상의 전송을 사용하여 연결하려고 시도할 것이다.
Create a Browser Client
서버 사이드
<!DOCTYPE html>
<html>
<head>
<title>Hello WebSocket</title>
<link href="/webjars/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="/main.css" rel="stylesheet">
<script src="/webjars/jquery/jquery.min.js"></script>
<script src="/webjars/sockjs-client/sockjs.min.js"></script>
<script src="/webjars/stomp-websocket/stomp.min.js"></script>
<script src="/app.js"></script>
</head>
<body>
<noscript><h2 style="color: #ff0000">Seems your browser doesn't support Javascript! Websocket relies on Javascript being
enabled. Please enable
Javascript and reload this page!</h2></noscript>
<div id="main-content" class="container">
<div class="row">
<div class="col-md-6">
<form class="form-inline">
<div class="form-group">
<label for="connect">WebSocket connection:</label>
<button id="connect" class="btn btn-default" type="submit">Connect</button>
<button id="disconnect" class="btn btn-default" type="submit" disabled="disabled">Disconnect
</button>
</div>
</form>
</div>
<div class="col-md-6">
<form class="form-inline">
<div class="form-group">
<label for="name">What is your name?</label>
<input type="text" id="name" class="form-control" placeholder="Your name here...">
</div>
<button id="send" class="btn btn-default" type="submit">Send</button>
</form>
</div>
</div>
<div class="row">
<div class="col-md-12">
<table id="conversation" class="table table-striped">
<thead>
<tr>
<th>Greetings</th>
</tr>
</thead>
<tbody id="greetings">
</tbody>
</table>
</div>
</div>
</div>
</body>
</html>
이 HTML파일은 웹 소켓과 STOMP를 통해 서버와 통신하는데 사용될 SockJS 및 STOMP Javascript 라이브러리를 가져온다. 또한 클라이언트 애플리케이션의 로직이 포함된 app.js도 가져온다.
var stompClient = null;
function setConnected(connected) {
$("#connect").prop("disabled", connected);
$("#disconnect").prop("disabled", !connected);
if (connected) {
$("#conversation").show();
}
else {
$("#conversation").hide();
}
$("#greetings").html("");
}
function connect() {
var socket = new SockJS('/gs-guide-websocket');
stompClient = Stomp.over(socket);
stompClient.connect({}, function (frame) {
setConnected(true);
console.log('Connected: ' + frame);
stompClient.subscribe('/topic/greetings', function (greeting) {
showGreeting(JSON.parse(greeting.body).content);
});
});
}
function disconnect() {
if (stompClient !== null) {
stompClient.disconnect();
}
setConnected(false);
console.log("Disconnected");
}
function sendName() {
stompClient.send("/app/hello", {}, JSON.stringify({'name': $("#name").val()}));
}
function showGreeting(message) {
$("#greetings").append("<tr><td>" + message + "</td></tr>");
}
$(function () {
$("form").on('submit', function (e) {
e.preventDefault();
});
$( "#connect" ).click(function() { connect(); });
$( "#disconnect" ).click(function() { disconnect(); });
$( "#send" ).click(function() { sendName(); });
});
주요 기능 -> connect() & sendName() 함수
`connect()`기능은 SockJS와 stomp.js를 사용하여 SockJS서버가 연결을 대기하는 /gs-guide-websocket에 대한 연결을 연다. 연결에 성공하면 클라이언트는 /topic/greetings 목적지를 구독하고 서버가 greeting 메시지를 게시한다. 해당 목적지에서 greeting 이 수신되면 DOM에 문단 요소를 추가하여 greeting 메시지를 표시한다.
`sendName()`기능은 사용자가 입력한 이름을 검색하고 STOMP 클라이언트를 사용하여 /app/hello 목적지로 전송한다. (GreetingController.greeting()에서 수신) 원하는 경우 main.css를 생략하거나 빈 main.css를 생성하여 <link>를 해결할 수 있다.
'Framework & Library > springboot' 카테고리의 다른 글
Spring Boot 2.6.6 swagger 3.0 적용 오류 (0) | 2022.05.13 |
---|---|
[SpringBoot] CORS 에러 (0) | 2021.07.02 |
[springboot] Exception 처리 (0) | 2021.05.12 |
[springboot] Spring-Data-JPA Paging 기능 (0) | 2021.04.24 |
[springboot] swagger 연동하기 (0) | 2021.04.20 |