该主题之所以具有"种类的"是因为我在JSF 2.2中有一个例子,我使用commandButton并调用bean函数两次(取决于url)。它基本上是相同的代码,仅在一个示例中执行。
这里是代码"错误"在代码下面:
用户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>
<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。
这是如何引起的?如何解决?
答案 0 :(得分:2)
这是因为#{param['action'] == 'edit'}
在处理表单提交过程中没有评估true
因此在处理表单提交时基本上没有呈现<h:panelGroup>
,包括<h:commandButton>
坐在那里。表单提交即没有将该参数传递回JSF。这样JSF就不会看到<h:commandButton>
,因此永远无法对其动作事件进行解码和排队。在处理表单时,您需要确保所有rendered
条件在显示表单期间评估相同(这是JSF防止篡改/黑客入侵的一部分,否则最终用户将会这样做能够执行未管理的命令按钮,如管理员按钮)。
因此,您基本上需要在回发期间保留该参数,以便在处理表单提交期间rendered
表达式仍然评估true
。这可以通过以下几种方式实现:
在相关<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'
包含句点或代表另一个变量时,这些括号才有用
通过<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>
如果您已经在使用JSF实用程序库OmniFaces,请使用其<o:form>
代替<h:form>
,这样您就可以提交到当前请求URI而不是当前的JSF视图ID。通过这种方式,GET请求字符串将自动保留,您不需要像#1中的所有命令按钮一样<f:param>
:
<o:form useRequestURI="true">
...
</o:form>