Spring Boot+AngularJS+Thymeleaf环境下继电器调度触发的前端实时更新咨询
Hey there! Let's figure out how to show real-time relay status updates on your frontend without page refreshes, given your Spring Boot + AngularJS + Thymeleaf stack. Here are three practical approaches tailored to your setup:
1. Polling (Simplest Quick Win)
This is the easiest to implement, great if you don't need sub-second updates. We'll have AngularJS periodically fetch the latest status from a Spring Boot REST endpoint.
Backend (Spring Boot)
Create a REST endpoint that returns the current relay status:
@RestController @RequestMapping("/api/relay") public class RelayStatusController { @Autowired private RelayService relayService; // Your service to track relay state @GetMapping("/status") public ResponseEntity<RelayStatus> getCurrentStatus() { RelayStatus status = relayService.getCurrentStatus(); return ResponseEntity.ok(status); } } // DTO for status public class RelayStatus { private boolean active; private LocalDateTime lastTriggered; // Getters/setters }
Frontend (AngularJS + Thymeleaf)
Use $interval to poll the endpoint, and use Thymeleaf to populate the initial state on page load:
<div ng-controller="RelayController"> <div class="relay-status" ng-class="{ 'active': relayStatus.active, 'flash': statusUpdated }"> <h3>Relay Status: <span ng-if="relayStatus.active">*ACTIVE*</span> <span ng-if="!relayStatus.active">INACTIVE</span> </h3> <p>Last Triggered: {{ relayStatus.lastTriggered | date:'medium' }}</p> </div> </div>
angular.module('relayApp').controller('RelayController', function($scope, $http, $interval) { // Populate initial status with Thymeleaf $scope.relayStatus = /*[[${initialRelayStatus}]]*/ {}; $scope.statusUpdated = false; // Poll every 2 seconds (adjust based on your needs) const poller = $interval(() => { $http.get('/api/relay/status') .then(response => { // Only update if status changed to avoid unnecessary DOM work if ($scope.relayStatus.active !== response.data.active) { $scope.relayStatus = response.data; $scope.statusUpdated = true; // Reset flash after 2 seconds setTimeout(() => $scope.$apply(() => $scope.statusUpdated = false), 2000); } }) .catch(error => console.error('Failed to fetch status:', error)); }, 2000); // Clean up poller when controller is destroyed $scope.$on('$destroy', () => { if (angular.isDefined(poller)) { $interval.cancel(poller); } }); });
2. Server-Sent Events (SSE) - Efficient Push Updates
SSE lets the server push status updates to the frontend in real-time, no polling needed. Perfect for when you want instant updates when the scheduler triggers an action.
Backend (Spring Boot)
Create an SSE endpoint that broadcasts status changes:
@RestController @RequestMapping("/api/relay") public class RelaySseController { private final List<SseEmitter> emitters = new CopyOnWriteArrayList<>(); @Autowired private RelayService relayService; @GetMapping(value = "/status-stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE) public SseEmitter streamStatus() { SseEmitter emitter = new SseEmitter(Long.MAX_VALUE); emitters.add(emitter); // Send initial status immediately try { emitter.send(SseEmitter.event().data(relayService.getCurrentStatus())); } catch (IOException e) { emitters.remove(emitter); } // Clean up inactive emitters emitter.onCompletion(() => emitters.remove(emitter)); emitter.onTimeout(() => emitters.remove(emitter)); return emitter; } // Call this method when your scheduler triggers a relay action public void broadcastStatusUpdate(RelayStatus newStatus) { Iterator<SseEmitter> iterator = emitters.iterator(); while (iterator.hasNext()) { SseEmitter emitter = iterator.next(); try { emitter.send(SseEmitter.event() .name("status-update") .data(newStatus)); } catch (IOException e) { iterator.remove(); } } } }
Frontend (AngularJS)
Listen for SSE events and update the view:
angular.module('relayApp').controller('RelayController', function($scope) { $scope.relayStatus = /*[[${initialRelayStatus}]]*/ {}; $scope.statusUpdated = false; // Connect to the SSE stream const eventSource = new EventSource('/api/relay/status-stream'); // Listen for status update events eventSource.addEventListener('status-update', event => { $scope.$apply(() => { $scope.relayStatus = JSON.parse(event.data); $scope.statusUpdated = true; setTimeout(() => $scope.$apply(() => $scope.statusUpdated = false), 2000); }); }); // Clean up when controller is destroyed $scope.$on('$destroy', () => eventSource.close()); });
3. WebSocket - Full Duplex Communication
Use WebSockets if you need two-way communication (e.g., manual user triggers + scheduler updates). Spring Boot supports STOMP over WebSockets seamlessly.
Backend (Spring Boot)
First add the WebSocket starter dependency:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency>
Configure WebSocket and create a controller to send updates:
@Configuration @EnableWebSocketMessageBroker public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { @Override public void configureMessageBroker(MessageBrokerRegistry config) { config.enableSimpleBroker("/topic"); config.setApplicationDestinationPrefixes("/app"); } @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/relay-websocket").withSockJS(); } } @Controller public class RelayWebSocketController { @Autowired private SimpMessagingTemplate messagingTemplate; // Call this when scheduler triggers a relay action public void sendStatusUpdate(RelayStatus newStatus) { messagingTemplate.convertAndSend("/topic/relay-status", newStatus); } }
Frontend (AngularJS)
Use SockJS and STOMP to connect and subscribe to updates:
angular.module('relayApp').controller('RelayController', function($scope) { $scope.relayStatus = /*[[${initialRelayStatus}]]*/ {}; $scope.statusUpdated = false; // Connect to WebSocket const socket = new SockJS('/relay-websocket'); const stompClient = Stomp.over(socket); stompClient.connect({}, frame => { // Subscribe to status updates stompClient.subscribe('/topic/relay-status', message => { $scope.$apply(() => { $scope.relayStatus = JSON.parse(message.body); $scope.statusUpdated = true; setTimeout(() => $scope.$apply(() => $scope.statusUpdated = false), 2000); }); }); }); // Clean up when controller is destroyed $scope.$on('$destroy', () => { if (stompClient != null) { stompClient.disconnect(); } }); });
Which Approach to Choose?
- Polling: Best for small-scale apps where you don't need instant updates.
- SSE: Ideal for one-way real-time updates (scheduler → frontend) with minimal setup.
- WebSocket: Perfect if you need two-way communication (user triggers + scheduler updates).
内容的提问来源于stack exchange,提问作者Gerhard van Zyl

