SpringBoot+WebSocketで特定のユーザーに情報を送る
SpringBootでWebSocketを使ってWebRTCのシグナリングサーバーを作ろうとしたらSpringのWebSocketに関する情報が今一つなくて苦労したので備忘も兼ねて。
ちなみに、STOMPの利用が前提。
やりたかったこと
- WebSocketを使って、特定のユーザーにのみ情報を送る
- ユーザーはSpringSecurityで管理されているものとする
- 基本1対1通信
SpringBootでWebSocketを使うための準備
依存ライブラリの追加
EclipseのSTSを利用する場合
利用するものにメッセージング>WebSocketを追加
maven
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
gradle
compile("org.springframework.boot:spring-boot-starter-websocket")
```
## Configの追加
以下のようなクラスをComponentScanのかかるところに置いておく
``` java
@Configuration
@EnableWebSocketMessageBroker //STOMPを用いたブローカーベースのWebSocketを有効化する
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer //古い資料だとAbstractWebSocketMessageBrokerConfigurerを使えと書いてあるが、今はこちら。
{
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/queue", "/user");//サーバーサイドから送り返す先のprefix
config.setApplicationDestinationPrefixes("/app");//MessageMappingのprefix
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws").withSockJS();//ブローカーに管理させるエンドポイント。クライアントサイドでSockJsを利用する場合。
}
}
```
## Controllerの実装
``` java
@Controller
public class WebSocketController {
@Autowired//SpringBttoがよろしく作ってくれるので自分でConfigを書く必要はない
private SimpMessagingTemplate simpMessagingTemplate;
@MessageMapping("/test")//setApplicationDestinationPrefixesで指定した値を付け加えた、app/testに送信した値がここに来る
public void sendMessage(Principal principal,//PrincipalはSpringSecurityと同様。ユーザー情報の取得に用いる
@Payload String message//クライアントサイドから送られたメッセージ
) {
//何らかのロジックで送り先のユーザーID=toUserId(Principal.getUserName()で取れるもの)を取得する
simpMessagingTemplate.convertAndSendToUser(toUserId, "/queue/test", sendMessage);//toUserIdが/user/queue/testをsubscribeしているところにsendMessageを送る
//convertAndSendToUserは内部でよろしく特定のユーザー向けに宛先を調整してくれるので、
//ここの開発者が細かい制御をする必要はない
}
}
```
## Clientサイドの実装
前提として、
* stomp.js,sock.jsは読み込まれている
* SpringSecurityでのログインは済んでいる
ものとします。
```js
const socket = new SockJS('/ws'); //WebSocketConfig.registerStompEndpointsで指定したもの
const stompClient = Stomp.over(socket);
stompClient.connect({},function(frame){
//接続成功時のコールバック関数
stompClient.subscribe('/user/queue/test',function(result){//subscribe対象の指定
//convertAndSendToUserの引数とsubscribeの引数が異なるので注意。userによる変換がかかるのでこちらはuserを指定。
const sendMessage = result.body;//送信されたものはbodyで取り出す
});
});
//何か送るとき
stompClient.send('/app/test',{},message);//WebSocketConfigで指定したapp + Controllerで指定したtest
//今回空で渡している第二引数はheaderを入れる部分
```
## その他注意点
### nginxを挟む時は注意
proxy内に以下を追記しないと400エラーが発生して接続できない
```conf
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
```