Spring BootでWebSocketを使う
WebSocketはサーバーとクライアント間の双方向通信を可能にする長い接続技術で、サーバーがクライアントに能動的に情報をプッシュすることができます。
アプリケーションを構築する
依存関係を追加する
- build.gradle
dependencies {
compile("org.springframework.boot:spring-boot-starter-websocket")
compile("org.webjars:webjars-locator-core")
compile("org.webjars:sockjs-client:1.0.2")
compile("org.webjars:stomp-websocket:2.3.3")
compile("org.webjars:bootstrap:3.3.7")
compile("org.webjars:jquery:3.1.0")
testCompile("org.springframework.boot:spring-boot-starter-test")
}
構成
- WebSocketConfig.java
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/topic");
registry.setApplicationDestinationPrefixes("/app");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/socket").withSockJS();
}
}
ここで、/topic はクライアントに送信するメッセージのパス名の接頭辞、/app はサービス・エンドポイントに送信するメッセージのパス名の接頭辞、/socket はクライアントが接続する際に使用するメッセージのパス名の接頭辞です。
グループメッセージング
メッセージを一括送信すると、そのメッセージを購読しているすべてのクライアントにメッセージを送信できます。 SendToまたはorg.springframework.messaging.simp.SimpMessagingTemplate#convertAndSendを使用して送信
サーバー
- アノテーションを使用して実現
@MessageMapping("/message/broadcast")
@SendTo("/response/message")
public Message broadcastMessage(String title) {
log.info("Receive new broadcast message from socket, title is :" + title);
return Message.builder()
.title(title)
.content("Socket Broadcast:" + title + " content!")
.createTime(LocalDateTime.now())
.build();
}
- RESTインターフェイスコールによるメソッド実装
@Autowired
private SimpMessagingTemplate simpMessagingTemplate;
@GetMapping("/message/broadcast")
@ResponseBody
public void sendBroadcastMessage(String title) {
log.info("Receive new broadcast message from REST interface, title is :" + title);
Message message = Message.builder()
.title(title)
.content("REST Broadcast:" + title + " content!")
.createTime(LocalDateTime.now())
.build();
simpMessagingTemplate.convertAndSend("/response/message", message);
}
クライアント
function a() {
var bar = new SockJS('/socket');
stompClient = Stomp.c(bar);
stompClient.connect({}, function {
stompClient.subscribe('/response/message', function {
console.log('Receive\x20message\x20from\x20server:' + obj);
});
});
}
function b() {
stompClient.send('/request/message/broadcast', {}, 'Message');
}テスト
- アプリケーションを起動し、2つの異なるブラウザで localhost:8080アクセスします。
- メッセージをブロードキャストして接続を確立し、メッセージを送信すると、両方のブラウザが送信したばかりのメッセージを受信したことがわかります。
- RESTインターフェイス経由で
curl 'localhost:8080/message/broadcast?title=hello'
指定したクライアントに送信する
メッセージをブロードキャストすると、そのメッセージを購読しているすべてのクライアントにメッセージが送信されます。@SendToUserまたはorg.springframework.messaging.simp.SimpMessagingTemplate#convertAndSend
サーバー
指定のクライアントに送信します。クライアントには指定のユーザー名が必要です。継承により実装されています。
- CustomPrinciple.java
@AllArgsConstructor
public class CustomPrinciple implements Principal {
private String name;
@Override
public String getName() {
return これ.name;
}
}- CustomHandshakeHandler.java
@Slf4j
public class CustomHandshakeHandler extends DefaultHandshakeHandler {
@Override
protected Principal determineUser(ServerHttpRequest request, WebSocketHandler wsHandler, Map<String, Object> attributes) {
String userId = UUID.randomUUID().toString();
log.info("Current username is: {}", userId);
return new CustomPrinciple(userId);
}
}
attributes) {
String userId = UUID.randomUUID().toString();
log.info(「Current username is: {}」, userId);
return new CustomPrinciple(userId);
}
} - WebSocketConfig.java
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/socket")
.setHandshakeHandler(new CustomHandshakeHandler())
.withSockJS();
}
- アノテーションを使用して実現
@MessageMapping("/message/specify")
@SendToUser("/response/message")
public Message speicifyMessage(String title) {
log.info("Receive new specify message from socket, title is :" + title);
return Message.builder()
.title(title)
.content("Socket Specify:" + title + " content!")
.createTime(LocalDateTime.now())
.build();
}
- メソッドを呼び出して実装
@GetMapping("/message/specify")
@ResponseBody
public void sendSpecifyUserMessage(String title, String username) {
log.info("Receive new specify message from REST interface, title is :" + title);
Message message = Message.builder()
.title(title)
.content("REST Specify:" + title + " content!")
.createTime(LocalDateTime.now())
.build();
simpMessagingTemplate.convertAndSendToUser(username, "/response/message", message);
}
クライアント
function bar() {
var b = new SockJS('/socket');
stompClient = Stomp.a(b);
stompClient.connect({}, function {
stompClient.subscribe('/user/response/message', function {
console.log('Receive\x20message\x20from\x20server:' + c);
});
});
}
function obj() {
stompClient.send('/request/message/specify', {}, 'Message');
}注意すべき点は、指定ユーザーへのメッセージ購読を送信する際に、/user接頭辞を追加する必要があるということです。
テスト
- アプリケーションを起動し、2つの異なるブラウザで localhost:8080アクセスします。
- 指定されたメッセージは接続を確立し、メッセージを送信します。このメッセージはメッセージを送信したブラウザのみが受信し、もう一方のブラウザは受信しません。
- RESTインターフェース経由で接続できます: 接続を確立すると、コンソールに対応するユーザー名が表示されます。
curl 'localhost:8080/message/specify?title=hello&username=test'



