当前位置: 首页 > 知识库问答 >
问题:

如何从数据库中填充h:selectOneMenu的选项?

许远航
2023-03-14

我正在创建一个web应用程序,您必须从数据库中读取对象/实体的列表,并将其填充到JSF

我知道如何获得列表

<h:selectOneMenu value="#{bean.name}">
    ...?
</h:selectOneMenu>

共有3个答案

周志文
2023-03-14

BALUCC给出了一个关于这个问题的非常有用的概述性答案。但有一个他没有介绍的替代方案:Roll your own通用转换器,将复杂对象作为选定项处理。如果你想处理所有的情况,这是非常复杂的,但对于简单的情况,这是非常简单的。

下面的代码包含此类转换器的示例。它的工作原理与OmniFaces SelectItemsConverter相同,因为它查看包含对象的UISelectItem的组件的子级。不同之处在于它只处理与实体对象的简单集合或字符串的绑定。它不处理项目组、SelectItems的集合、数组以及可能的许多其他东西。

组件绑定到的实体必须实现IdObject接口。(这可以通过其他方式解决,例如使用toString。)

请注意,实体必须以相同ID的两个实体比较相等的方式实现equals

要使用它,只需将其指定为select组件上的转换器,绑定到实体属性和可能的实体列表:

<h:selectOneMenu value="#{bean.user}" converter="selectListConverter">
  <f:selectItem itemValue="unselected" itemLabel="Select user..."/>
  <f:selectItem itemValue="empty" itemLabel="No user"/>
  <f:selectItems value="#{bean.users}" var="user" itemValue="#{user}" itemLabel="#{user.name}" />
</h:selectOneMenu>

转换器:

/**
 * A converter for select components (those that have select items as children).
 * 
 * It convertes the selected value string into one of its element entities, thus allowing
 * binding to complex objects.
 * 
 * It only handles simple uses of select components, in which the value is a simple list of
 * entities. No ItemGroups, arrays or other kinds of values.
 * 
 * Items it binds to can be strings or implementations of the {@link IdObject} interface.
 */
@FacesConverter("selectListConverter")
public class SelectListConverter implements Converter {

  public static interface IdObject {
    public String getDisplayId();
  }

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

    return component.getChildren().stream()
      .flatMap(child -> getEntriesOfItem(child))
      .filter(o -> value.equals(o instanceof IdObject ? ((IdObject) o).getDisplayId() : o))
      .findAny().orElse(null);
  }

  /**
   * Gets the values stored in a {@link UISelectItem} or a {@link UISelectItems}.
   * For other components returns an empty stream.
   */
  private Stream<?> getEntriesOfItem(UIComponent child) {
    if (child instanceof UISelectItem) {
      UISelectItem item = (UISelectItem) child;
      if (!item.isNoSelectionOption()) {
        return Stream.of(item.getValue());
      }

    } else if (child instanceof UISelectItems) {
      Object value = ((UISelectItems) child).getValue();

      if (value instanceof Collection) {
        return ((Collection<?>) value).stream();
      } else {
        throw new IllegalStateException("Unsupported value of UISelectItems: " + value);
      }
    }

    return Stream.empty();
  }

  @Override
  public String getAsString(FacesContext context, UIComponent component, Object value) {
    if (value == null) return null;
    if (value instanceof String) return (String) value;
    if (value instanceof IdObject) return ((IdObject) value).getDisplayId();

    throw new IllegalArgumentException("Unexpected value type");
  }

}
申屠森
2023-03-14

查看页面

<h:selectOneMenu id="selectOneCB" value="#{page.selectedName}">
     <f:selectItems value="#{page.names}"/>
</h:selectOneMenu>

背豆

   List<SelectItem> names = new ArrayList<SelectItem>();

   //-- Populate list from database

   names.add(new SelectItem(valueObject,"label"));

   //-- setter/getter accessor methods for list

要显示特定的选定记录,它必须是列表中的一个值。

孟承嗣
2023-03-14

根据您的问题历史,您使用的是JSF2。x、 这是一个JSF2。有针对性的回答。在JSF1中。x您将被迫在丑陋的SelectItem实例中包装项目值/标签。幸运的是,在JSF2中不再需要这一点。十、

要直接回答你的问题,只需使用

<h:selectOneMenu value="#{bean.name}">
    <f:selectItems value="#{bean.names}" />
</h:selectOneMenu>

具有

@ManagedBean
@RequestScoped
public class Bean {

    private String name;
    private List<String> names; 

    @EJB
    private NameService nameService;

    @PostConstruct
    public void init() {
        names = nameService.list();
    }

    // ... (getters, setters, etc)
}

就这么简单。实际上,TtoString()将用于表示下拉项标签和值。所以,当你不是列表

另请注意,的bean

<h:selectOneMenu value="#{bean.name}">
    <f:selectItems value="#{data.names}" />
</h:selectOneMenu>

