Не забывайте, что в этом случае доступные элементы должны быть списком. Мы использовали HashMap и изменили его на List.

я проблемы с пониманием того, как эффективно использовать выделение в JSF 2 с POJO / сущностью. Например, я пытаюсь выбратьWarehouse сущность через раскрывающийся список:

<h:selectOneMenu value="#{bean.selectedWarehouse}">
    <f:selectItem itemLabel="Choose one .." itemValue="#{null}" />
    <f:selectItems value="#{bean.availableWarehouses}" />
</h:selectOneMenu>

И ниже управляемый боб:

@Named
@ViewScoped
public class Bean {

    private Warehouse selectedWarehouse;
    private List<SelectItem> availableWarehouses;

    // ...

    @PostConstruct
    public void init() {
        // ...

        availableWarehouses = new ArrayList<>();

        for (Warehouse warehouse : warehouseService.listAll()) {
            availableWarehouses.add(new SelectItem(warehouse, warehouse.getName()));
        }
    }

    // ...
}

Обратите внимание, что я использую весьWarehouse сущность как ценностьSelectItem.

Когда я отправляю форму, это терпит неудачу со следующим сообщением лиц:

Значение параметра Ошибка преобразования '[email protected]' для 'нулевого конвертера'.

Я надеялся, что JSF может просто установить правильныйWarehouse возражать против моего управляемого боба, когда я обернуть его вSelectItem, Заворачивая мою сущность вSelectItem должен был пропустить созданиеConverter для моей сущности.

Я действительно должен использоватьConverter всякий раз, когда я хочу использовать сущности в моем<h:selectOneMenu>? Для JSF должно быть возможно просто извлечь выбранный элемент из списка доступных элементов. Если мне действительно нужно использовать конвертер, каков практический способ сделать это? До сих пор я дошел до этого:

СоздатьConverter реализация для субъекта.ПереопределениеgetAsString(), Я думаю, что мне это не нужно, так как свойство labelSelectItem будет использоваться для отображения метки выпадающего списка.ПереопределениеgetAsObject(), Я думаю, что это будет использоваться, чтобы вернуть правильныйSelectItem или объект в зависимости от типа выбранного поля, определенного в управляемом компоненте.

getAsObject() смущает меня Каков эффективный способ сделать это? Имея строковое значение, как я могу получить связанный объект сущности? Должен ли я запросить объект сущности из сервисного объекта на основе строкового значения и вернуть сущность? Или, возможно, каким-то образом я могу получить доступ к списку сущностей, которые формируют элементы выбора, зациклить их, чтобы найти правильную сущность, и вернуть сущность?

Каков нормальный подход к этому?

Ответы на вопрос(2)

Решение Вопроса
Введение

String, Чтобы представить объекты Java в HTML, они должны быть преобразованы вString, Кроме того, при отправке формы HTML отправленные значения обрабатываются какString в параметрах HTTP-запроса. Под прикрытием JSF извлекает их изHttpServletRequest#getParameter() который возвращаетсяString.

Преобразовать между нестандартным объектом Java (т.е. неString, Number или жеBoolean для которого EL имеет встроенные преобразования, илиDate для которого JSF предоставляет встроенные<f:convertDateTime> тег), вы действительно должны предоставитьConverter,SelectItem не имеет никакого специального назначения вообще. Это просто пережиток JSF 1.x, когда было невозможно поставить, например,List<Warehouse> прямо к<f:selectItems>, Он также не имеет особого отношения к этикеткам и конверсии.

getAsString ()

Вам необходимо реализоватьgetAsString() метод таким образом, что желаемый объект Java был представлен вуникальный String представление, которое можно использовать в качестве параметра HTTP-запроса. Обычно здесь используется технический идентификатор (первичный ключ базы данных).

public String getAsString(FacesContext context, UIComponent component, Object modelValue) {
    if (modelValue == null) {
        return "";
    }

    if (modelValue instanceof Warehouse) {
        return String.valueOf(((Warehouse) modelValue).getId());
    } else {
        throw new ConverterException(new FacesMessage(modelValue + " is not a valid Warehouse"));
    }
}

Обратите внимание, что возврат пустой строки в случае нулевого / пустого значения модели является значительным и требуется дляJavadoc, Смотрите такжеИспользование «Пожалуйста, выберите» f: selectItem с нулевым / пустым значением внутри p: selectOneMenu.

getAsObject ()

Вам необходимо реализоватьgetAsObject() таким образом, чтоименно так этоString представление, как возвращеноgetAsString() может быть преобразован обратно вименно так тот же объект Java, указанный какmodelValue вgetAsString().

public Object getAsObject(FacesContext context, UIComponent component, String submittedValue) {
    if (submittedValue == null || submittedValue.isEmpty()) {
        return null;
    }

    try {
        return warehouseService.find(Long.valueOf(submittedValue));
    } catch (NumberFormatException e) {
        throw new ConverterException(new FacesMessage(submittedValue + " is not a valid Warehouse ID"), e);
    }
}

Другими словами, вы должны быть технически способны вернуть возвращаемый объект какmodelValue аргументgetAsString() а затем вернуть полученную строку какsubmittedValue аргументgetAsObject() в бесконечном цикле.

использование

Наконец, просто аннотируйтеConverter с участием@FacesConverter чтобы подключить рассматриваемый тип объекта, JSF автоматически позаботится о преобразовании, когдаWarehouse Тип когда-либо входит в картину:

@FacesConverter(forClass=Warehouse.class)

