本篇範例是建立一個 WebSocket 通道,連上此 WebSocket 的所有 Client 端,每5秒會收到 Server 廣播的訊息。使用 Spring Boot 1.4.2 版本,gradle設定如下:
dependencies {
// https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-websocket
compile group: 'org.springframework.boot', name: 'spring-boot-starter-websocket', version: '1.4.2.RELEASE'
// https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web
compile group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '1.4.2.RELEASE'
// https://mvnrepository.com/artifact/org.slf4j/slf4j-api
compile group: 'org.slf4j', name: 'slf4j-api', version: '1.7.25'
}
於 WebSocketConfiguration 中綁定 WebSocketHandler 與 URI 之關係,本例的 WebSocket URI 為 ws://IP:Port/greet。Client須知此URI,以建立 WebSocket 連線。
@Configuration
public class WebSocketConfiguration implements WebSocketConfigurer {
@Autowired
private GreetWebSocketHandler greetWebSocketHandler;
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(greetWebSocketHandler, "/greet").setAllowedOrigins("*");
}
}
WebSocketHandler用來處理 WebSocket連線的相關 Event,Event 包括 Client 建立連線、關閉連線、傳輸錯誤、Client送來訊息等。
@Component
public class GreetWebSocketHandler extends TextWebSocketHandler {
private final Logger logger = LoggerFactory.getLogger(GreetWebSocketHandler.class);
//Map: 儲存Client Session。
public ConcurrentMap sessions = new ConcurrentHashMap<>();
@Override
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
exception.printStackTrace(pw);
logger.error("TransportError:" + session.getId());
logger.error(sw.toString());
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
logger.info("SessionClosed: " + session.getId());
if(sessions.containsKey(session.getId())) {
//將 Session 自 Map 刪除
sessions.remove(session.getId());
}
}
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
logger.info("SessionCreated: " + session.getId());
//將 Session 加到 Map
sessions.put(session.getId(), session);
}
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
logger.info("Message: " + message.getPayload());
session.sendMessage(new TextMessage("Hi, " + message.getPayload()));
}
}
啟動 Scheduler,每 5 秒送訊息給所有 Client 。
@Component
public class GreetingTaskScheduler {
@Autowired
private GreetingTask task;
@Autowired
private ThreadPoolTaskScheduler scheduler;
@PostConstruct
private void start() {
scheduler.setPoolSize(1);
scheduler.setThreadNamePrefix("GreetingTaskScheduler");
scheduler.scheduleAtFixedRate(task, 5000);
}
@Component
public class GreetingTask implements Runnable {
private Logger logger = LoggerFactory.getLogger(GreetingTask.class);
private SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
@Autowired
GreetWebSocketHandler handler;
@Override
public void run() {
String msg = "The time is now " + dateFormat.format(new Date());
WebSocketSession[] sessions = handler.sessions.values().toArray(new WebSocketSession[]{});
//Broadcast訊息給所有Client
for(WebSocketSession session: sessions) {
try {
session.sendMessage(new TextMessage(msg));
logger.info(session.getId() + ": The time is now {}", dateFormat.format(new Date()));
} catch (IOException e) {
}
}
}
}
}
Client 端測試:
使用 Chrome 的擴充功能 "Simple WebSocket Client"進行測試。
連到 ws://IP:PORT/greet後,每 5 秒收到 Server 廣播的 Server Side 時間。
多開幾個頁籤進行連線,每個頁籤在 Server 端視為不同 Session (session id 不同),皆可收到廣播的訊息。
另外,javascript部份也蠻簡單,
可參考 https://www.tutorialspoint.com/html5/html5_websocket.htm
<!DOCTYPE HTML>
<html>
<head>
<script type = "text/javascript">
function WebSocketTest() {
if ("WebSocket" in window) {
console.log("WebSocket is supported by your Browser!");
// Let us open a web socket
var ws = new WebSocket("ws://localhost:8080/greet");
ws.onopen = function() {
// Web Socket is connected, send data using send()
ws.send("Message to send");
console.log("Message to send");
};
ws.onmessage = function (evt) {
var received_msg = evt.data;
console.log(received_msg);
};
ws.onclose = function() {
// websocket is closed.
console.log("closed");
};
} else {
// The browser doesn't support WebSocket
console.log("WebSocket NOT supported by your Browser!");
}
}
</script>
</head>
<body>
<div id = "sse">
<a href = "javascript:WebSocketTest()">Run WebSocket</a>
</div>
</body>
</html>
以上~
沒有留言:
張貼留言