我有一个带有数据表的页面,它是根据查询参数填充的(例如,username
和pagenum
)。表中的每个条目都有一个delete commandButton
当pagenum != 0
和我们点击删除时,在"应用"阶段生成要显示的记录列表。在这个阶段,视图参数还没有设置,所以记录列表是空的,所以没有被删除(我们的delete方法没有被调用)
为了解决这个问题,我添加了一个@PostConstruct
方法,它从Servlet请求中检索查询参数并设置bean中的值,因此当我们获得离开记录列表时它们是可用的,这允许调用我的delete方法。
我确信JSF有更好的方法来处理这种情况,而@PostConstruct
的工作是一个hack。
在不使用视图或会话作用域bean的情况下,实现此场景的正确方法是什么?
肯定有一种方法,只需POST表单和删除适当的记录,而不必浪费时间重新生成记录列表。
在不使用视图或会话作用域bean的情况下,实现此场景的正确方法是什么?当然,必须有一种方法,只需POST表单和删除适当的记录,而不必浪费时间重新生成记录列表
对不起,没有办法。至少在标准<h:dataTable>
中使用标准<h:commandButton>
时不会。这是JSF有状态特性的结果。JSF只是想确保在处理回发期间的视图与生成HTML输出期间的视图完全相同。
这是JSF防止篡改请求的一部分,其中最终用户/黑客可以以这种方式操纵请求参数,从而可以做危险的事情,例如更改条目的ID以删除,或绕过对rendered
属性的检查,等等。如果JSF没有为您做这些事情,那么您无论如何都应该做额外的预验证,并且这些事情很容易被初学者忽略(然后他们会责怪JSF不安全而不是他们自己)。参见为什么JSF在服务器上保存UI组件的状态?和commandButton/commandLink/ajax action/listener方法未调用或输入值未更新。
在<h:dataTable>
中有<h:commandButton>
的情况下,JSF只需要在应用请求值阶段拥有可用的数据模型,这样它就可以遍历组件树中的<h:dataTable>
,以便找到按下的按钮并将动作事件排队。如果没有数据模型,那么它就找不到按下的按钮,动作事件也不会排队。通常,这可以通过将托管bean放在JSF视图作用域中来解决。参见如何选择正确的bean作用域?
对于请求作用域的bean, <f:viewParam>
确实不是在应用请求值阶段之前保存数据模型的正确工具。您需要在@PostConstruct
注释方法中完成这项工作。在JSF托管bean的情况下,请求参数可以通过@ManagedProperty
注入。参见ViewParam vs @ManagedProperty(value = "#{param.id}")。在CDI或Spring托管bean的情况下,没有标准注释可用于将HTTP请求参数作为bean属性注入。对于CDI, JSF实用程序库OmniFaces有一个专门的@Param
。参见OmniFaces @Param
展示。在春天,你需要自己种植。然而,作为非spring用户,我不知道如何做到这一点。谷歌似乎也没有透露太多。
或者,您也可以通过@ViewScoped
将bean放在视图范围中。只要你回发到同一个视图,它就会一直存在。JSF 2.2在javax.faces.view
包中有一个CDI兼容的注释。javax.faces.bean
包中的注释是@ManagedBean
的旧JSF 2.0/2.1注释。Spring对此没有现成的注释,否则就会依赖于JSF API。你需要自己种植。Google给出了几个例子:
实现这个场景的正确方法是什么
在后台bean上执行任何逻辑之前,JSF 总是必须重新构建视图,以便获得关于执行内容的信息。对于显示和更新的目的,最好的(也是正确的)解决方案当然是@ViewScoped
。
不诉诸于视图或会话作用域bean?
如果你坚持使用@RequestScoped
,我想说没有正确的方法,只有变通或hack。一种方法是在您提到的@PostConstruct
方法中初始化列表。另一种方法可能是为删除按钮的onclick
属性使用JavaScript函数。例如,JS函数将使用URL调用服务器以请求删除。或者,你也可以使用PrimeFace的RemoteCommand作为JS函数。