Это был «канонический» подход JSF. В конце концов, это не очень эффективно, так как могло бы просто взять предмет из<f:selectItems>, Но самый важный моментConverter является то, что он возвращаетуникальный String представление, так что объект Java может быть идентифицирован простымString подходит для передачи по HTTP и HTML.

Универсальный конвертер на основе toString ()

Библиотека утилит JSFOmniFaces имеетSelectItemsConverter который работает на основеtoString() результат сущности. Таким образом, вам не нужно возиться сgetAsObject() и более дорогие операции с базами данных. Для некоторых конкретных примеров использования см. Такжевитрина.

Чтобы использовать это, просто зарегистрируйте это как ниже:

<h:selectOneMenu ... converter="omnifaces.SelectItemsConverter">

И убедитесь, чтоtoString() вашейWarehouse сущность возвращаетуникальный представление субъекта. Например, вы можете напрямую вернуть идентификатор:

@Override
public String toString() {
    return String.valueOf(id);
}

Или что-то более читаемое / многоразовое:

@Override
public String toString() {
    return "Warehouse[id=" + id + "]";
}
Смотрите также:Как заполнить опции h: selectOneMenu из базы данных?Универсальный конвертер сущностей JSF - так что вам не нужно писать конвертер длякаждый организация.Использование перечислений в элементах выбора JSF - перечисления должны рассматриваться немного по-другомуКак добавить @EJB, @PersistenceContext, @Inject, @Autowired и т. Д. В @FacesConverter?

несвязанный к проблеме, так как JSF 2.0 больше не требуется явно иметьList<SelectItem> как<f:selectItem> стоимость. ПростоList<Warehouse> также будет достаточно.

<h:selectOneMenu value="#{bean.selectedWarehouse}">
    <f:selectItem itemLabel="Choose one .." itemValue="#{null}" />
    <f:selectItems value="#{bean.availableWarehouses}" var="warehouse"
        itemLabel="#{warehouse.name}" itemValue="#{warehouse}" />
</h:selectOneMenu>
private Warehouse selectedWarehouse;
private List<Warehouse> availableWarehouses;
 bertie19 янв. 2011 г., 22:38
большое спасибо за подробный ответ, это решило мою проблему! Универсальный конвертер сущностей JSF очень хорош!
 Roland08 окт. 2017 г., 18:49
Я скучал по<f:converter converterId="ContactConverter" /> часть. Спасибо @BalusC за указание правильного направления.
 BalusC19 янв. 2011 г., 23:06
Пожалуйста.
 Joe Almore16 янв. 2012 г., 21:07
Здравствуйте @BalusC, я реализовал это решение, и оно работает, но я вижу только одну проблему. Если я пытаюсь переместить файл пользовательского конвертера в отдельный компонент, то при перезагрузке страницы появляется сообщение «Ошибка выражения: объект с именем MyCustomCoverter не найден». Так что этот текст<f:converter converterId="MyCustomConverter"/> не могу найти конвертер. Теперь, как я могу заставить это работать?

Пример универсального конвертера JSF с ABaseEntity и идентификатором:

ABaseEntity.java

public abstract class ABaseEntity implements Serializable {

    private static final long serialVersionUID = 1L;

    public abstract Long getIdentifier();
}

SelectItemToEntityConverter.java

@FacesConverter(value = "SelectItemToEntityConverter")
public class SelectItemToEntityConverter implements Converter {

    @Override
    public Object getAsObject(FacesContext ctx, UIComponent comp, String value) {
        Object o = null;
        if (!(value == null || value.isEmpty())) {
            o = this.getSelectedItemAsEntity(comp, value);
        }
        return o;
    }

    @Override
    public String getAsString(FacesContext ctx, UIComponent comp, Object value) {
        String s = "";
        if (value != null) {
            s = ((ABaseEntity) value).getIdentifier().toString();
        }
        return s;
    }

    private ABaseEntity getSelectedItemAsEntity(UIComponent comp, String value) {
        ABaseEntity item = null;

        List<ABaseEntity> selectItems = null;
        for (UIComponent uic : comp.getChildren()) {
            if (uic instanceof UISelectItems) {
                Long itemId = Long.valueOf(value);
                selectItems = (List<ABaseEntity>) ((UISelectItems) uic).getValue();

                if (itemId != null && selectItems != null && !selectItems.isEmpty()) {
                    Predicate<ABaseEntity> predicate = i -> i.getIdentifier().equals(itemId);
                    item = selectItems.stream().filter(predicate).findFirst().orElse(null);
                }
            }
        }

        return item;
    }
}

И использование:

<p:selectOneMenu id="somItems" value="#{exampleBean.selectedItem}" converter="SelectItemToEntityConverter">
    <f:selectItem itemLabel="< select item >" itemValue="#{null}"/>
    <f:selectItems value="#{exampleBean.availableItems}" var="item" itemLabel="${item.identifier}" itemValue="#{item}"/>
</p:selectOneMenu>
 Andrei08 июл. 2018 г., 16:54
Не забывайте, что в этом случае доступные элементы должны быть списком. Мы использовали HashMap и изменили его на List.
 Kukeltje02 авг. 2017 г., 19:43
Это уже в другом Q / A, указанном в исходном ответе:stackoverflow.com/questions/17343032/...
 AngelAvila09 авг. 2017 г., 20:01
Большое спасибо, это решение сработало для меня.
 Kukeltje04 авг. 2017 г., 08:38
объясните пожалуйста более подробно в вашем ответе
 proxymo04 авг. 2017 г., 02:38
Разница в том, что нет необходимости в обслуживании и вызовах базы данных.

Ваш ответ на вопрос