Spring Boot向AngularJS 1.4推送STOMP事件异常问题求助
Hey there! Let's work through why your Spring Boot server isn't pushing STOMP messages to your AngularJS 1.4 client, even though the connection and subscription seem to work. I'll also walk you through the correct setup for both sides.
Common Troubleshooting Steps First
Before diving into full implementations, let's rule out the most common issues:
- Destination Path Mismatch: Double-check that the topic/queue path your server sends messages to exactly matches what your client subscribes to (case sensitivity and slashes matter!).
- Spring Container Context Issue: If you're manually instantiating your service class (instead of letting Spring manage it), the
SimpMessagingTemplatewon't have access to the WebSocket context—always use constructor injection for this bean. - Broker Configuration: Ensure your Spring WebSocket config enables the message broker for the paths you're using (e.g.,
/topicor/queue). - Security Blocking: If you're using Spring Security, verify that it allows STOMP messages to your target destinations (add rules for
"/topic/**"or your specific path). - Angular Digest Cycle: STOMP callbacks run outside Angular's digest loop—you need to use
$scope.$apply()to update the UI with incoming messages.
Correct Spring Boot STOMP Implementation
1. WebSocket Configuration
First, set up the WebSocket message broker:
@Configuration @EnableWebSocketMessageBroker public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { @Override public void configureMessageBroker(MessageBrokerRegistry config) { // Enable simple in-memory broker for topic/queue destinations config.enableSimpleBroker("/topic", "/queue"); // Prefix for messages sent from client to server-side controllers config.setApplicationDestinationPrefixes("/app"); } @Override public void registerStompEndpoints(StompEndpointRegistry registry) { // Register the STOMP endpoint with SockJS fallback (for older browsers) registry.addEndpoint("/ws-stomp") .setAllowedOriginPatterns("*") // Adjust CORS as needed for your environment .withSockJS(); } }
2. Service to Process Files & Send Notifications
Use SimpMessagingTemplate (injected by Spring) to send messages once file processing completes:
@Service public class FileProcessingService { private final SimpMessagingTemplate messagingTemplate; // Constructor injection ensures we get the Spring-managed template instance public FileProcessingService(SimpMessagingTemplate messagingTemplate) { this.messagingTemplate = messagingTemplate; } public void processFileList(List<File> files) { // Run file processing asynchronously to avoid blocking the HTTP request CompletableFuture.runAsync(() -> { try { // Your actual file processing logic here Thread.sleep(3000); // Simulate processing time // Send completion notification to the target topic String notification = "文件列表已处理完成,以下为结果文件"; messagingTemplate.convertAndSend("/topic/file-process-complete", notification); // Optional: Send result file details if needed // messagingTemplate.convertAndSend("/topic/file-process-complete", resultFileData); } catch (InterruptedException e) { Thread.currentThread().interrupt(); // Send error notification if processing fails messagingTemplate.convertAndSend("/topic/file-process-error", "文件处理被中断"); } }); } }
3. REST Controller to Trigger Processing
Expose a REST endpoint to start the file processing:
@RestController @RequestMapping("/api/files") public class FileController { private final FileProcessingService fileProcessingService; public FileController(FileProcessingService fileProcessingService) { this.fileProcessingService = fileProcessingService; } @PostMapping("/process") public ResponseEntity<String> triggerProcessing(@RequestBody List<File> files) { fileProcessingService.processFileList(files); return ResponseEntity.ok("文件处理已启动,完成后将收到通知"); } }
AngularJS 1.4 Client Setup
Make sure you have sockjs.min.js and stomp.min.js included in your project (use local copies, not external links). Then set up the client:
angular.module('fileProcessingApp', []) .controller('FileCtrl', function($scope, $http) { var stompClient = null; // Initialize STOMP connection function connect() { var socket = new SockJS('/ws-stomp'); stompClient = Stomp.over(socket); stompClient.connect({}, function(frame) { console.log('Connected to STOMP: ' + frame); // Subscribe to the completion notification topic stompClient.subscribe('/topic/file-process-complete', function(message) { // Wrap the update in $scope.$apply() to trigger Angular's digest loop $scope.$apply(function() { $scope.notification = message.body; // Add logic here to display result files }); }); // Optional: Subscribe to error notifications stompClient.subscribe('/topic/file-process-error', function(errorMsg) { $scope.$apply(function() { $scope.error = errorMsg.body; }); }); }, function(error) { console.error('STOMP connection failed: ' + error); // Reconnect on failure (optional) setTimeout(connect, 5000); }); } // Trigger file processing via REST API $scope.startProcessing = function() { $http.post('/api/files/process', $scope.fileList) .then(function(response) { console.log(response.data); }) .catch(function(error) { console.error('Failed to start processing: ' + error); }); }; // Start connection on controller load connect(); });
Key Takeaways
- Path Consistency: The topic path used in
messagingTemplate.convertAndSend()must exactly match what the client subscribes to. - Spring Managed Beans: Never manually create instances of services that use
SimpMessagingTemplate—let Spring handle injection. - Angular Digest Loop: Always wrap STOMP callback logic in
$scope.$apply()to update the UI. - Async Processing: Run file processing in a separate thread to avoid blocking the HTTP request thread.
内容的提问来源于stack exchange,提问作者Dharita Chokshi
相关产品推荐
相关产品推荐

