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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 06:44:28