SpringBoot使用WebSocket
阿新 • • 發佈:2018-11-19
WebSocket 介紹
WebSocket 是一種建立在TCP之上的協議,主要用於解決伺服器和客戶端雙向通話問題,具體可以參考 阮一峰WebSocket教程。
Java Web專案使用WebSocket
JSR356 中對Java WebSocket API 有詳細的規定,包含客戶端API和服務端API,在使用java編寫客戶端時,利用註解是比較方便的方式,在類上新增@ClientEndpoint, 在不同的方法上新增@OnOpen @OnClose @OnError @OnMessage來處理不同的事件。
使用JAVA更多應用場景是提供WebSocket服務,同樣也是通過註解的方式可以快速實現,在類上新增@ServerEndpoint,如
@ServerEndpoint("/game/{gameType}")
public class GameServer {
@OnOpen
public open () {...}
@OnClose
public close() {...}
@OnMessage
public message() {...}
@OnError
public error() {...}
}
通過上述的編碼,可以獲得一個地址類似 ws[s]://ip:port/game/type1 的WebSocket服務,要想獲取gameType的值,可以使用@PathParam 註解
@OnMessage public message(@PathParam("gameType") String gameType) {...}
Spring 中使用WebSocket
Java Web 最常用的框架自然是Spring莫屬,在Spring中可以直接使用Java WebSocket API來提供服務,如果使用內建的web容器,需要做的僅僅是需要在配置檔案中新增
/** * The bean shown in the preceding example registers any @ServerEndpoint * annotated beans with the underlying WebSocket container. When deployed to a * standalone servlet container, this role is performed by a servlet container * initializer, and the ServerEndpointExporter bean is not required. * * @return */ @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); }
Spring 對WebSocket 也提供了一定的封裝支援,可以參考Spring 的官網說明, 其實也比較簡單,下面是我參考官網寫的一段程式碼
package com.iflytek.research.storage.config;
import javax.annotation.Resource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
import com.iflytek.research.storage.repository.FileObjectRepository;
import com.iflytek.research.storage.repository.UserRepository;
import com.iflytek.research.storage.websocket.SearchHandler;
/**
* 開啟WebSocket支援
* 參考:https://docs.spring.io/spring/docs/5.1.2.RELEASE/spring-framework-reference/web.html#websocket
*
* @author ljgeng
*/
@Configuration
@EnableWebSocket
public class WebSocketConfiguration implements WebSocketConfigurer {
@Resource
FileObjectRepository fileObjectRepository;
@Resource
UserRepository userRepository;
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(new SearchHandler(fileObjectRepository,userRepository), "/api/search/**/").setAllowedOrigins("*");
}
/**
* The bean shown in the preceding example registers any @ServerEndpoint
* annotated beans with the underlying WebSocket container. When deployed to a
* standalone servlet container, this role is performed by a servlet container
* initializer, and the ServerEndpointExporter bean is not required.
*
* @return
*/
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
Spring Security 和 WebSocket
我的專案是使用SpringBoot 搭建的,同時引入了Spring Security 來做安全管理,在釋出WebSocket服務並不用過多處理,在上述的SearchHandler中,它繼承了TextWebSocketHandler,在重新實現handleTextMessage方式時,其中有一個引數WebSocketSession就包含了使用者資訊
public class SearchHandler extends TextWebSocketHandler {
private final FileObjectRepository fileObjectRepository;
private final UserRepository userRepository;
public SearchHandler(FileObjectRepository fileObjectRepository,UserRepository userRepository) {
this.fileObjectRepository = fileObjectRepository;
this.userRepository = userRepository;
}
@Override
public void handleTextMessage(WebSocketSession session, TextMessage message) {
// 當前使用者賬號
Principal principal = session.getPrincipal();
String username = principal.getName();
...
}
...
}