Событие на стороне сервера не запускается в Джерси 2.8 с использованием SSE

Я пытаюсь использовать пример, приведенный в официальной документации Jersey SSE.

См. « 14.5.2. Асинхронная обработка SSE с EventSource » по ссылке ниже https://jersey.github.io/documentation/2.8/user-guide.html#example-simple-sse

Мой код, как показано ниже

Код клиента -

  public class ClientSSEEventManager {
        public void WaitForEvents() {
            // Client client = ClientBuilder.newBuilder()
            // .register(SseFeature.class).build();
            // WebTarget target =
            // client.target("http://localhost:8080/server/events");
            //
            // EventInput eventInput = target.request().get(EventInput.class);
            // while (!eventInput.isClosed()) {
            // final InboundEvent inboundEvent = eventInput.read();
            // if (inboundEvent == null) {
            // // connection has been closed
            // break;
            // }
            // System.out.println(inboundEvent.getName() + "; "
            // + inboundEvent.readData(String.class));
            // }

            Client client = ClientBuilder.newBuilder().register(SseFeature.class)
                    .build();
            WebTarget target = client.target("http://localhost:8080/server/events");
            EventSource eventSource = EventSource.target(target).build();
            EventListener listener = new EventListener() {
                @Override
                public void onEvent(InboundEvent inboundEvent) {
                    System.out.println(inboundEvent.getName() + "; "
                            + inboundEvent.readData(String.class));
                }
            };
            eventSource.register(listener, "message-to-client");
            eventSource.open();
        }
    }

public class MyApplication extends ResourceConfig {
    public MyApplication(){
     super(ClientSSEEventManager.class, SseFeature.class);
    }
//   Set<Class<?>> classes = new HashSet<Class<?>>() {
//          /**
//       * 
//       */
//      private static final long serialVersionUID = 1L;
//
//          { add(ClientSSEEventManager.class);
//          }};
//
//      @Override
//      public Set<Class<?>> getClasses() {
//          return classes;
//      }

}

Затем в одном из методов действия я просто инициализирую прослушивание события следующим образом.

//Start listening to event from server
     ClientSSEEventManager clientSSEEventManager = new                      ClientSSEEventManager();
clientSSEEventManager.WaitForEvents();
///

Клиентский Web.xml имеет следующие параметры инициализации:

<init-param>
    <param-name>javax.ws.rs.Application</param-name>
    <param-value>com.framework.MyApplication</param-value>
</init-param>

Код сервера -

@Path("events")
public class ServerSSEServerEventManager {
    @GET
    @Produces(SseFeature.SERVER_SENT_EVENTS)
    public EventOutput getNotificationEvents(){
         final EventOutput eventOutput = new EventOutput();
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        for (int i = 0; i < 10; i++) {
                            // ... code that waits 1 second
                            final OutboundEvent.Builder eventBuilder
                            = new OutboundEvent.Builder();
                            eventBuilder.name("message-to-client");
                            eventBuilder.data(String.class,
                                "Hello world " + i + "!");
                            final OutboundEvent event = eventBuilder.build();
                            eventOutput.write(event);
                        }
                    } catch (IOException e) {
                        throw new RuntimeException(
                            "Error when writing the event.", e);
                    } finally {
                        try {
                            eventOutput.close();
                        } catch (IOException ioClose) {
                            throw new RuntimeException(
                                "Error when closing the event output.", ioClose);
                        }
                    }
                }
            }).start();
            return eventOutput;
    }
}

Ожидаемый результат на стороне клиента выглядит следующим образом

message-to-client; Hello world 0!
message-to-client; Hello world 1!
message-to-client; Hello world 2!
message-to-client; Hello world 3!
message-to-client; Hello world 4!
message-to-client; Hello world 5!
message-to-client; Hello world 6!
message-to-client; Hello world 7!
message-to-client; Hello world 8!
message-to-client; Hello world 9!

Но на стороне клиента ничего не печатается. Я что-то пропустил здесь? У меня есть сомнения, client.Target должен иметь "http://:8080/server/events"? ИЛИ это должно быть просто "http://:8080/events"


person Sadanand    schedule 15.05.2014    source источник
comment
URL вашего сервера зависит от Context Path вашего приложения. Если вы развертываете как server, ваш путь должен быть http://localhost:8080/server/events. Я бы добавил некоторые журналы на стороне вашего сервера и добавил фильтр регистрации Джексона к вашему клиенту client.register(new LoggingFilter(LOG, true));, чтобы вы могли видеть, что ваш клиент отправляет/получает.   -  person Baldy    schedule 15.05.2014
comment
Если я открою URL-адрес непосредственно в браузере, например http://‹serverip:8080›/server/events, тогда будет вызван метод getNotificationEvents на стороне сервера. но то же самое, если я сделаю это, запустив клиентское приложение, как показано в приведенном выше коде, getNotificationEvents на стороне сервера не вызывается.   -  person Sadanand    schedule 18.05.2014
comment
Хорошо, глядя на ваш клиентский код, вы настраиваете обработчик событий, но никогда не отправляете свой запрос GET.   -  person Baldy    schedule 18.05.2014
comment
@Baldy, когда мы открываем соединение, разве это не что иное, как отправка запроса GET? не могли бы вы обновить мне фрагмент кода о том, какие изменения я должен сделать ??   -  person Sadanand    schedule 18.05.2014
comment
Также в приведенном выше примере сервер немедленно отвечает клиенту, но на самом деле сервер должен отправлять событие всякий раз, когда что-то изменяется на стороне сервера. так как сервер может подтолкнуть событие? где и какой код я должен добавить для этого?   -  person Sadanand    schedule 18.05.2014
comment
привет @Sadanand ты когда-нибудь находил ответ на этот вопрос? у меня возникают проблемы, подобные описанным здесь получение чего-либо из потока сервера"> stackoverflow.com/questions/30917568/   -  person a.hrdie    schedule 18.06.2015


Ответы (1)


Наконец-то SSE заработал нормально для меня. есть пара вещей, которые нам нужно сделать

  1. Прослушиватель SSE в Springs

      @Singleton
         @Path("/events")
         public class NotificationHandler {
             @Path("/register/{userName}")
         @Produces(SseFeature.SERVER_SENT_EVENTS)
         @GET
         public @ResponseBody EventOutput registerForAnEventSummary(
                @PathParam("userName") String userName) {
            }
         }
    
  2. Вызов службы, которая делает вызов, чтобы уведомить всех клиентов

     PostMethod postMethod = null;
            postMethod = new PostMethod(
                    resourceBundle.getString("localhost:8080")
                            + resourceBundle.getString("applicationnotifier")
                            + resourceBundle
                                    .getString("sse/events/broadcast/"));
    
  3. Вещатель

     @Path("/broadcast")
        @POST
         @Produces(MediaType.TEXT_PLAIN)
         @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
        public String broadcastNotifications(@FormParam("message") String message) { }
    
  4. Javascript - слушайте все события SSE, зарегистрировавшись

     var notificationBaseURL =  ""; //The URL Where your services are hosted
     function listenAllEvents() {
         if ( (EventSource) !== "undefined") {
    
        var source = new EventSource(
        notificationBaseURL+"applicationnotifier/sse/events/register/"+loggedInUserName);
        source.onmessage = notifyEvent;
    } else {
        console.log("Sorry no event data sent - ");
        }
     }
    
     function notifyEvent(event) {
        var responseJson = JSON.parse(event.data);
        alert("... Notification Received ...");
     }
    
person Sadanand    schedule 19.06.2015