h:一旦我将它包装在<h:panelgroup rendered =“”> </h:panelgroup>中,commandButton就无法工作

时间:2014-05-19 15:54:13

标签: jsf-2 primefaces facelets jsf-2.2 commandbutton

该主题之所以具有&#34;种类的&#34;是因为我在JSF 2.2中有一个例子,我使用commandButton并调用bean函数两次(取决于url)。它基本上是相同的代码,仅在一个示例中执行。

这里是代码&#34;错误&#34;在代码下面:

用户bean

@ManagedBean
@RequestScoped
public class User {

private String name;
private String surname;
private int age;
private int id;

public String getName() {
    return name;
}
public void setName(String name) {
    this.name = name;
}

public String getSurname() {
    return surname;
}
public void setSurname(String surname) {
    this.surname = surname;
}

public int getAge() {
    return age;
}
public void setAge(int age) {
    this.age = age;
}

public int getId() {
    return id;
}
public void setId(int id) {
    this.id = id;
}

public User(String name, String surname, int age, int id) {
    super();
    this.name = name;
    this.surname = surname;
    this.age = age;
    this.id = id;
}

public User(){}

}

UsersBean bean:

@ManagedBean
@SessionScoped
public class UsersBean {

private List<User> listOfUsers = new ArrayList<User>();
private String passedParameter;

public UsersBean() {
    listOfUsers.add(new User("Tywin", "Lannister", 60, 1));
    listOfUsers.add(new User("Tyrion", "Lannister", 30, 2));
    listOfUsers.add(new User("Jaime", "Lannister", 31, 3));
    listOfUsers.add(new User("Cercei", "Lannister", 29, 4));
    listOfUsers.add(new User("John", "Snow", 31, 5));
}

public List<User> getAll() {

    System.out.println("getAall is called.");
    return listOfUsers;
}

public User getDetails() {
    passedParameter = (String) FacesContext.getCurrentInstance()
            .getExternalContext().getRequestParameterMap().get("userID");
    int id = Integer.parseInt(passedParameter);
    User selected = null;
    for (User u : listOfUsers) {
        if (u.getId() == id) {
            selected = u;
        }
    }
    return selected;
}

public String addUser(User u) {
    System.out.println("addUser is called.");
    if (u.getId() != 0) {
        for (User edit : listOfUsers) {
            if (edit.getId() == u.getId()) {
                System.out.println("Found it!");
                edit.setAge(u.getAge());
                edit.setName(u.getName());
                edit.setSurname(u.getSurname());
            }
        }

    } else {
        u.setId(listOfUsers.size() + 1);
        listOfUsers.add(u);
    }

    return "";
}
}

users.xhtml:

    <f:view>
        <!-- http://stackoverflow.com/questions/8083469/method-must-have-signature-string-method-etc-but-has-signature-void -->
        <h:dataTable value="#{usersBean.all}" var="u">

            <h:column>
                <f:facet name="header">
                    User ID
                </f:facet>
                    #{u.id}
            </h:column>

            <h:column>
                <f:facet name="header">
                    Name
                </f:facet>
                    #{u.name}
            </h:column> 

            <h:column>
                <f:facet name="header">
                    Details
                </f:facet>

                <h:link outcome="users" value="edit user">
                    <f:param name="userID" value="#{u.id}"></f:param>
                    <f:param name="action" value="edit"></f:param>
                </h:link>

                &nbsp;

                <h:link outcome="usersDetails" value="get details">
                    <f:param name="userID" value="#{u.id}"></f:param>
                </h:link>                   
            </h:column> 

        </h:dataTable>

        <h:panelGroup rendered="#{param['action'] == 'edit'}">
            <h1>Edit!</h1>
            <h:form>
                <ui:param name="editUser" value="#{usersBean.details}"></ui:param>
                <h:outputText value="Name"></h:outputText>
                <h:inputText value="#{editUser.name}"></h:inputText> <br />

                <h:outputText value="Surname"></h:outputText>
                <h:inputText value="#{editUser.surname}"></h:inputText> <br />

                <h:outputText value="Age"></h:outputText>
                <h:inputText value="#{editUser.age}"></h:inputText> <br />

                <h:commandButton action="#{usersBean.addUser(editUser)}" value="Edit" type="submit">    </h:commandButton>
            </h:form>
    </h:panelGroup>

        <h:panelGroup rendered="#{empty param['action']}">
            <h1>Add!</h1>
            <h:form>
                <h:outputText value="Name"></h:outputText>
                <h:inputText value="#{user.name}"></h:inputText>
                <h:outputText value="Surname"></h:outputText>
                <h:inputText value="#{user.surname}"></h:inputText>
                <h:outputText value="Age"></h:outputText>
                <h:inputText value="#{user.age}"></h:inputText>
                <h:commandButton action="#{usersBean.addUser(user)}" value="Add" type="submit"></h:commandButton>
            </h:form>
        </h:panelGroup>     

    </f:view>

好的,所以一切都很完美。 usersBean.addUser添加用户。如果我为ID添加另一个inputText并且我输入了现有ID,则相应的函数会更新这些值。因此,addUser函数按预期工作。

问题出在

的情况下
<h:panelGroup rendered="#{param['action'] == 'edit'}">

正如您在上面的xhtml中看到的,代码基本相同,唯一的例外是我填写了所选用户的数据。这有效,我将相应的数据输入到输入字段中,但是当我更改它们并单击编辑时,没有任何反应。该功能未被调用!而在添加的情况下,函数被调用并且它起作用。 看起来似乎在编辑时没有定义任何操作,它只重新加载页面(提交)而没有实际操作addUser。

这是如何引起的?如何解决?

1 个答案:

答案 0 :(得分:2)

这是因为#{param['action'] == 'edit'}在处理表单提交过程中没有评估true因此在处理表单提交时基本上没有呈现<h:panelGroup>,包括<h:commandButton>坐在那里。表单提交即没有将该参数传递回JSF。这样JSF就不会看到<h:commandButton>,因此永远无法对其动作事件进行解码和排队。在处理表单时,您需要确保所有rendered条件在显示表单期间评估相同(这是JSF防止篡改/黑客入侵的一部分,否则最终用户将会这样做能够执行未管理的命令按钮,如管理员按钮)。

因此,您基本上需要在回发期间保留该参数,以便在处理表单提交期间rendered表达式仍然评估true。这可以通过以下几种方式实现:

  1. 在相关<f:param>内添加<h:commandButton>

    <h:commandButton action="#{usersBean.addUser(editUser)}" value="Edit" type="submit">
        <f:param name="action" value="#{param.action}" />
    </h:commandButton>
    

    (注意:param['action']param.action是等效的;只有当'action'包含句点或代表另一个变量时,这些括号才有用

  2. 通过<f:viewParam>将其设置为bean属性。要求是bean需要在视野范围内或更广泛。你已经在会话范围内了,这没关系(but which is IMO way too broad, but that aside):

    <f:metadata>
        <f:viewParam name="action" value="#{usersBean.action}" />
    </f:metadata>
    ...
    <h:panelGroup rendered="#{usersBean.action}">
        ...
    </h:panelGroup>
    
  3. 如果您已经在使用JSF实用程序库OmniFaces,请使用其<o:form>代替<h:form>,这样您就可以提交到当前请求URI而不是当前的JSF视图ID。通过这种方式,GET请求字符串将自动保留,您不需要像#1中的所有命令按钮一样<f:param>

    <o:form useRequestURI="true">
        ...
    </o:form>
    
  4. 另见: