Скачиваний:
88
Добавлен:
09.05.2014
Размер:
823.27 Кб
Скачать

javax.faces.Float javax.faces.convert.FloatConverter

Таким образом, если поле формы связано со свойством типа int или Integer, то конвертация происходит автоматически. В листинге 19 показан компонент, использующийся в нашем демонстрационном приложении для управления контактами. Он связан непосредственно со свойством age c помощью выражения #{contactController.contact.age}:

Листинг 19. Связывание со свойством age: конвертация выполняется автоматически

<%-- age --%>

<h:outputLabel value="Age" for="age" accesskey="age" />

<h:inputText id="age" size="3" value="#{contactController.contact.age}"> </h:inputText>

JSF предоставляет конвертеры для всех примитивных типов, классов-оболочек над примитивными типами, строк и перечислений. Неплохо, не правда ли? Кроме того, есть конвертеры для дат и чисел. Поскольку числа могут задаваться в различных форматах, существующий конвертер позволяет указать конкретный формат, используемый пользователем. То же самое справедливо и для дат. Пример использования конвертера для преобразования строки в дату в соответствии с конкретным форматом показан в листинге 20.

Хотя JSF хорошо справляется с конвертацией строк в примитивные (и схожие с ними) типы по умолчанию, при работе с датами необходимо использовать специальный тег <f:convertDateTime/>. Этот тег использует классы из пакетаjava.text и работает с коротким, длинным и специальными форматами дат. В листинге 20 показано, как использовать<f:convertDateTime/> для проверки того, что в поле ―дата рождения‖ находится дата, отформатированная в видеMM/yyyy (2 цифры месяца/4 цифры года). Список всех поддерживаемых форматов можно найти в документации Java API (см. Ресурсы).

Листинг 20. Указание формата даты

<%-- birthDate --%>

<h:outputLabel value="Birth Date" for="birthDate" accesskey="b" /> <h:inputText id="birthDate" value="#{contactController.contact.birthDate}">

<f:convertDateTime pattern="MM/yyyy"/> </h:inputText>

<h:message for="birthDate" errorClass="errorClass" />

В начало

Специализированные конвертеры JSF

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

String в объект типа PhoneNumber (поля PhoneNumber.areaCode, PhoneNumber.prefix, ...)

String в объект типа Name (поля Name.first, Name.last)

String в объект типа ProductCode (поля ProductCode.partNum,ProductCode.rev, ...)

String в объект типа Group

String в объект типа Tags

Для создания специализированного конвертера необходимо следующее:

1.Создать класс, реализующий интерфейс Converter (полное имя javax.faxes.convert.Converter).

2.Реализовать метод getAsObject(), который будет вызываться для преобразования строкового значения поля в объект (например, типа PhoneNumber).

3.Реализовать метод getAsString, который будет вызываться для получения строкового представления объекта (например, типа PhoneNumber).

4.Зарегистрировать конвертер в контексте Faces.

На рисунке 7 показано, как эти действия вписываются в жизненный цикл приложения JSF:

Валидаторы в JSF

Главной целью конвертации и валидации является подготовка данных для обновления объектов модели. Таким образом, к моменту вызова методов, реализующих логику приложения, можно сделать определенные выводы о состоянии модели. Конвертация и валидация позволяют сконцентрироваться на бизнес-логике приложения, а не на утомительных проверках ввода, таких как проверка на null, на длину, на границы массивов и т.д.

Поэтому разумно, что конвертация и валидация выполняются до того, как данные поступают в управляемые bean-объекты на этапе обновления модели. Как вы помните из раздела "Жизненный цикл обработки запросов в приложениях JSF", эти операции выполняются на этапе проверки данных: сначала конвертация, потом валидация.

ВJSF существует четыре варианта того, как может происходить валидация:

С помощью встроенных компонентов

На уровне приложения

С помощью проверочных методов серверных объектов (inline-валидация)

С помощью специализированных компонентов, реализующих интерфейсValidator Ниже мы рассмотрим все эти варианты.

Стандартная валидация

JSF включает в себя три стандартных компонента для валидации:

DoubleRangeValidator: Проверяет, что значение компонента укладывается в интервал, определяемый нижней границей, верхней границей или и тем, и другим. Значение должно быть числом.

LongRangeValidator: Проверяет, что значение укладывается в интервал, определяемый нижней границей, верхней границей или и тем, и другим. Значение должно быть числом, преобразуемым к типу long.

LengthValidator: Проверяет, что длина значения укладывается в интервал, определяемый нижней границей, верхней границей или и тем, и другим. Значение должно быть типа String.

Внашем примере возраст в данных контакта может быть любым числом. Но поскольку такие значения, как –2, не имеют смысла, стоит связать это поле с правилом валидации. В листинге 29 показан пример кода, выполняющего валидацию с

