@FacesConverter("ccno")
public class CreditCardConverter implements Converter {
...
}
Java Platform, Enterprise Edition (Java EE) 8 Учебник по Java EE |
Назад | Вперёд | Содержание |
Класс конвертера JavaServer Faces преобразует строки в объекты, а объекты в строки по мере необходимости. Для этой цели JavaServer Faces предоставляет несколько стандартных конвертеров. Смотрите Использование стандартных конвертеров для получения дополнительной информации об этих включённых конвертерах.
Как объясняется в Модель конвертации, если стандартные конвертеры, включённые в JavaServer Faces, не могут выполнить преобразование данных, которое вам нужно, вы можете создать кастомный конвертер для выполнения этого специализированного преобразования. Эта реализация, как минимум, должна определить, как преобразовывать данные в обоих направлениях между двумя представлениями данных, описанными в Модель преобразования.
Все кастомные конвертеры должны реализовывать интерфейс javax.faces.convert.Converter
. В этом разделе объясняется, как реализовать этот интерфейс для выполнения кастомной конвертации данных.
В примере Duke's Bookstore используется специальная реализация Converter
, расположенная в tut-install/examples/case-studies/dukes-bookstore/src/java/dukesbookstore/converters/CreditCardConverter.java
, чтобы преобразовать данные, введенные в поле «Номер кредитной карты» на странице bookcashier.xhtml
. Он удаляет пробелы и дефисы из текстовой строки и форматирует её так, чтобы пробел разделял каждые четыре символа.
Другой типичный пример использования кастомного конвертера — список нестандартных типов объектов. В примере Duke's Tutoring сущностям Student
и Guardian
требуется кастомный конвертер, чтобы их можно было преобразовывать в компонент ввода UISelectItems
и из него.
Класс кастомного конвертера CreditCardConverter
создаётся следующим образом:
@FacesConverter("ccno")
public class CreditCardConverter implements Converter {
...
}
Аннотация @FacesConverter
регистрирует класс кастомного конвертера как конвертер с именем ccno
в реализации JavaServer Faces. Кроме того, вы можете зарегистрировать конвертер с записями в файле конфигурации приложения, как показано в Регистрация кастомного конвертера.
Чтобы определить, как данные преобразуются из представления в модель, реализация Converter
должна реализовать метод getAsObject(FacesContext, UIComponent, String)
интерфейса Converter
. Вот реализация этого метода из CreditCardConverter
:
@Override
public Object getAsObject(FacesContext context,
UIComponent component, String newValue)
throws ConverterException {
if (newValue.isEmpty()) {
return null;
}
// Поскольку это всего лишь преобразование строки в строку,
// оно не выкидывает ConverterException.
String convertedValue = newValue.trim();
if ( (convertedValue.contains("-")) || (convertedValue.contains(" "))) {
char[] input = convertedValue.toCharArray();
StringBuilder builder = new StringBuilder(input.length);
for (int i = 0; i < input.length; ++i) {
if ((input[i] == '-') || (input[i] == ' ')) {
} else {
builder.append(input[i]);
}
}
convertedValue = builder.toString();
}
return convertedValue;
}
В фазе применения значений запроса, когда обрабатываются методы decode
компонентов, JavaServer Faces ищет локальное значение компонента в запросе и вызывает метод getAsObject
. При вызове этого метода JavaServer Faces передаёт текущий объект FacesContext
, компонент, данные которого требуют преобразования, и локальное значение в виде String
. Затем метод записывает локальное значение в массив символов, обрезает дефисы и пробелы, добавляет остальные символы в String
и возвращает String
.
Чтобы определить, как данные преобразуются из модели в представление, реализация Converter
должна реализовать метод getAsString(FacesContext, UIComponent, Object)
из интерфейса Converter
. Вот реализация этого метода:
@Override
public String getAsString(FacesContext context,
UIComponent component, Object value)
throws ConverterException {
String inputVal = null;
if ( value == null ) {
return "";
}
// значение должно иметь тип, приводимый к String.
try {
inputVal = (String)value;
} catch (ClassCastException ce) {
FacesMessage errMsg = new FacesMessage(CONVERSION_ERROR_MESSAGE_ID);
FacesContext.getCurrentInstance().addMessage(null, errMsg);
throw new ConverterException(errMsg.getSummary());
}
// после каждых четырёх символов вставляем пробелы
// (если их ещё нет) для лучшей удобочитаемости.
char[] input = inputVal.toCharArray();
StringBuilder builder = new StringBuilder(input.length + 3);
for (int i = 0; i < input.length; ++i) {
if ((i % 4) == 0 && (i != 0)) {
if ({input[i] != ' ') || (input[i] != '-')){
builder.append(" ");
// если присутствуют "-"', конвертируем их в пробелы.
} else if (input[i] == '-') {
builder.append(" ");
}
}
builder.append(input[i]);
}
String convertedValue = builder.toString();
return convertedValue;
}
В фазе отрисовки ответа, на котором вызываются методы encode
компонентов, JavaServer Faces вызывает метод getAsString
для генерации соответствующего вывода. Когда JavaServer Faces вызывает этот метод, он передаёт текущий FacesContext
компоненту UIComponent
, значение которого необходимо конвертировать, и значение бина, подлежащего конвертации. Поскольку этот конвертер выполняет преобразование String
в String
, этот метод может преобразовывать значение бина в String
.
Если значение не может быть преобразовано в String
, метод выдает исключение, передавая сообщение об ошибке из пакета ресурсов, зарегистрированного в приложении. Регистрация сообщений приложения объясняет, как зарегистрировать кастомные сообщения об ошибках в приложении.
Если значение можно преобразовать в String
, метод считывает String
в массив символов и циклически перебирает массив, добавляя пробел после каждых четырёх символов.
Вы также можете создать кастомный конвертер с аннотацией @FacesConverter
, в которой указан атрибут forClass
, как показано в следующем примере из приложения Duke's Tutoring:
@FacesConverter(forClass=Guardian.class, value="guardian")
public class GuardianConverter extends EntityConverter implements Converter { ...
Атрибут forClass
регистрирует конвертер как конвертер по умолчанию для класса Guardian
. Поэтому всякий раз, когда этот класс указывается атрибутом value
компонента ввода, конвертер вызывается автоматически.
Класс конвертера может быть отдельным классом POJO, как в случае с Duke's Bookstore. Однако если ему требуется доступ к объектам, определённым в классе Managed-бина, он может быть дочерним классом Managed-бина JavaServer Faces, как в примере address-book
, в котором конвертеры используют Enterprise-бин, который инъецируется в класс Managed-бина.
Чтобы применить преобразование данных, выполненное кастомным конвертером, к значению определённого компонента, необходимо выполнить одно из следующих действий.
Запишите ссылку на конвертер в атрибуте converter
тега компонента.
Вложите тег f:converter
в тег компонента и укажите ссылку на кастомный конвертер из одного из атрибутов тега f:converter
.
Если вы используете атрибут converter
тега компонента, этот атрибут должен ссылаться на идентификатор реализации Converter
или полное имя класса конвертера. Создание и использование кастомного конвертера объясняет, как реализовать кастомный конвертер.
Идентификатор класса конвертера кредитных карт: ccno
, значение указано в аннотации @FacesConverter
:
@FacesConverter("ccno")
public class CreditCardConverter implements Converter {
...
Поэтому объект CreditCardConverter
можно зарегистрировать в компоненте ccno
, как показано в следующем примере:
<h:inputText id="ccno"
size="19"
converter="ccno"
value="#{cashierBean.creditCardNumber}"
required="true"
requiredMessage="#{bundle.ReqCreditCard}">
...
</h:inputText>
Задавая атрибут converter
тега компонента для идентификатора конвертера или его имени класса, вы вызываете автоматическое преобразование локального значения этого компонента в соответствии с правилами, указанными в реализации Converter
.
Вместо ссылки на конвертер из атрибута converter
тега компонента, вы можете ссылаться на конвертер из тега f:converter
, вложенного в тег компонента. Чтобы сослаться на кастомный конвертер с помощью тега f:converter
, выполните одно из следующих действий.
Задайте для атрибута converterId
тега f:converter
идентификатор реализации Converter
, определённый в аннотации @FacesConverter
или в файле конфигурации приложения. Этот метод показан в bookcashier.xhtml
:
<h:inputText id="ccno"
size="19"
value="#{cashierBean.creditCardNumber}"
required="true"
requiredMessage="#{bundle.ReqCreditCard}">
<f:converter converterId="ccno"/>
<f:validateRegex
pattern="\d{16}|\d{4} \d{4} \d{4} \d{4}|\d{4}-\d{4}-\d{4}-\d{4}"/>
</h:inputText>
Свяжите реализацию Converter
со свойством Managed-бина с помощью атрибута binding
тега f:converter
, как описано в Связывание конвертеров, слушателей и валидаторов со свойствами Managed-бина.
JavaServer Faces вызывает метод конвертера getAsObject
для удаления пробелов и дефисов из введённого значения. Метод getAsString
вызывается при повторном отображении страницы bookcashier.xhtml
. Это происходит, если пользователь заказывает книги на сумму более 100 долларов.
В примере Duke's Tutoring каждый конвертер зарегистрирован как конвертер для определённого класса. Конвертер автоматически вызывается всякий раз, когда этот класс определяется атрибутом value
компонента ввода. В следующем примере атрибут itemValue
(выделен жирным шрифтом) вызывает конвертер для класса Guardian
:
<h:selectManyListbox id="selectGuardiansMenu"
title="#{bundle['action.add.guardian']}"
value="#{guardianManager.selectedGuardians}"
size="5"
converter="guardian">
<f:selectItems value="#{guardianManager.allGuardians}"
var="selectedGuardian"
itemLabel="#{selectedGuardian.name}"
itemValue="#{selectedGuardian}" />
</h:selectManyListbox>
Назад | Вперёд | Содержание |