Как упоминалось в предыдущих статьях, в следующий выпуск 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 и другие… . |