Статьи

Основы JSF

Это краткое руководство, в котором кратко рассматриваются некоторые основы JSF, как мы определяем страницы и подключаем их к объектам на стороне сервера. Вместо того, чтобы охватывать основы запуска нового приложения JSF, я собираюсь начать с одного из архетипов Knappsack, который может предоставить вам приложение JEE 6, готовое к запуску. В этом случае мы начнем с примера на основе сервлета, чтобы вы могли запустить его с помощью встроенных контейнеров сервлета.

Для создания нового проекта мы будем использовать следующие значения GAV архетипа. Вы также можете прочитать о создании нового приложения Knappsack

groupId = org.fluttercode.knappsack
artifactId=jee6-servlet-basic
version=1.0.5

Получив проект, просто запустите mvn jetty: запустите в командной строке и перейдите по адресу http: // localhost: 8080 / jsfbasics / home.jsf . Хорошо, теперь все готово, давайте посмотрим на страницу JSF и ее содержимое.

JSF использует язык шаблонов, называемый facelets. JSF 1 первоначально использовал JSP в качестве языка представления, но для JSF 2.0 Facelets стали стандартами де-факто и были приняты в качестве стандартных языков определения представления для JSF 2.0. В нашем приложении у нас есть файл шаблона с именем WEB-INF / templates / template.xhtml. Шаблон просто имеет много стандартного кода представления, но есть некоторый интерфейс: вставьте теги, которые отмечают места в шаблоне, куда мы должны вставлять контент. Например, основной контент вставляется в область лицевых сторон, которая называется контентом

<ui:insert name="content">Main Content</ui:insert>

Это точки вставки, которые используются страницами, основанными на этом шаблоне. Одной из замечательных особенностей лицевых сторон является то, что шаблон определяет точки содержимого, а сама страница используется для определения используемого шаблона, а затем помещает содержимое в точки содержимого. Это гораздо лучше, чем включать фрагменты страницы в страницу JSP, использовать декоратор страницы или использовать шаблон для включения страницы контента. Наша главная страница home.xhtml — одна из таких страниц, которая использует этот шаблон.

home.xhtml

<?xml version="1.0" encoding="UTF-8"?>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
template="/WEB-INF/templates/template.xhtml">

<ui:define name="content">
<h1><h:outputText value="Hello From JSF" /></h1>
</ui:define>

</ui:composition>

 

В самом верху тега композиции мы сообщаем Facelets, что хотим использовать файл template.xhtml в качестве нашей страницы шаблона. Далее у нас есть тег ui: define, который определяет контент, который будет использоваться в шаблоне. Facelets работает, когда страница вытягивает шаблон на страницу и помещает его содержимое в слоты, предоставленные шаблоном. Это гораздо лучше, чем перетаскивать контент на главную страницу с помощью include или указывать шаблон, который используется везде, и украшать им контент. Это лучшее из обоих миров. Каждая страница определяет, какую страницу шаблона она использует, и помещает в нее содержимое.

Наш первый использованный компонент

Здесь вы можете видеть, что мы использовали наш первый компонент JSF:

<h:outputText value="Hello From JSF" />

 

Это стандартный компонент JSF, который используется для вывода текста. Мы могли бы просто написать текст прямо на странице, но цель этой страницы — проверить, работает ли конфигурация JSF, и для этого нам нужно проверить, правильно ли отображается компонент JSF. Вы можете редактировать текст в значении, и, очевидно, это изменит текст, отображаемый на странице.

Наш первый боб

Отображение статического текста — это не то, для чего были созданы веб-фреймворки, мы действительно хотим отображать что-то, что происходит из некоторого Java-кода. Для этого мы создадим компонент поддержки, который является Java-объектом, который является частью веб-приложения, о котором знает JSF. Чтобы создать базовый компонент, создайте новый класс и назовите его PageBean.

import javax.enterprise.context.RequestScoped;
import javax.inject.Named;

@Named
@RequestScoped
public class PageBean {

private String message = "Mighty apps from little java beans grow";

public String getMessage() {
return message;
}

public void setMessage(String message) {
this.message = message;
}
}

Сам код довольно прост. Одно поле со значением по умолчанию и геттерами и сеттерами. Тем не менее, у нас есть пара новых аннотаций на уровне класса. Во-первых, аннотация @Named, которая сообщает CDI, что у этого компонента есть имя, которое будет использоваться для ссылки на этот компонент с помощью выражений EL. Поскольку мы не указали имя, используется имя по умолчанию для pageBean. Аннотация @RequestScope сообщает CDI, что этот bean-компонент является областью действия запроса, поэтому при создании он должен сохраняться до конца текущего запроса и затем уничтожаться. Это означает, что в следующий раз, когда мы вызовем эту страницу, этот bean-компонент будет создан заново и будет использована новая версия, которая снова будет уничтожена в конце запроса.