每当T涉及一个复杂的对象(javabean),比如User,它的String属性为name,然后,您可以使用var属性来获取迭代变量,然后您可以在itemValue和/或itemLabel属性中使用该变量(如果省略itemLabel,则标签将与值相同)。

示例#1:

<h:selectOneMenu value="#{bean.userName}">
    <f:selectItems value="#{bean.users}" var="user" itemValue="#{user.name}" />
</h:selectOneMenu>

具有

private String userName;
private List<User> users;

@EJB
private UserService userService;

@PostConstruct
public void init() {
    users = userService.list();
}

// ... (getters, setters, etc)

或者当它有一个Long属性id时,您希望将其设置为项目值:

示例#2:

<h:selectOneMenu value="#{bean.userId}">
    <f:selectItems value="#{bean.users}" var="user" itemValue="#{user.id}" itemLabel="#{user.name}" />
</h:selectOneMenu>

具有

private Long userId;
private List<User> users;

// ... (the same as in previous bean example)

每当你想在bean中将它设置为T属性,并且T代表用户,那么你就需要烘焙一个自定义转换器,它在用户和唯一的字符串表示(可以是id属性)之间进行转换。请注意,itemValue必须表示复杂对象本身,即需要设置为选择组件的值的类型。

<h:selectOneMenu value="#{bean.user}" converter="#{userConverter}">
    <f:selectItems value="#{bean.users}" var="user" itemValue="#{user}" itemLabel="#{user.name}" />
</h:selectOneMenu>

具有

private User user;
private List<User> users;

// ... (the same as in previous bean example)

@ManagedBean
@RequestScoped
public class UserConverter implements Converter {

    @EJB
    private UserService userService;

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

        try {
            return userService.find(Long.valueOf(submittedValue));
        } catch (NumberFormatException e) {
            throw new ConverterException(new FacesMessage(String.format("%s is not a valid User ID", submittedValue)), e);
        }
    }

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

        if (modelValue instanceof User) {
            return String.valueOf(((User) modelValue).getId());
        } else {
            throw new ConverterException(new FacesMessage(String.format("%s is not a valid User", modelValue)), e);
        }
    }

}

(请注意,Converter有点黑客,以便能够在JSF转换器中注入@EJB;通常人们会将其注释为@FacesConverter(forClass=User.class),但不幸的是,这不允许@EJB注入)

不要忘记确保复杂对象类正确实现了equals()hashCode(),否则JSF将在渲染期间无法显示预选项,并且您将在提交时遇到验证错误:值无效。

public class User {

    private Long id;

    @Override
    public boolean equals(Object other) {
        return (other != null && getClass() == other.getClass() && id != null)
            ? id.equals(((User) other).id)
            : (other == this);
    }

    @Override
    public int hashCode() {
        return (id != null) 
            ? (getClass().hashCode() + id.hashCode())
            : super.hashCode();
    }

}

请回答这个问题:为具有Java泛型的实体实现转换器。

JSF实用程序库OmniFaces提供了一种特殊的现成转换器,允许您在

<h:selectOneMenu value="#{bean.user}" converter="omnifaces.SelectItemsConverter">
    <f:selectItems value="#{bean.users}" var="user" itemValue="#{user}" itemLabel="#{user.name}" />
</h:selectOneMenu>
  • 我们的<代码>

 类似资料:
  • 简介 Laravel 可以用 seed 类轻松地为数据库填充测试数据。所有的 seed 类都存放在 database/seeds 目录下。你可以任意为 seed 类命名,但是更应该遵守类似 UsersTableSeeder 的命名规范。Laravel 默认定义的一个 DatabaseSeeder 类。可以在这个类中使用 call 方法来运行其它的 seed 类从而控制数据填充的顺序。 编写 See

  • 问题内容: 我一直在尝试使用从数据库查询的数据加载TableView,但似乎无法使其正常工作。 这是我第一次尝试用数据库查询项填充数据库的情况,以防我的代码看起来杂乱无章,而且效果不佳。 FXML是通过JavaFx SceneBuilder完成的。 这是数据库查询类: 这是通过JavaFx场景生成器生成的FXML脚本: 问题答案: 这是将数据从数据库填充到tableView的最佳解决方案。 这是参

  • 所以我用Java处理这些数据: 我需要将其转换为JSON: 但是我不知道怎么做。 目前我认为这是最好的方法: 但我不确定如何使用Hashmap实现这一点。我知道是这样的: 但确切的语法,以及如何将其与其他数据一起添加,我无法计算。有什么想法吗?

  • 问题内容: 我有一个表格(“场地”),其中存储了志愿者可以工作的所有可能场所,每个志愿者被分配为每个场所工作一个。 我想从场所表中创建一个选择下拉列表。 现在,我可以显示分配给每个志愿者的地点,但是我希望它显示下拉框,并且已经在列表中选择了地点。 例如,将ID为7的志愿者分配给了场地编号4 我知道它将采用for或while循环的形式从场地表中拉出场地列表 我的查询是: 如何填充选择下拉框与场馆(