Holmes開発者ブログ

契約マネジメントシステム「ホームズクラウド」の開発者ブログです

Spring BootでWebSocketを試す

この記事は Holmes Advent Calendar 2020 - Qiita 5 日目の記事です。


こんにちは、Holmesでサーバサイドエンジニアをしているid:c-terashimaです
12月は年末ということもありより忙しい月かと思いますが、いかがお過ごしですか?
私は技術書典10の執筆にPHPカンファレンスの当日スタッフ、子供(二人)の誕生日と慌ただしい日々を送っています。。

今回は spring-boot-starter-websocket を使ってWebSocket(STOMP)を試してみたいと思います

WebSocketとは

Web上において双方向通信を低コストで行う仕組みのことです
Webアプリケーションサーバから任意のタイミングでクライアントに情報を送信することが可能で、チャットアプリみたいに多数のクライアントにメッセージを通知する場合に双方向通信が必要になります

環境

次の環境で動作を確認しております

  • Java11
  • Gradle
  • SpringBoot 2.4.0

依存関係

build.gradleのdependenciesに spring-boot-starter-webspring-boot-starter-websocketを追加します
それ以外は必要に応じて追加してください

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-websocket'
    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    testImplementation 'io.projectreactor:reactor-test'
}

WebSocketConfig

アプリケーションでWebSocketを有効にするための構成クラスを追加します

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/websocket")    // ①
                .setAllowedOrigins("chrome-extension://ggnhohnkfcpcanfekomdkjffnfcjnjam")  // ③
                .withSockJS();
    }

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableSimpleBroker("/topic");    // ②
    }
}

①で指定している /websocket はクライアントがコネクションを貼るためのエンドポイントで、②は通知を購読する(subscribe)ためのエンドポイントになります
クライアントは /topic を購読しておくことで、サーバからの通知を受け取ることが可能になります
今回クライアントはChrome拡張機能Apic - Complete API solution - Chrome ウェブストアを利用します
クロスオリジン対策として拡張機能のホストを③に登録します

メッセージ通知

/hello APIをコールすると購読しているユーザにメッセージを通知します

@RestController
@RequiredArgsConstructor
public class Controller {
    private final SimpMessagingTemplate simpMessagingTemplate;

    @PutMapping("/hello")
    public String hello(@RequestBody Parameter parameter) {
        String message = "hello " + parameter.name;
        simpMessagingTemplate.convertAndSend("/topic", message);   // ①
        return message;
    }

    @Data
    static class Parameter {
        private String name;
    }
}

SimpMessagingTemplate#convertAndSendメソッドで /topicを購読しているユーザにメッセージを送信しています

f:id:c-terashima:20201204194719g:plain

curlを実行するとMessageがリアルタイムで表示することができました
かんたんに双方向通信を実装することができましたね!


明日はスクラムマスターをしているid:misudaさんです