当前位置: 首页 > 知识库问答 >
问题:

使用Jersey SSE触发和输出事件

陈俊誉
2023-03-14

我是泽西岛使用SSE的新手,有以下情况。

我有一个JAXB注释类,它表示Raspberry Pi的I/O并对其起作用(类GpioSymation)。
客户端类通过返回类的XML对象表示的方法getUpdate()访问I/O的状态。

@XmlRootElement
public class GpioRepresentation implements GpioSubject
{

...

    /**
         * Returns an object of this class with the current
         * representation of the I/O states
         * @return this
         */
        public synchronized GpioRepresentation getUpdate() 
        {
            this.getGarageDoorInputState();
            this.getZoneOneFeedback();
            this.getZoneTwoFeedback();
            this.getZoneThreeFeedback();
            this.getGarageDoorRelayState();
            this.getZoneOneRelayState();
            this.getZoneTwoRelayState();
            this.getZoneThreeRelayState();
            return this;
        }
...

}

使用getUpdate()的客户端是HomeResource类,方法getPiStatusStream()。这是一个JAX-RS注释方法,并提供远程客户端服务器发送的事件。目前,该方法如图所示编写,在一个单独的线程中有一个连续循环,用于轮询更新。

@Path("/homeservice")
@RolesAllowed({"ADMIN", "USER"})
@Produces(MediaType.APPLICATION_XML)
@Consumes(MediaType.APPLICATION_XML)
public class HomeResource 
{
    private static final Logger LOGGER = LoggerFactory.getLogger(HomeResource.class);

    private GpioRepresentation piService;

    ...

    /**
         * gets status information on the Raspberry Pi's
         * I/O and returns it to the client on a continuous basis
         * and only if it changes.
         * @return EventOutput 
         */
        @GET
        @Path("/iostatus")
        @Produces(SseFeature.SERVER_SENT_EVENTS)
        public EventOutput getPiStatusStream() 
        {
            final EventOutput eventOutput = new EventOutput();

            new Thread(new Runnable() 
            {
                public void run()
                {

                    try {
                         String gdState = null;
                         String zOneState = null;
                         String zTwoState = null;
                         String zThreeState = null;
                         String gdRState = null;
                         String zOneRState = null;
                         String zTwoRState = null;
                         String zThreeRState = null;
                         String lastgdState = null;
                         String lastzOneState = null;
                         String lastzTwoState = null;
                         String lastzThreeState = null;
                         String lastgdRState = null;
                         String lastzOneRState = null;
                         String lastzTwoRState = null;
                         String lastzThreeRState = null;


                        while(true) {

                            final OutboundEvent.Builder eventBuilder = new OutboundEvent.Builder();

                            final GpioRepresentation iostatus = piService.getUpdate();

                            gdState = piService.getGarageDoorInputState();
                            zOneState = piService.getZoneOneFeedback();
                            zTwoState = piService.getZoneTwoFeedback();
                            zThreeState = piService.getZoneThreeFeedback();
                            gdRState = piService.getGarageDoorRelayState();
                            zOneRState = piService.getZoneOneRelayState();
                            zTwoRState = piService.getZoneTwoRelayState();
                            zThreeRState = piService.getZoneThreeRelayState();

                            if (!(gdState.equals(lastgdState) && zOneState.equals(lastzOneState) && zTwoState.equals(lastzTwoState) && zThreeState.equals(lastzThreeState)
                                    && gdRState.equals(lastgdRState) && zOneRState.equals(lastzOneRState) && zTwoRState.equals(lastzTwoRState) && zThreeRState.equals(lastzThreeRState)))
                            {
                                OutboundEvent event = eventBuilder.data(GpioRepresentation.class, iostatus)
                                        .mediaType(MediaType.APPLICATION_XML_TYPE)
                                        .build();

                                eventOutput.write(event);

                                lastgdState = gdState;
                                lastzOneState = zOneState;
                                lastzTwoState = zTwoState;
                                lastzThreeState = zThreeState;
                                lastgdRState = gdRState;
                                lastzOneRState = zOneRState;
                                lastzTwoRState = zTwoRState;
                                lastzThreeRState = zThreeRState;

                            }

                            Thread.sleep(100);
                        }
                    } 
                    catch (Exception exeption) 
                        {
                            System.err.println("Error: " + exeption);
                        } 
                    finally 
                        {
                            try 
                                {
                                    eventOutput.close();
                                } 
                            catch (IOException ioClose) 
                                {
                                    throw new RuntimeException("Error when closing the event output.", ioClose);
                                }
                        }
                    }
            }).start();

            return eventOutput;
        }