Теперь мы собираемся изменить наше приложение, чтобы вместо этого отображать это сообщение. С этого момента мы просто будем показывать код внутри операторов ui: define:

	<ui:define name="content">
<h:outputText value="#{pageBean.message}" />
</ui:define>
</ui:composition>

Если мы запустим приложение сейчас, вы должны увидеть сообщение, отображаемое на главной странице:

JSF Скриншот основного сообщения дня

Теперь давайте рассмотрим метод продюсера, который можно использовать для отображения даты и времени отображения страницы. Сначала откройте файл шаблона и найдите панель нижнего колонтитула внизу и измените его на:

<h:panelGroup id="footer" layout="block">This page was rendered at #{currentSysDate}</h:panelGroup>

Что такое значение currentSysDate? Что ж, нам нужно вернуться к нашему PageBean и определить его. Мы добавим новый метод, который возвращает новый объект Date, и будем пометить его @Named и @Produces.

@Produces @Named("currentSysDate")
public Date produceDate() {
return new Date();
}

Аннотация Produces and Named сообщает CDI, что этот метод можно использовать для создания значения с именем currentSysDate. Когда наше приложение развернуто, CDI отмечает, что это значение исходит от этого метода, поэтому, когда наша страница отображается и JSF ищет значение currentSysDate, CDI вызывает метод и возвращает значение, полученное из этого метода.

Если мы обновим страницу, то увидим, что наша новая функция отметки времени включена.

Скриншот основной метки времени JSF

Это пригодится позже, когда мы начнем использовать AJAX и захотим убедиться, что полная страница не обновилась (временная метка останется прежней, поскольку эта часть страницы не изменится). Мы показали, как мы можем перенести данные с сервера на страницу, поэтому давайте посмотрим, как мы отправляем данные обратно на сервер.

На нашей странице home.xhtml мы добавим текстовый ввод для редактирования сообщения и кнопку для его отправки.

<h:form id="messageForm">
<h:outputText value="#{pageBean.message}" /><br/>
<br/>
New Message : <h:inputText value="#{pageBean.message}"/>
<h:commandButton action="update" value="Update"/>
</h:form>

Сначала мы добавили теги h: form, которые дают нам HTML-форму для размещения элементов управления вводом. Любая запись данных на странице JSF должна быть заключена в тег формы JSF для последующей передачи на сервер. Мы определили текстовое поле ввода, которое было привязано к тому же значению, что и отображение сообщения, и командную кнопку, которая используется для отправки значений обратно. Если мы обновим страницу, введите новое сообщение и нажмите кнопку, наше сообщение изменится.

Скриншот JSF Basic Form Post

Тем не менее, это эпоха Web 2.0, и просто отправить обратно форму и отобразить результаты недостаточно, нам нужно сделать это с AJAX. AJAX — это механизм, с помощью которого браузер выполняет асинхронный запрос к серверу и возвращает ответ. Когда ответ будет возвращен, браузер вызовет функцию javascript, которая обновит часть страницы вместо всей. Звучит сложно, но приятные люди, написавшие JSF, обернули всю эту функциональность в один маленький тег с именем f: ajax

Мы хотим сделать нашу командную кнопку кнопкой AJAX, что мы можем сделать, поместив тег f: ajax в качестве дочернего тега кнопки. Все, что нам нужно для предоставления тега AJAX — это атрибуты execute и render. Это указывает, какие части страницы мы хотим отправить обратно на сервер, и какие части мы хотим перерисовать при возврате ответа. Мы хотим выполнить форму и повторно обработать ее, чтобы мы могли использовать идентификатор компонента (messageForm) для значений атрибута. JSF также предоставляет несколько ярлыков, которые мы можем использовать. Значение @form ссылается на форму, в которой находится кнопка, вместо того, чтобы жестко кодировать идентификатор формы, значение @form позволит нам ссылаться на форму, не делая этого по имени.

<h:commandButton action="update" value="Update">
<f:ajax execute="@form" render="@form" />
</h:commandButton>

Обратите внимание, что теперь у вас есть кнопка AJAX, отметка времени в нижнем колонтитуле не изменяется при отправке значения обратно.

Выполнение действий

До сих пор мы рассматривали отображение информации от серверного компонента и запись значений обратно, но часто мы хотим, чтобы какое-то действие пользователя выполняло некоторый код на сервере.

Начните с добавления атрибута Integer к нашему классу PageBean и двух методов: одного для его увеличения и другого для его уменьшения, а также методов получения и установки значения.

 

private int value = 0;

public void increase() {
value++;
}

public void decrease() {
value--;
}

