【问题标题】:Angular 2 spring boot server side eventsAngular 2 Spring Boot 服务器端事件
【发布时间】:2017-04-20 15:09:24
【问题描述】:

有人可以为我提供一个 Spring Boot 服务器端事件的示例吗?

基本上我需要将服务器端事件推送到浏览器。我正在使用 angular 2 和 spring boot 后端。 请提供 1 个示例,我找不到好的示例。

@Controller
public class SSEController {

    private final List<SseEmitter> emitters = new ArrayList<>();

    @RequestMapping(path = "/stream", method = RequestMethod.GET)
    public SseEmitter stream() throws IOException {

        SseEmitter emitter = new SseEmitter();

        emitters.add(emitter);
        emitter.onCompletion(() -> emitters.remove(emitter));

        return emitter;
    }
}

如何从服务器连续推送数据以及如何在Angular 2中订阅这个事件?

【问题讨论】:

    标签: java angular events spring-boot server-sent-events


    【解决方案1】:

    有一个 Spring Rest 控制器

    SseController.java

    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
    
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;
    
    @RestController
    public class SSEController {
    
        public static final List<SseEmitter> emitters = Collections.synchronizedList( new ArrayList<>());
    
        @RequestMapping(path = "/stream", method = RequestMethod.GET)
        public SseEmitter stream() throws IOException {
    
            SseEmitter emitter = new SseEmitter();
    
            emitters.add(emitter);
            emitter.onCompletion(() -> emitters.remove(emitter));
    
            return emitter;
        }
    }
    

    ServiceClass.java

    public void sendSseEventsToUI(Notification notification) { //your model class
            List<SseEmitter> sseEmitterListToRemove = new ArrayList<>();
            SSEController.emitters.forEach((SseEmitter emitter) -> {
                try {
                    emitter.send(notification, MediaType.APPLICATION_JSON);
                } catch (IOException e) {
                    emitter.complete();
                    sseEmitterListToRemove.add(emitter);
                    e.printStackTrace();
                }
            });
            SSEController.emitters.removeAll(sseEmitterListToRemove);
        }
    

    最终在 Angular2 组件中执行此操作

    notification.component.ts

    import {Component, OnInit} from '@angular/core';
    
    declare let EventSource:any;
    
    @Component({
        selector: 'notification-cmp',
        templateUrl: 'notification.component.html'  
    })
    
    export class NotificationComponent implements OnInit {
       connect(): void {
            let source = new EventSource('http://localhost:8080/stream');
            source.addEventListener('message', message => {
                let n: Notification; //need to have this Notification model class in angular2
                n = JSON.parse(message.data);
                console.log(message.data); 
            });
        }
    }
    

    【讨论】:

    • 您有任何工作示例吗,我正面临使用 rabbitMq 使用基于 queue 的机制进行繁重操作的问题。现在,当消费者完成消费消息时,我想将事件发送到 UI。我找不到创建可以自动装配和发送事件的 serviceImpl 或 serviceComponent 的方法
    • @NagendraSingh 您可以为此发布一个新问题。不清楚你在期待什么
    【解决方案2】:

    上面的答案很有帮助。

    还有..

    接收实际推送的数据..

    代码应该是

    source.onmessage = (message)=>{
       let n:Notification = JSON.parse(message.data);
    }
    
    
    source.addEventListener('message', message => {
    // There is no data property available on 'message' here
       let n: Notification; 
       n = JSON.parse(message.data);
       console.log(message.data); 
    });
    

    【讨论】:

      【解决方案3】:

      Answer from Pratap A.K 很棒。但是为了让它更干净一点,你应该创建一个实现接口的 NotificationService。像这样:

      NotificationServiceImpl.java

      public class NotificationServiceImpl implements NotificationService {
      
      public static final List<SseEmitter> emitters = Collections.synchronizedList(new ArrayList<>());
      
      @Override
      public SseEmitter initSseEmitters() {
      
          SseEmitter emitter = new SseEmitter();
          emitters.add(emitter);
          emitter.onCompletion(() -> emitters.remove(emitter));
      
          return emitter;
      }
      
      @Override
      public void sendSseEventsToUI(WebSource notification) {
          List<SseEmitter> sseEmitterListToRemove = new ArrayList<>();
          this.emitters.forEach((SseEmitter emitter) -> {
              try {
                  emitter.send(notification, MediaType.APPLICATION_JSON);
              } catch (IOException e) {
                  emitter.complete();
                  sseEmitterListToRemove.add(emitter);
                  e.printStackTrace();
              }
          });
          this.emitters.removeAll(sseEmitterListToRemove);
        }
      }
      

      NotificationService.java

      public interface NotificationService {
      
      public SseEmitter initSseEmitters();
      public void sendSseEventsToUI(WebSource notification);
      
      }
      

      SSEController.java

      @RestController
      @RequestMapping("/mystream")
      public class SSEController {
      
      @Autowired
      NotificationServiceImpl INotificationServiceImpl;
      
      @CrossOrigin
      @RequestMapping(path = "/streamsource", method = RequestMethod.GET)
      public SseEmitter stream() throws IOException {
      
          return INotificationServiceImpl.initSseEmitters();
        }
      }
      

      【讨论】:

      • 应该在哪里调用sendSSeEvetnsToUI?使用此代码如果我调用/streamsource 控制器,则什么也没有发生!如何创建消息以发送它?能解释清楚一点吗?
      【解决方案4】:

      现在使用 Spring Webflux 更容易完成该任务,只需使用以下媒体类型:

          @GetMapping(value = "/queue/events", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
          public Flux<EventNotification> streamEvents() {
              return managerService.streamEvents();
          }
      

      因此您可以创建如下架构:

      您还可以通过 RSocket 示例检查 https://github.com/htenjo/vqueue 中的工作实现。

      【讨论】:

        猜你喜欢
        • 2018-02-09
        • 1970-01-01
        • 1970-01-01
        • 2018-02-03
        • 1970-01-01
        • 2018-09-18
        • 2019-01-26
        • 2020-10-04
        • 1970-01-01
        相关资源
        最近更新 更多