Предоставление веб-приложению обновлений в реальном времени для объектов домена из серверной части Spring.

На стороне сервера я использую Spring 4. На стороне браузера я использую Ember.js.

В моем приложении есть классы сущностей, такие как Person и Product. Эти объекты используются как на сервере, так и в браузере и моделируются одинаково. Например:

//this is on the server side

public interface Person {    
    String getId();

    String getFirstName();
    void setFirstName(String firstName);

    String getLastName();
    void setLastName(String lastName);
}
//this is on the browser side, modeled with Ember Data

App.Person = DS.Model.extend({
    // id: DS.attr("string"), //property 'id' will be provided by Ember automatically
    firstName: DS.attr("string"),
    lastName: DS.attr("string")
});

У меня есть требование синхронизировать объекты между сервером и браузером. Так, например, когда свойство firstName Person изменяется на стороне сервера, это изменение должно быть передано всем заинтересованным браузерам в режиме реального времени.

Я исследовал поддержку Spring WebSocket и освоившись с примером Spring "Hello WebSocket", я убедился, что с помощью этого технология является правильным подходом для моего требования.

Поскольку WebSocket/STOMP является довольно низкоуровневым, я ищу решение, основанное на этой технологии и обеспечивающее поведение, подобное шаблону наблюдателя, между браузером (роль сущностей здесь будет наблюдатель). и сервер (роль сущностей здесь будет subject/observable).

Поскольку я не смог найти существующее решение этой проблемы «сохранения синхронизации объектов» (ни решения в Spring, ни в какой-либо сторонней библиотеке), я хочу создать свое собственное решение, но дизайн уже вызывает интересные вопросы. , такие как:

  • Как должен выглядеть протокол? После того, как произошло изменение, должен ли сервер отправить минимальный кадр, включающий только тип объекта и его идентификатор? (например, после изменения любого свойства Person с идентификатором "3" отправьте {"type": "Person", "id": "3"} всем заинтересованным клиентам)
  • Существуют ли реальные ограничения на количество сущностей, на которые можно подписаться? Во время сеанса один браузер может контактировать с сотнями Product.

Мне интересно узнать, какие решения успешно синхронизируют объекты сервера на основе Spring с прокси-объектами клиента JavaScript (не обязательно Ember.js).


person Abdull    schedule 12.06.2014    source источник


Ответы (1)


Я собираюсь дать вам общий обзор, потому что для предоставления всех подробностей требуется сообщение в блоге.

Что вам понадобится

  • сервер Socket.io.
  • Клиент Socket.io или одна из их новых библиотек, которая отправляет события в Redis. клиент Ruby Socket.io, Java-клиент Socket.io
  • Перехватывает все ваши изоляторы данных на стороне сервера, чтобы получать уведомления об обновлениях.
  • Observer для всех ваших моделей Ember Data.

У вас есть два варианта протокола

Вариант первый: только событие

Полезная нагрузка:

{
  meta: {
    type: 'NAME_OF_YOUR_MODEL'
    id:   'ID_OF_UPDATED_MODEL'
  }
}

Код:

window.socket = io()

App.ApplicationRoute = Ember.Route.extend({
  activate: function(){
    var store = this.store;

    socket.on('recordUpdated', function(payload){
      store.find(Ember.get(payload, 'meta.type'), Ember.get(payload, 'meta.id'));
    };
  }
}

App.Model = DS.Model.extend({
  lastUpdate: function(){
    var payload = {
      id: this.get('id'),
      type: this.constructor.toString()
    };

    socket.emit('recordUpdated', payload);

    this.save(); // You should save the record to get it in saved state.

    return payload;
  }.observes('isDirty') 
});

Вариант второй: представление модели в формате JSON с событием

Полезная нагрузка:

{
  "meta": {
    "type": "person"
    "id": "18"
  },

  "persons": [
    {"id": "18", "firstName": "Yahuda", "lastName": "Katz"}
  ]
}

Код:

window.socket = io();

App.ApplicationRoute = Ember.Route.extend({
  activate: function(){
    var store = this.store;

    socket.on('recordUpdated', function(payload){
      store.pushPayload(payload);
    };
  }
});

App.Model = DS.Model.extend({
  lastUpdate: function(){
    var payload = this.toJSON();

    socket.emit('recordUpdated', payload);

    this.save();

    return payload;
  }.observes('isDirty') 
});

Примечания

Вы можете использовать Stalkable для лучшего наблюдения за всеми свойствами. Это также избавляет от необходимости вызывать save как часть свойства lastUpdate.

person Pooyan Khosravi    schedule 16.06.2014
comment
op не хочет переключаться на socket.io, а использует свою существующую инфраструктуру на основе spring и веб-сокетов. заглянуть в stompjs - person arisalexis; 23.07.2015