创建新视图时会创建一个全新的视图范围 bean。目标视图保存的视图范围 bean 的实例与表单的初始视图上的 action 方法设置属性的实例不同。
乍一看确实不直观,但这就是视图范围的工作方式。视图范围 bean 的存在时间与视图存在的时间一样长。毕竟是有道理的。
最好的办法是使用<f:param> 而不是<f:setPropertyActionListener>,并让目标视图由<f:viewParam> 设置它。
例如
<h:commandButton value="Edit" action="edit-company.xhtml">
<f:param name="companyId" value="#{company.id}"/>
</h:commandButton>
与
<f:metadata>
<f:viewParam name="companyId" value="#{bean.company}" required="true" />
</f:metadata>
和
@ManagedBean
@ViewScoped
public class Bean {
private Company company;
// ...
}
和
@FacesConverter(forClass=Company.class)
public class CompanyConverter implements Converter {
@Override
public void getAsObject(FacesContext context, UIComponent component, Object value) throws ConverterException {
try {
return companyService.find(Long.valueOf(value));
} catch (Exception e) {
throw new ConverterException(new FacesMessage(
String.format("Cannot convert %s to Company", value)), e);
}
}
// ...
}
作为一种完全不同的替代方案,您也可以通过返回 void 或 null 导航回同一视图并有条件地呈现包含。
<ui:include src="#{bean.editmode ? 'edit' : 'view'}.xhtml" />
但是,如果您需要支持 GET 而不是 POST(顺便说一下,您需要将 <h:commandButton> 替换为 <h:button>),这将不起作用。