помощью элемента <f:validateLongRange> для обеспечения корректности возрастных данных в модели приложения.

Листинг 29. Валидация возрастных данных с помощью элемента <f:validateLongRange>

<%-- возраст (age) --%>

<h:outputLabel value="Age" for="age" accesskey="age" />

<h:inputText id="age" size="3" value="#{contactController.contact.age}"> <f:validateLongRange minimum="0" maximum="150"/>

</h:inputText>

<h:message for="age" errorClass="errorClass" />

Разобравшись с полем age, можно перейти к ограничениям на длину строки поля FirstName (см. листинг 30).

Листинг 30. Проверка длины строки свойства firstName

<%-- Имя (first name) --%>

<h:outputLabel value="First Name" for="firstName" accesskey="f" /> <h:inputText id="firstName" label="First Name" required="true"

value="#{contactController.contact.firstName}" size="10" > <f:validateLength minimum="2" maximum="25" />

</h:inputText>

<h:message for="firstName" errorClass="errorClass" />

Несмотря на то, что встроенная валидация JSF применима во многих случаях, ее возможности ограничены. Если речь идет о валидации адресов электронной почты, телефонных номеров, URL, дат и т.д., то иногда лучше создавать собственные валидаторы (мы обсудим эту тему далее). Кроме того, можно использовать валидаторы, предоставляемые такими библиотеками, как Tomahawk, Shale, JSF-Validations и Crank (см. Ресурсы).

Валидация уровня приложения

Под валидацией уровня приложения понимается непосредственно бизнес-логика. В JSF она отделена от первичной валидации форм и их полей. Как правило, валидация уровня приложения заключается в добавлении в методы управляемых bean-объектов кода, который использует модель приложения для проверки уже помещенных в нее данных. Например, в случае корзины покупок валидация форм может проверять корректность значения, определяющего количество тех или иных товаров, но для проверки того, что пользователь не превысил свою кредитную линию, необходима бизнес-логика. Это еще один пример принципа разделения ответственности (separation of concerns) в JSF. Допустим, пользователь нажал на кнопку, связанную с action-методом, исполняемом на этапе вызова приложения (см.рисунок 5). Перед тем, как с данными будут произведены какие либо действия (что, как правило, происходит в фазе обновления модели), можно проверить, являются ли введенные данные корректными с точки зрения бизнес-правил приложения.

Например, пусть в нашем приложении пользователь нажал на кнопку Update/Add, связанную с методом контроллераpersist(). В этот метод можно добавить фрагмент кода, проверяющий, существует ли уже такая комбинация полейfirstName/lastName в системе. Если такой контакт уже существует, можно также добавить сообщение в объектFacesContext, а затем указать JSF, что следует сохранить текущее представление, вернув null в качестве исхода (если для данного метода определены правила переходов).

Теперь давайте вернемся к нашему приложению и добавим некоторую логику уровня приложения в метод persist(), как показано в листингах 31 и 32. В листинге 31 показана валидация уровня приложения в контроллере:

Листинг 31. Валидация уровня приложения в классе контроллера

public class ContactController { public String persist() {

/* Валидация уровня приложения. */ try {

contact.validate();

} catch (ContactValidationException contactValidationException) { addErrorMessage(contactValidationException.getLocalizedMessage()); return null;

}

/* Форма доступна, ссылка для добавления - нет. */ form.setRendered(false); addNewCommand.setRendered(true);

/* Добавление сообщения о статусе операцмм. */

if (contactRepository.persist(contact) == null) { addStatusMessage("Added " + contact);

} else {

addStatusMessage("Updated " + contact);

}

return "contactPersisted";

}

private void addErrorMessage(String message) { FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(

FacesMessage.SEVERITY_ERROR, message, null));

}

Как видно из листинга 31, метод persist() вызывает метод validate() класса Сontact. Он обрабатывает все исключения и преобразует их в сообщения об ошибках – объекты типа FacesMessage. В случае выдачи исключения онnull, что означает: оставаться на текущем представлении и не переходить к следующему.

Код, выполняющий саму валидацию, находится в модели — в методе validate() класса Contact (см. листинг 32). Благодаря этому становится возможным добавлять новые правила валидации, не затрагивая при этом слои контроллера и представления.

Листинг 32. Валидация в слое модели, а не контроллера

...

