當用戶在 A 地點向資料庫插入資料時,B 地點的頁面能即時看到變更,這屬於典型的「伺服器推送」或「即時同步」場景。傳統 JSP 基於請求-回應模型,無法主動推送更新,需引入額外機制。
| 方案 | 原理 | 優點 | 缺點 |
|---|---|---|---|
| 定時輪詢 | 前端定時發送 AJAX 請求查詢最新資料 | 實作簡單,相容性好 | 延遲明顯,增加伺服器負載 |
| Long Polling | 客戶端發起請求,伺服器有資料才回應 | 較輪詢即時,減少無效請求 | 佔用連線資源,需處理超時重連 |
| Server-Sent Events (SSE) | HTTP 長連線,伺服器單向推送文字流 | 原生支援斷線重連,輕量 | 僅單向,IE 不支援 |
| WebSocket | 全雙工長連線,雙向即時通訊 | 延遲極低,雙向通訊 | 需 WebSocket 伺服器支援,舊瀏覽器不相容 |
若專案已使用 Spring 框架,整合 WebSocket 最為順暢:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-messaging</artifactId>
</dependency>
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/sync").withSockJS(); // 支援 SockJS 降級
}
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/topic");
registry.setApplicationDestinationPrefixes("/app");
}
}
@Controller
public class DataSyncController {
@Autowired private SimpMessagingTemplate messagingTemplate;
@PostMapping("/insert")
public ResponseEntity<Void> insertData(@RequestBody DataDTO dto) {
dataService.save(dto);
messagingTemplate.convertAndSend("/topic/dataUpdate", dto); // 推送給所有訂閱者
return ResponseEntity.ok().build();
}
}
<script src="https://cdn.jsdelivr.net/npm/sockjs-client/dist/sockjs.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/stompjs/lib/stomp.min.js"></script>
<script>
const socket = new SockJS('/sync');
const stompClient = Stomp.over(socket);
stompClient.connect({}, () => {
stompClient.subscribe('/topic/dataUpdate', (message) => {
const newData = JSON.parse(message.body);
appendToTable(newData); // 更新頁面 DOM
});
});
</script>
若不想引入 WebSocket,可用 Spring 的 @Scheduled 定時檢查資料庫變更,配合前端 setInterval 輪詢:
@Component
public class DataChangeDetector {
private Long lastMaxId = 0L;
@Scheduled(fixedRate = 3000) // 每 3 秒檢查一次
public void checkChanges() {
Long currentMaxId = dataRepository.findMaxId();
if (currentMaxId > lastMaxId) {
lastMaxId = currentMaxId;
// 可結合 ApplicationEvent 發布事件,或直接更新快取
}
}
}
前端每隔幾秒請求 /api/latest 取得增量資料並追加渲染。
綜上,WebSocket 方案最適合「即時、雙向、高頻」的同步需求;若頻率較低、單向推送,SSE 或輪詢即可滿足。