        ...

}

我所看到的问题是,这不能很好地扩展。为来自远程客户端的每个GET创建线程需要时间,并且占用CPU资源。此外,我认为这不是一个优雅的解决方案。我想做的是将事件代码封装到一个单独的类中,并使用某种可以触发事件创建的观察者模式。。。。但是,如何将其绑定到资源方法中,以便将其返回到远程客户端?

有没有人能给我举一些例子,或者提供一些关于设计解决方案的建议?

共有1个答案

景英杰
2023-03-14

解决方案是利用SSEEbroadcaster类。我让HomeService类成为GpioRepresentation类的观察者,然后调用一个新方法(broadcastIOUpdateMessage()),然后将我的事件输出到远程客户端。

public void broadcastIOUpdateMessage()
{
    GpioRepresentation iostatus = piService.getUpdate();
    OutboundEvent.Builder eventBuilder = new OutboundEvent.Builder();
    OutboundEvent event = eventBuilder.data(GpioRepresentation.class, iostatus)
            .mediaType(MediaType.APPLICATION_XML_TYPE)
            .build();

    broadcaster.broadcast(event);
}

@GET
@Path("/iostatus")
@Produces(SseFeature.SERVER_SENT_EVENTS)
public EventOutput getPiStatusStream() 
{
    final EventOutput eventOutput = new EventOutput();
    this.broadcaster.add(eventOutput);
    return eventOutput;
}
 类似资料:
  • 我正在寻找合适的资源/教程,可以帮助我开发和部署事件网格触发器,该触发器将等待图像上传到blob容器,使用python处理该图像,然后将结果保存在另一个blob容器中。我发现了许多单独的文档,它们不一定在逻辑上指导我使用Azure Portal和VSCode进行开发和部署,就像从头到尾的一步一步的演练,介绍了实现这一点的所有步骤。 任何指导将不胜感激。

  • 当我的函数方法签名如下时,我有一个成功触发的v3 WebJob: 然而,当我添加一个输出blob时,BlobTrigger永远不会触发。 下面的文档如下:https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-storage-blob#output

  • 问题内容: 有人知道像使用jQuery的触发函数一样可以触发Prototype中的事件的方法吗? 我已经使用watch方法绑定了一个事件监听器,但是我也希望能够以编程方式触发该事件。 提前致谢 问题答案: 符合您的需求。 我已经使用了几次,它就像一个魅力。它允许您 手动触发本机事件 ,例如单击或悬停,如下所示: 这样做的好处是,所有附加的事件处理程序仍将执行,就像您自己单击该元素一样。 对于 自定

  • 问题内容: 我正在使用哈希链接的事件将a 作为弹出窗口打开。但是 ,单击中键不会触发事件,而只会获取链接的属性值并将URL加载到新页面中。如何使用中键打开弹出窗口? 问题答案: beggs的答案是正确的,但是听起来您想阻止默认的中间点击操作。在这种情况下,请包括以下内容 preventDefault()将停止事件的默认操作。

  • 问题内容: 我的整个项目都使用(Bluebird)Promises,但是有一个使用EventEmitter的特定库。 我想要实现以下目标: 我在Promises链中读了EventEmitter的答案。这给了我一种执行’connect’事件的回调的方法。这是我到目前为止所到之处 现在如何进一步链接“ eventB”? 问题答案: 我假设您想为每个事件做不同的事情。即使由的动作触发,您也可以将其视为另

  • 我想自动化一个在线游戏。它在仅基于终端的情况下工作。但是我想添加一个JavaFXUI,现在我不知道把Thread放在哪里。等待直到达到某个LocalDateTime。JavaFX在哪里等待它的事件(比如按钮点击,…),我可以覆盖该方法吗?或者有没有一种方法可以为javaFX创建自定义LocalDateTime事件和侦听器? 如果在initialize()中添加一个Thread.wait,则整个场景