Stu*_*ion 5 jsf primefaces view-scope
我已经使用 JSF 很多年了,在下一个项目中,我们的目标是使 Web 层尽可能无状态。我正在探索的一种可能性是去除@ViewScoped豆子以支持@RequestScoped(@SessionScoped根据需要加上一两个豆子)。这对于带有 AJAX、数据表和条件渲染的复杂页面来说很麻烦。我的问题是:JSF(和 PrimeFaces)与无状态 Web bean 的工作情况如何?这是我应该继续探索的东西,还是@ViewScope现在如此基本以至于不值得付出努力?
我很感激在我写这个问题时它可能会被关闭为“主要基于意见”,但我希望它不是,我对@ViewScope解决的具体问题感兴趣,以及我必须重新解决哪些历史性的解决方法-通过忽略引入@ViewScoped。
JSF(和 PrimeFaces)与无状态 Web Bean 的配合效果如何?
技术上是可行的。
JSF 使用视图状态主要是为了跟踪组件的“禁用”、“只读”和“渲染”属性UIInput以及UICommand“提交的值”、“本地值”和“有效吗?” 组件的状态EditableValueHolder(由其他组件实现UIInput)。
在“disabled”、“readonly”和“rendered”属性的情况下,如果这些属性表示 EL 表达式,那么 JSF 将在处理表单提交请求期间重新检查它。下面是一个基本示例:
<h:form>
<h:commandButton value="toggle" action="#{bean.toggle}">
<f:ajax render="panel" />
</h:commandButton>
<h:panelGroup id="panel">
<h:commandButton value="submit" action="#{bean.submit}" rendered="#{bean.toggled}">
<f:ajax />
</h:commandButton>
</h:panelGroup>
</h:form>
Run Code Online (Sandbox Code Playgroud)
@Named
@ViewScoped
public class Bean implements Serializable {
private static final long serialVersionUID = 1L;
private boolean toggled;
public void toggle() {
this.toggled = !toggled;
}
public void submit() {
System.out.println("Submitted");
}
public boolean isToggled() {
return toggled;
}
}
Run Code Online (Sandbox Code Playgroud)
首先单击“切换”按钮,然后单击“提交”按钮。如果是视图作用域 bean,它会工作得很好。但是,如果您替换@ViewScoped为@RequestScoped此处,那么它将失败,因为toggled默认返回到false此时 JSF 需要在回发请求期间解码“提交”按钮,因此其rendered属性将进行评估false,最终 JSF 不会对操作事件进行排队。
在这种情况下,您需要确保在请求作用域 bean 的(后)构造期间将该属性预先初始化为预期值。一种方法是在 ajax 更新的组件中使用隐藏的输入字段。这是调整后的示例:
<h:form>
<h:commandButton value="toggle" action="#{bean.toggle}">
<f:ajax render="panel" />
</h:commandButton>
<h:panelGroup id="panel">
<input type="hidden" name="toggled" value="#{bean.toggled}" />
<h:commandButton value="submit" action="#{bean.submit}" rendered="#{bean.toggled}">
<f:ajax />
</h:commandButton>
</h:panelGroup>
</h:form>
Run Code Online (Sandbox Code Playgroud)
@Named
@RequestScoped
public class Bean {
@Inject @ManagedProperty("#{param.toggled}")
private boolean toggled;
public void toggle() {
this.toggled = !toggled;
}
public void submit() {
System.out.println("Submitted");
}
public boolean isToggled() {
return toggled;
}
}
Run Code Online (Sandbox Code Playgroud)
注意:
<h:inputHidden>不幸的是,a 将不起作用,因为它仅在操作事件排队后才更新模型值。即使没有就可以immediate="true"了。顺便说一句,这让我产生了为<o:inputHidden>OmniFaces 推出新产品的想法。
有了这些改变,它就会工作得很好。
然而,由于最初属于视图范围的状态(toggled属性)现在已成为请求参数,因此它完全暴露于外界,因此也可以被黑客篡改。想要调用“提交”按钮而不首先调用“切换”按钮的黑客现在可以简单地手动添加请求参数toggled=true。这是否可取取决于应用程序的业务需求,但通常情况下这是完全不可取的。
这就是 JSF 试图通过提供将这些敏感属性放入@ViewScopedbean 中的可能性来保护您免受的影响。
这对于使用 AJAX、数据表和条件渲染的复杂页面来说是很麻烦的
确实如此,但在技术上仍然不是不可能。您只需通过手动填充的隐藏输入字段手动进行分页、排序和过滤状态,如上所示。支持<p:dataTable>将这些状态绑定到 bean 属性。例如:
<p:dataTable ...
first="#{bean.first}"
sortField="#{bean.sortField}"
sortOrder="#{bean.sortOrder}"
filterBy="#{bean.filterBy}">
...
</p:dataTable>
Run Code Online (Sandbox Code Playgroud)
您可以将它们复制到<input type="hidden">前面演示的字段中(您确保已被覆盖<p:ajax update>!),最后通过@ManagedProperty和/或@PostConstruct.
javax.faces.ViewState实际上,您基本上通过这种方式重新发明了当前已经通过隐藏输入字段与@ViewScopedbean结合完成的工作。那么为什么不立即使用它呢?:)
如果您主要关心的是内存使用情况,那么您需要仔细设计您的 bean,以便仅将视图作用域状态存储在 bean 中@ViewScoped,并且仅将请求作用域状态存储在@RequestScopedbean 中。例如,将数据模型放在请求作用域 bean 中并将分页/排序/过滤状态放在视图作用域 bean 中是完全可以的。您可能还需要考虑OmniFaces@ViewScoped,因为它会在页面卸载时立即销毁视图状态和物理 bean。
也就是说,考虑到这个问题,我几个小时前验证并改进了OptimusFaces库,以确保它也完全支持无状态视图<f:view transient="true">以及新的集成测试。OptimusFaces 的优点之一是您不再需要手动担心分页/排序/过滤状态。OptimusFaces 会为您担心。
| 归档时间: |
|
| 查看次数: |
273 次 |
| 最近记录: |