Статьи

Интеграция Spring и JSF: выбор элементов

С JSF, чтобы использовать комбинированные списки, списки и флажки, вы должны знать класс javax.faces.model.SelectItem . SelectItem представляет один выбираемый параметр; он содержит как информацию, необходимую для рендеринга, так и значение, которое следует связать, если выбран элемент. В большинстве случаев элементы SelectItems создаются со значением и меткой :
1
new SelectItem(Title.MISS, "Miss");

Работа с SelectItems до JSF 2.0 часто была утомительной, так как вам нужно было написать код, чтобы адаптировать ваши доменные объекты в SelectItems . JSF 2.0 значительно улучшил ситуацию, и теперь вы можете динамически создавать SelectItems, используя выражения EL. Например:

1
2
3
<h:selectOneMenu>
  <f:selectItems value="#{customerRepository.all}" var="customer" label="#{customer.name}"/>
</h:selectOneMenu>

Это, безусловно, помогает уменьшить объем кода, но я все еще думаю, что есть вещи, которые мы можем сделать, чтобы сделать SelectItems еще проще, особенно при работе с Spring. Имея это в виду, я разрабатывал компонент <s: selectItems> , предназначенный для замены <f: selectItems> .

Первое, что мы можем сделать, — это помочь уменьшить типизацию, избавляя от необходимости указывать атрибут var . С помощью <s: selectItems> , если атрибут var не указан, он по умолчанию будет item . Таким образом, приведенный выше код может быть написан:

1
2
3
<h:selectOneMenu>
  <s:selectItems value="#{customerRepository.all}" label="#{item.name}"/>
</h:selectOneMenu>

В приведенном выше примере значение привязывается к интерфейсу репозитория, который возвращает коллекцию сущностей Customer . Как и со стандартными компонентами <f: selectItems>, вы также можете привязать к массиву или DataModel . Кроме того, новый компонент также поддерживает любое значение String, разделенное запятыми.

1
2
3
<h:selectOneMenu>
  <s:selectItems value="Java, Spring, JavaServer Faces"/>
</h:selectOneMenu>

Следующая вещь, с которой <s: selectItems> может помочь, это нулевые значения. Весьма распространено использовать опцию «Пожалуйста, выберите» в раскрывающихся списках, чтобы представлять нули . В vanilla JSF это часто может означать дополнительную наценку для каждого компонента:

1
2
3
4
<h:selectOneMenu>
  <f:selectItem label="--- Please Select ---" noSelectionOption="true" itemValue=""/>
  <s:selectItems value="'{items}"/>
</h:selectOneMenu>

Вместо того, чтобы нуждаться в этой дополнительной наценке для каждого элемента, наш компонент будет автоматически вставлять опцию «Пожалуйста, выберите» всякий раз, когда он связан с компонентом UISelectOne . Вы можете использовать атрибут includeNoSelectionOption, чтобы переопределить это поведение. Метка, используемая для «опции без выбора», по умолчанию будет «- Пожалуйста, выберите -», но вы можете легко настроить и интернационализировать этот текст, добавив org.springframework.context.MessageSource в ApplicationContext, который может разрешить код «spring.faces». .noselectionoption " .

Что касается объекта MessageSource , компонент <s: selectItems> будет, когда это возможно, пытаться создать метку SelectItem с помощью org.springframework.springfaces.message.ObjectMessageSource . В прошлом я писал о том, как конвертировать объекты в сообщения, и этот компонент просто использует эти идеи.

Новый компонент помог нам при создании элементов SelectItems для отображения, но как насчет обработки отправки формы? Как преобразовать отправленный параметр String обратно в реальный объект ? в приведенном выше примере мы связываемся с сущностями клиента JPA; Значения будут отображаться очень хорошо, но когда вы отправляете форму, отображается «Ошибка преобразования», потому что JSF не знает, как получить обратно отправленную строку в объект Customer . Обычный ответ здесь — разработать собственную реализацию javax.faces.convert.Converter , но это часто проблематично. Часто вы выбираете значение элемента, представляющее собой сложный объект, который трудно представить в виде строки .

Существует интересная техника, которую вы можете использовать при написании конвертера, который будет использоваться с компонентом UISelectOne или UISelectMany . На самом деле вам нужен только код записи для преобразования из Object в String , преобразование в другом направлении может быть выполнено путем итерации SelectItem и возврата единственного значения Object, которое при преобразовании в String соответствует вашему переданному значению. Вы можете прочитать больше об этой идее в этом посте Арджана Тиймса. Использовать эту технику с компонентом <s: selectItems> очень просто, просто предоставьте атрибут itemConverterStringValue, который будет использоваться для создания уникального значения getAsString () :

1
2
3
<h:selectOneMenu>
  <s:selectItems value="#{customerRepository.all}" label="#{item.name}" itemConverterStringValue="#{item.id}"/>
</h:selectOneMenu>

На самом деле itemConverterStringValue является необязательным. Если вы не укажете его, будет использоваться метод объекта toString () или, в случае JPA @Entity , поле @ID будет использоваться автоматически. Вы по-прежнему можете писать и присоединять свой собственный конвертер, если это необходимо, в таких случаях itemConverterStringValue игнорируется.

Наконец, это еще один трюк, который может выполнить <s: selectItems> . Если вы выберете компонент, связанный с логическим или Enum, то атрибут value может быть полностью опущен. Элементы выбора будут построены на основе всех возможных опций, которые поддерживает привязка («Да» / «Нет» для логических значений или полный набор значений Enum ). Это также работает с типизированными коллекциями. Например, следующее отобразит параметры «Java», «Spring» и «JavaServer Faces» (при условии, что у вас есть соответствующий ObjectMessageSource ):

1
2
3
public enum Technology {
  JAVA, SPRING, JAVASERVER_FACES
}
1
2
3
4
public class Bean implements Serializable {
  private Set<Technology> technologies = new HashSet<Technology>();
  // ... getters and setters
}
1
2
3
<h:selectManyCheckbox value="#{bean.technologies}">
  <s:selectItems/>
</h:selectManyCheckbox>
Если вы хотите проверить любой из этого кода, взгляните на пакет org.springframework.springfaces.selectitems из проекта GitHub .

Ссылка: Интеграция Spring & JavaServer Faces: Выберите элементы от нашего партнера JCG Филиппа Уэбба в блоге Фила Уэбба в блоге.