You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 19:12:48