如何用Spring Boot+Ajax定时刷新Web页面参数?
解决方案与示例代码
一、基础方案:Ajax定时轮询(快速上手)
ModelAndView是服务端渲染时一次性传递数据,页面加载后无法主动更新,所以需要前端定时请求后端接口获取最新数据。
1. 后端RestController改造
首先把TCP线程获取的数据存到线程安全的容器(比如ConcurrentHashMap)里,再写接口返回这些数据:
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @RestController public class DataController { // 存储TCP线程传来的实时数据,线程安全 private final Map<String, Object> realTimeData = new ConcurrentHashMap<>(); // 供TCP线程调用,更新数据 public void updateData(String key, Object value) { realTimeData.put(key, value); } // 暴露接口给前端获取最新数据 @GetMapping("/api/realtime-data") public Map<String, Object> getRealtimeData() { return realTimeData; } }
注:你的TCP线程需要注入这个DataController,调用updateData方法更新数据。
2. 前端JavaScript实现定时请求
用setInterval每秒发送一次Ajax请求,拿到数据后更新页面表格:
<!-- 页面表格示例 --> <table id="data-table"> <thead> <tr> <th>参数名</th> <th>值</th> </tr> </thead> <tbody id="table-body"></tbody> </table> <script> // 每秒执行一次数据更新 setInterval(() => { fetch('/api/realtime-data') .then(response => response.json()) .then(data => { const tableBody = document.getElementById('table-body'); tableBody.innerHTML = ''; // 遍历数据生成表格行 for (const [key, value] of Object.entries(data)) { const row = document.createElement('tr'); row.innerHTML = `<td>${key}</td><td>${value}</td>`; tableBody.appendChild(row); } }) .catch(error => console.error('获取数据失败:', error)); }, 1000); // 1000毫秒=1秒 </script>
二、进阶方案:WebSocket(服务器主动推送)
如果每秒轮询开销大,WebSocket是更优选择——建立一次长连接,后端有新数据就主动推给前端,无需前端反复请求。
1. 后端WebSocket配置与实现
先添加Spring WebSocket依赖(Maven示例):
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency>
再写WebSocket配置和处理器:
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.handler.TextWebSocketHandler; import org.springframework.web.socket.TextMessage; import com.fasterxml.jackson.databind.ObjectMapper; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; import org.springframework.web.socket.WebSocketSession; @Configuration @EnableWebSocket public class WebSocketConfig implements WebSocketConfigurer { @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { registry.addHandler(new RealTimeDataHandler(), "/ws/realtime").setAllowedOrigins("*"); } } class RealTimeDataHandler extends TextWebSocketHandler { // 存储所有连接的客户端会话 private final CopyOnWriteArrayList<WebSocketSession> sessions = new CopyOnWriteArrayList<>(); private final ObjectMapper objectMapper = new ObjectMapper(); // 线程安全容器存储TCP数据 private final Map<String, Object> realTimeData = new ConcurrentHashMap<>(); // 供TCP线程调用,更新并推送数据 public void updateAndPushData(String key, Object value) { realTimeData.put(key, value); // 推送给所有在线客户端 sessions.forEach(session -> { if (session.isOpen()) { try { String jsonData = objectMapper.writeValueAsString(realTimeData); session.sendMessage(new TextMessage(jsonData)); } catch (Exception e) { e.printStackTrace(); } } }); } @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { sessions.add(session); // 连接建立后立即发送当前数据 String jsonData = objectMapper.writeValueAsString(realTimeData); session.sendMessage(new TextMessage(jsonData)); } @Override public void afterConnectionClosed(WebSocketSession session, org.springframework.web.socket.CloseStatus status) throws Exception { sessions.remove(session); } }
2. 前端WebSocket代码
<table id="data-table"> <thead> <tr> <th>参数名</th> <th>值</th> </tr> </thead> <tbody id="table-body"></tbody> </table> <script> // 建立WebSocket连接 const ws = new WebSocket('ws://' + window.location.host + '/ws/realtime'); // 接收到后端推送的数据时更新页面 ws.onmessage = function(event) { const data = JSON.parse(event.data); const tableBody = document.getElementById('table-body'); tableBody.innerHTML = ''; for (const [key, value] of Object.entries(data)) { const row = document.createElement('tr'); row.innerHTML = `<td>${key}</td><td>${value}</td>`; tableBody.appendChild(row); } }; // 处理连接错误 ws.onerror = function(error) { console.error('WebSocket连接错误:', error); }; </script>
三、适用技术推荐
- 前端框架:如果觉得原生JS操作DOM麻烦,可以用Vue.js或React.js,它们的响应式数据绑定能更轻松地更新页面,无需手动操作DOM。
- Server-Sent Events (SSE):比WebSocket更简单的单向推送方案,适合仅需后端推数据给前端的场景,Spring Boot支持SSE,代码量比WebSocket少。
- Spring Boot Thymeleaf:若坚持用服务端渲染,可结合Thymeleaf和上述Ajax/WebSocket方案,无需放弃现有模板。
内容的提问来源于stack exchange,提问作者Kostas
相关产品推荐
相关产品推荐

