Как упоминалось в предыдущих статьях, в следующий выпуск JavaServer Faces (Mojarra) добавлен ряд улучшений. JSF 2.3 планируется к выпуску с Java EE 8 в 2017 году, но вы можете получить некоторые из усовершенствований и обновлений JSF для тестирования уже сейчас, собрав исходные коды или выполнив этапный выпуск.
Одним из таких усовершенствований API является добавление односторонней (сервер-клиент) push-связи на основе f:websocket тег f:websocket и Push API. Команда OmniFaces разработала решение JSF на основе o: socket , которое является частью служебной библиотеки OmniFaces. В частности, члены экспертной группы JSR 372 Бауке Шольц и Арджан Тиймс внесли это и многие другие улучшения и исправления в кодовую базу Mojarra.
Патч, который включает поддержку f:websocket еще не был применен к ветке Mojarra 2.3, но вы можете получить патч из выпуска JAVASERVERFACES_SPEC_PUBLIC-1396 . Прежде чем применять патч к вашему локальному клону Mojarra, вы должны обязательно обновить свои источники из центральной ветки 2.3, чтобы убедиться, что у вас установлены последние обновления. Использование простое, очень похоже на хорошо документированную функцию o:socket на сайте OmniFaces, выполните следующие шаги, чтобы использовать f:websocket .
Сначала добавьте
|
1
|
javax.faces.ENABLE_WEBSOCKET_ENDPOINT |
параметр context для web.xml вашего приложения и установите значение true.
|
1
2
3
4
|
<context-param> <param-name>javax.faces.ENABLE_WEBSOCKET_ENDPOINT</param-name> <param-value>true</param-value> </context-param> |
Код на стороне клиента
На вашем клиенте (представление JSF) добавьте тег f:websocket и укажите канал, к которому вы хотите подключиться. Необходимо также указать прослушиватель onmessage который будет выполнять указанную функцию JavaScript после получения сообщения. Также может быть указан необязательный атрибут onclose , позволяющий указанной функции JavaScript выполняться при закрытии соединения. В следующем примере мы указываем, что сокет будет подключаться к каналу с именем «duke» вместе с прослушивателем dukeSocketListener именем dukeSocketListener :
|
1
|
<f:websocket channel="duke" onmessage="dukeMessageListener"/> |
Слушатель onmessage может быть вызван с тремя параметрами (объект JSON push-сообщения, имя канала, событие сообщения). Если вы просто хотите передать сообщение, оно может выглядеть примерно так:
|
1
2
3
|
function dukeMessageListener(message) { PF('broadcastGrowl').show(message);} |
Если onclose дополнительный прослушиватель onclose , соответствующая функция может принимать три параметра (код причины закрытия — целое число, имя канала, событие сообщения), но требуется только первый.
В большинстве случаев предполагается отправить сообщение с сервера, чтобы уведомить все клиентские представления, имеющие одинаковую websocket канала websocket . В f:websocket есть необязательный атрибут области f:websocket , для которого можно установить значение «сессия», и это ограничит сообщения всеми представлениями клиентов с одним и тем же каналом веб-сокета только в текущем сеансе.
Наконец, необязательный атрибут port может быть установлен для указания номера порта TCP, отличного от порта HTTP, если это необходимо.
Код на стороне сервера
Поскольку мы планируем отправить сообщение с сервера всем подключенным клиентам, давайте посмотрим на код на стороне сервера. Новый PushContext может быть PushContext в любой артефакт CDI путем включения аннотации @Push , и имя контекста может либо соответствовать имени канала, либо необязательный атрибут channel может быть указан в аннотации @Push для указания канала, к которому сообщение должно быть передано.
|
1
2
3
4
5
6
|
@Inject @Push private PushContext duke;...public void sendMessage(Object message){ duke.send(message);} |
Сообщение будет закодировано как JSON и доставлено в аргумент сообщения функции JavaScript на клиенте, который указан для атрибута onmessage в f:websocket . В качестве сообщения можно отправить любой тип контейнера, будь то обычный String, JavaBean, Map, Collection и т. Д.
Пример использования
Предположим, что у нас есть административная консоль для нашего веб-приложения, и мы хотим предоставить администраторам средства оповещения клиентов о чем-то. Административная консоль может иметь текстовую область для ввода сообщения вместе с commandButton, чтобы вызвать отправку сообщения как такового.
|
1
2
|
<h:inputText id="pushMessage" value="#{testBean.pushMessage}"/><h:commandButton action="#{testBean.sendAdminMessage}" value="Send Message"/> |
Тогда у класса JSF-контроллера testBean будет метод sendAdminMessage , который принимает сообщение, хранящееся в pushMessage , и отправляет его в наш метод sendMessage .
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
@Inject @Push private PushContext duke;...public void sendAdminMessage(){ sendMessage(pushMessage); FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Message has been broadcasted"));}...public void sendMessage(Object message){ duke.send(message);} |
Любой клиент, который получит сообщение, должен содержать тег f:websocket , указывающий на канал duke . Клиент также должен включать как минимум функцию JavaScript, которая будет вызываться при получении сообщения.
|
01
02
03
04
05
06
07
08
09
10
|
<f:websocket channel="duke" onmessage="dukeMessageListener"/><p:growl id="messages"/>function dukeMessageListener(message) { facesmessage.severity = 'info'; PF('broadcastGrowl').show(message);} |
В этом конкретном примере компонент сообщения рычания PrimeFaces будет обновляться при получении сообщения.
JSF 2.3 хорошо развивается благодаря отличному вкладу членов экспертной группы JSR 372.
| Ссылка: | Посмотрите на предстоящую поддержку JSF 2.3 Push от нашего партнера JCG Джоша Джуно в блоге Josh’s Dev — блог Java, Java EE, Jython, Oracle и другие… . |