为什么要将selectOneMenu的ItemLabel发送到转换器中?

10

我的JSF页面


<h:form>
   <h:selectOneMenu id="studlist" value="#{studBean.selectedStudent}">                   
     <p:ajax event="change" process="studlist" update="studdep" ></p:ajax>
     <f:selectItems value="#{studBean.student}" var="s" 
                    itemValue="#{s.studid}" itemLabel="#{s.name}"/>
     <f:converter   converterId="studentconverter"/>
     </h:selectOneMenu>
</h:form>

转换器类(StudentConverter)


public Object getAsObject(FacesContext context, UIComponent component, String value) {

 Student studConvert= new Student();
 List<Student> students=new ArrayList<Student>();
 students=(ArrayList<Student>)((UISelectItems     
           component.getChildren().get(0)).getValue();
}

在这个转换器上,参数 'String value' 给出了 itemLabel 为什么会发生这种情况?我希望得到这个字符串的 itemValue。

4个回答

19

我不确定为什么你在 getAsObject() 中获取到的是项目标签而不是项目值。也许是因为你的 getAsString() 实现有误,它返回的是学生名称而不是基于学生ID的选项值。

无论如何,我可以肯定地告诉你,你的 itemValue 明显是错误的。

<h:selectOneMenu id="studlist" value="#{studBean.selectedStudent}">  
    <f:selectItems value="#{studBean.student}" var="s" 
        itemValue="#{s.studid}" itemLabel="#{s.name}" />
    <f:converter converterId="studentconverter" />
</h:selectOneMenu>

转换器用于将复杂的Java对象与字符串表示之间进行转换,以便将其作为HTTP请求参数传递。然而,您正在将学生ID指定为项值,而不是整个学生对象。您需要指定整个学生对象。您还应确保#{studBean.selectedStudent}引用学生属性,而不是表示学生ID的某个Long属性。

当您按以下方式修复itemValue时:

<h:selectOneMenu id="studlist" value="#{studBean.selectedStudent}">  
    <f:selectItems value="#{studBean.student}" var="s" 
        itemValue="#{s}" itemLabel="#{s.name}" />
    <f:converter converterId="studentconverter" />
</h:selectOneMenu>

你的转换器应该如下所示(省略了微不足道的空指针检查):

public String getAsString(FacesContext context, UIComponent component, Object value) {
    // This method is called when item value is to be converted to HTTP request parameter.
    // Normal practice is to return an unique identifier here, such as student ID.
    Student student = (Student) value;
    Long id = student.getStudid();
    return String.valueOf(id);
}

public Object getAsObject(FacesContext context, UIComponent component, String value) {
    // This method is called when HTTP request parameter is to be converted to item value.
    // You need to convert the student ID back to Student.
    Long id = Long.valueOf(value);
    Student student = someStudentService.find(id);
    return student;
}

那么它应该能够工作。

另外,你可以保留你最初的itemValue并完全删除<f:converter>,但是这时你必须将 #{studBean.selectedStudent}修改为指向表示学生ID的Long属性。


BalusC,您一如既往的出色!谢谢。 - Mariah

1

h:selectOneMenuf:selecitems属性中,您必须使用selectitem列表。

您的页面将会像这样:

<h:form>   
  <h:selectOneMenu id="studlist" value="#{studBean.selectedStudent}">
     <p:ajax event="change" process="studlist" update="studdep" ></p:ajax>     
     <f:selectItems value="#{studBean.studentSelectItemList}" />     
   <f:converter   converterId="studentconverter"/>     
  </h:selectOneMenu>
</h:form>

在后端Bean中,您需要填充studentSelectItemList selectitem。

private List<SelectItem> studentSelectItemList;

//fill studentSelectItemList at the appropriate place
  studentSelectItemList.add(new SelectItem(studentId,studentName));

完成这些设置后,你应该将学生 ID 设为下拉列表的选项值。


这没有任何区别。 - BalusC

0

BalusC(再次)为我解决了这个问题。 我遇到了同样的问题,正如BalusC之前指出的那样,我的转换器的getAsString()方法返回了我的对象的“firstname”属性。

@Override public String getAsString(FacesContext context, UIComponent component, Object value) {

    if (value == null || value.equals("")) {
        return "";
    }
    else {
        return String.valueOf(((Employee) value).getfirstname());
    }

}

我将其更改为返回ID,然后它按预期工作。

@Override public String getAsString(FacesContext context, UIComponent component, Object value) {

    if (value == null || value.equals("")) {
        return "";
    }
    else {
        return String.valueOf(((Employee) value).getId());
    }

}

BalusC,非常感谢您解释这个理论。您简直是天赐之人!


0

今天我遇到了同样的问题。

这是由于错误的渲染引起的:

<select ...>
    <option>None</option>
    <option value="1">First</option>
    <option value="2">Second</option>
</select>

省略 "None" 选项的 value="" 将导致提交标签而不是空字符串

然而,为了解决这个问题并使渲染器为第一个选项写入value="",只需确保getAsString()永远不返回null,而是返回""(空字符串)。


@BalusC

<h:form id="form">
    ...

    <p:selectOneMenu id="targetStep" value="#{action.targetStep}" required="true">
        <o:converter converterId="omnifaces.ListIndexConverter" list="#{entity.stepList}" />
        <f:selectItems var="step" value="#{entity.stepList}" itemLabel="#{step.name}" 
            itemValue="#{step}" />
    </p:selectOneMenu>

    <p:commandButton process="@this" update="@widgetVar(stepDialog)" 
        oncomplete="PF('stepDialog').show()" icon="#{icons.addStep}" 
        value="#{bundle.addStep}">
        <f:setPropertyActionListener target="#{viewScope.step}"
            value="#{s:newInstance('it.shape.edea2.jpa.WorkflowStep')}" />
    </p:commandButton>

    <p:message for="targetStep" />

    ...
</h:form>

<p:dialog widgetVar="stepDialog" header="#{bundle.addStep}" modal="true" dynamic="true"
    resizable="false">
    <h:form>
        <p:panelGrid columns="2" styleClass="app-full-width">
            <h:outputLabel value="#{bundle.name}" />
            <h:panelGroup>
                <p:inputText id="name" value="#{step.name}" required="true" />
                <p:message for="name" />
            </h:panelGroup>

            ...

            <f:facet name="footer">
                <p:commandButton process="@form" update="@form :form"
                    oncomplete="hideDialog('stepDialog', args)" icon="#{icons.confirm}"
                    value="#{bundle.confirm}">
                    <p:collector value="#{step}" addTo="#{entity.stepList}" />
                    <f:setPropertyActionListener target="#{action.targetStep}"
                        value="#{step}" />
                </p:commandButton>
            </f:facet>
        </p:panelGrid>
    </h:form>
</p:dialog>

你的 omnifaces.ListIndexConverter 来拯救你啦 :)


不同意。如果 #{s.studid} 为空(可能是尚未由服务加载的新学生实例),并且 getAsString() 对于空的 submittedValue 返回 null(很可能是这种情况),则可能会出现这种情况。而这段代码解释了为什么 selectOneMenu 发送 ItemLabel 到转换器。然而,如果我几个小时前就找到了这个问题,我就可以省下那些时间 :) - Michele Mariotti
我知道这不是常见的情况,但有时我会遇到这种场景,用户必须选择一个实体并可以自行扩展选择空间。在更新的答案中有一个真实的用例。 - Michele Mariotti

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接