public class Contact implements Serializable {

...

public void validate() throws ContactValidationException { if (

(homePhoneNumber == null || ".equals(homePhoneNumber)) & (workPhoneNumber == null || ".equals(workPhoneNumber)) & (mobilePhoneNumber == null || ".equals(mobilePhoneNumber))

) {

throw new ContactValidationException("At least one phone number" + "must be set");

}

}

Валидация уровня приложения проста и легко реализуема. Ее преимущества:

простота реализации;

отсутствие необходимости специального класса (специализированного валидатора);

отсутствие необходимости указывать валидатор при разработке страниц представления; Недостатком валидации уровня приложения является то, что она выполняется после других форм валидации

(стандартной, специализированной и компонентной), поэтому сообщения об ошибках появляются только после того, как вся остальная валидация прошла успешно.

Вцелом валидацию уровня приложения следует использовать только там, где необходима проверка с учетом бизнеслогики.

Автономные специализированные валидаторы

JSF позволяет создавать подключаемые валидирующие компоненты, которые можно использовать в различных Webприложениях.

Для создания валидатора необходимо сделать следующее:

1.класс, реализующий интерфейс Validator (javax.faces.validator.Validator).

2.Реализовать метод validate().

3.Зарегистрировать валидатор в файле faces-config.xml.

4.Использовать тег <f:validator/> на страницах JSP.

Далее мы остановимся на каждом из этих шагов, рассмотрев пример создания специализированного валидатора.

Работы с обработчиками событий жизненного цикла

Согласно документации по JSF API (см. Ресурсы), PhaseListener (обработчик событий жизненного цикла) – это "интерфейс, реализуемый объектами, которым необходимы уведомления о начале или окончании каждой стандартной фазы жизненного цикла обработки запроса" (Sun Microsystems Inc., 2006 г.). Теперь, когда вы познакомились с конвертерами, валидаторами и action-методами, пришло время создать несколько обработчиков событий жизненного цикла. В предыдущих версиях JSF все обработчики событий были глобальными. В JSF 1.2 появилась возможность регистрировать обработчики событий на уровне представления с помощью тега <f:phaseListener binding="..." />.

Создание обработчиков событий жизненного цикла

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

Листинг 42. DebugPhaseListener

package com.arcmind.phase;

import javax.faces.event.PhaseEvent; import javax.faces.event.PhaseId; import javax.faces.event.PhaseListener;

@SuppressWarnings("serial")

public class DebugPhaseListener implements PhaseListener {

public void beforePhase(PhaseEvent phaseEvent) { System.out.println("------ BEFORE PHASE " + phaseEvent.getPhaseId());

}

public void afterPhase(PhaseEvent phaseEvent) { System.out.println("------ AFTER PHASE " + phaseEvent.getPhaseId());

if (phaseEvent.getPhaseId() == PhaseId.RENDER_RESPONSE) { System.out.println("REQUEST END\n\n");

}

}

public PhaseId getPhaseId() { return PhaseId.ANY_PHASE;

}

}

Классы, реализующие PhaseListener, будут вызываться перед началом входа и после выхода из каждой фазы цикла JSF. Фазы, о которых необходимо получать уведомления, указываются с помощью метода getPhaseId(). КонстантаPhaseId.ANY_PHASE означает, что уведомления будут посылаться для всех фаз.

Класс DebugPhaseListener просто печатает имя события, которое привело к его вызову, чтобы была понятна последовательность действий. Для большей наглядности добавим вызовы System.out.println ко всем методам конвертации, валидации и бизнес-логики. Кроме того, вызовы System.out.println будет полезно добавить в свойство firstName, чтобы видеть, в какие моменты к нему происходят обращения.

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

Expression Language (EL) — скриптовый язык выражений, который позволяет получить доступ к Java компонентам (JavaBeans) из JSP. Начиная с JSP 2.0 используется внутриJSP тегов для отделения Java кода от JSP для обеспечения лѐгкого доступа к Java компонентам.

Развитие EL происходило с целью сделать его более простым для дизайнеров, которые имеют минимальные познания в языке программирования Java. До появления языка выражений, JSP имел несколько специальных тегов таких

как скриптлеты (англ.), выражения и т. п. которые позволяли записывать Java код непосредственно на странице. С использованием языка выражений веб-дизайнер должен знать только то, как организовать вызов соответствующих javaметодов.

Используйте EL всегда, когда надо подставить нестатическое значение. Используйте EL всегда, когда возможно обойтись без Java-вставок. А лучше, никогда не использовать Java-вставок. Например, я никогда не использую Java-вставки и на практике всегда удаѐтся обойтись без них.

Например, так:

<a href="show.jsp?id=${myObject.id}">${myObject.title}</a>

Или в связке с Custom Tags, например, с JSTL:

<ul>

<c:forEach values="${pageBean.myItems}" var="item"> <li>${item.title}</li>

</c:forEach>

</ul>

Или вот, например, для раскраски строк таблицы

<c:forEach values="${myTable.rows}" var="row"> <tr class="${my:rowClass(row)}">..... </tr>

</c:forEach>

Соседние файлы в папке лабораторная работа 7 (jsf)