В представлении мы хотим отобразить значение и иметь пару кнопок для увеличения и уменьшения значения. Добавьте следующий код вида в home.jsf где-то между тегами h: form:

<h:panelGroup layout="block" id="spinner">
<h:commandButton action="#{pageBean.decrease}" value="-" />
#{pageBean.value}
<h:commandButton action="#{pageBean.increase}" value="+" />
</h:panelGroup>

Обновите страницу и нажмите кнопку, и вы заметите, что что-то не так. Нажмите кнопку увеличения, и значение станет равным 1, нажмите его еще раз, и оно … перейдет к 1. Нажмите кнопку уменьшения, и оно всегда будет равно -1. Проблема является вопросом государства. Каждый раз, когда мы нажимаем кнопку, мы отправляем сообщение обратно на сервер, и сервер создает новый экземпляр pageBean и вызывает методы увеличения или уменьшения. Проблема заключается в том, что каждый раз, когда мы создаем бин, значение начинается с нуля и поэтому всегда увеличивается до 1 или уменьшается до -1.
Теперь вам может быть интересно, что поскольку вы отображаете значение на странице, этого недостаточно, чтобы отправить его обратно на сервер, в конце концов, мы отобразили сообщение в поле ввода, и оно было передано обратно на сервер. Разница заключается в том, что поле ввода известно как держатель значения JSF, что означает, что оно фактически содержит значение, к которому оно привязано на клиенте, и отправляет его обратно на сервер, когда форма отправляется обратно. Это можно продемонстрировать, изменив компонент отображения текста значения на компонент ввода текста:

<h:panelGroup layout="block" id="spinner">
<h:commandButton action="#{pageBean.decrease}" value="-"/>
<h:inputText value="#{pageBean.value}"/>
<h:commandButton action="#{pageBean.increase}" value="+" />
</h:panelGroup>

Теперь, когда вы нажимаете кнопки +/-, значение изменяется за пределы -1 и 1. Это происходит потому, что при отображении страницы значение сохраняется на клиенте. Когда кнопка нажата и форма отправлена ​​обратно, значение на стороне клиента отправляется обратно в атрибут на стороне сервера, а затем вызывается метод увеличения / уменьшения с установленным значением. Это довольно часто встречается в веб-формах и является одним из способов обработки состояния путем помещения его в формы на стороне клиента, даже в виде скрытых значений полей.

Мы можем продемонстрировать это дальше, вручную введя значение в текстовый ввод и затем нажав кнопку. Введите 1000 в поле ввода и нажмите кнопку увеличения. Значение теперь должно быть 1001.

Основы JSF Ручной ввод значений

Когда мы вручную вводим значение, мы меняем значение, хранящееся на клиенте, в держателе значения, представленном текстовым полем ввода. Когда мы нажимаем кнопку увеличения, мы отправляем это значение обратно на сервер. При обратной передаче сервер создает экземпляр нашего класса PageBean, устанавливает для атрибута value значение в нашем текстовом поле (1000), а затем вызывает метод увеличения, который увеличивает значение до 1001. После завершения метода JSF должен отобразить ответ, который включает в себя получение значения из атрибута pageBean.value и помещение его в наше текстовое поле, как показано в текстовом поле 1001 после нажатия кнопки. На этом этапе, как только наш запрос будет завершен, бин страницы будет уничтожен, поскольку это только область запроса.

Проверка значения

Если мы хотим, чтобы значение находилось в диапазоне от 0 до 10, мы можем добавить аннотации проверки в поле значения, чтобы его можно было проверить на правильность, когда мы отправляем значения обратно. В нашем классе PageBean мы добавим аннотации следующим образом:

@Min(value=0)
@Max(value=10)
private int value = 0;

Нам также нужен способ отображения сообщений об ошибках, если пользователь вводит недопустимое значение, поэтому мы добавим тег ah: message. Тег сообщения используется для связи сообщения JSF с компонентом и его отображения. Мы даем имя вводному текстовому полю и добавляем сообщение для этого компонента:

<h:panelGroup layout="block" id="spinner">
<h:commandButton action="#{pageBean.decrease}" value="-"/>
<h:inputText value="#{pageBean.value}" id="valueInput"/>
<h:commandButton action="#{pageBean.increase}" value="+" />
<h:message for="valueInput" styleClass="errorMessage"/>
</h:panelGroup>

 

Теперь обновите страницу и введите 1000 в поле ввода значения и нажмите кнопку увеличения. Вы должны увидеть сообщение об ошибке рядом с текстовым редактором, потому что значение больше 10. Попробуйте ввести значение -1000 и нажать кнопку.

Скриншот ошибки основного ввода JSF

 

 

 

С http://www.andygibson.net/blog/tutorial/jsf-basics/