【问题标题】:Deleting from JSF Datatable on a Request Scope Bean从请求范围 Bean 上的 JSF 数据表中删除
【发布时间】:2014-05-05 14:46:29
【问题描述】:

我有一个带有数据表的页面,该数据表是根据查询参数(例如usernamepagenum)填充的。表中的每个条目都有一个删除命令按钮

pagenum != 0 和我们点击删除时,要显示的记录列表是在“应用”阶段生成的。在这个阶段,视图参数没有被设置,所以记录列表是空的,所以什么都没有被删除(我们的删除方法没有被调用)

为了解决这个问题,我添加了一个 @PostConstruct 方法,该方法从 Servlet 请求中检索查询参数并设置 bean 中的值,因此当我们获取离开记录列表时它们可用,这允许我删除方法被调用。

我确信 JSF 有更好的方法来处理这种情况,而 @PostConstruct 的解决方法是一个 hack。

在不使用 View 或 Session 范围的 bean 的情况下,实现此场景的正确方法是什么?

肯定有一种方法可以只发布表单并删除相应的记录,而不必浪费时间重新生成记录列表。

【问题讨论】:

  • 你为什么不想为你的 bean 使用@ViewScoped@SessionScoped 不适合这种情况。
  • 你能发布你的代码吗?正如@LuiggiMendoza 所说,最简单的方法是使用“@ViewScoped”,这将使您能够维护表格的状态。
  • 在这种情况下,将状态存储在服务器中(如在@ViewScoped bean 中)对我来说是违反直觉的。如果我不使用 JSF,那么很容易在每条记录上实现一个表单,提交时会调用适当的代码来删除记录,而无需在服务器上维护任何会话状态。帮助我理解为什么在这里使用@ViewScoped bean 是一件好事。如果用户加载页面、离开并吃午饭、提交删除表单之一,但会话已过期,会发生什么?
  • 或者至少帮助我理解为什么 JSF 在调用 delete 方法之前重建视图时不设置查询参数是有意义的。
  • 在 JSF 1.x 中,Tomahawk 提供了 <t:saveState> 一种方法,可以轻松地将请求范围 bean 转换为视图范围 bean。 Spring 的人们只是跳入各种 hack 或自定义注释,然后指责 JSF 而不是 Spring,因为 Spring 不知道“视图范围”概念。好吧,您的(理论)答案是一个自定义 Spring 注释,它立即注入 HTTP 请求参数,而不是使用 <f:viewParam>。我不能一概而论地详细回答这个问题。

标签: spring jsf jsf-2.2


【解决方案1】:

在不使用 View 或 Session 范围的 bean 的情况下,实现此场景的正确方法是什么?当然必须有一种方法可以只发布表单并删除相应的记录,而不必浪费时间重新生成记录列表

抱歉,没办法。至少在标准<h:dataTable> 中使用标准<h:commandButton> 时不会。这是 JSF 的有状态特性的结果。 JSF 只想确保视图在处理回发期间与生成 HTML 输出期间完全相同。

这是 JSF 针对被篡改请求的保护措施的一部分,其中最终用户/黑客可以操纵请求参数以使其可能做危险的事情,例如更改要删除的条目 ID,或绕过对 rendered 属性的检查等。如果 JSF 没有为您执行此操作并且很容易被初学者忽略,那么您将/应该进行额外预验证的所有这些事情(然后他们会责怪 JSF 不安全而不是他们自己)。另见Why JSF saves the state of UI components on server?commandButton/commandLink/ajax action/listener method not invoked or input value not updated

如果<h:commandButton><h:dataTable> 中,JSF 只需要在应用请求值阶段提供可用的数据模型,以便它可以遍历组件树中的<h:dataTable> 以找到按下的按钮并将动作事件排队。如果没有数据模型,则找不到按下的按钮,动作事件不会排队。通常,这可以通过将托管 bean 放在 JSF 视图范围中来解决。另见How to choose the right bean scope?

对于请求范围的 bean,<f:viewParam> 确实不是在应用请求值阶段发生之前保存数据模型的正确工具。您需要在 @PostConstruct 注释方法中完成这项工作。在 JSF 托管 bean 的情况下,请求参数可以通过@ManagedProperty 注入。另见ViewParam vs @ManagedProperty(value = "#{param.id}")。对于 CDI 或 Spring 托管 bean,没有可用于将 HTTP 请求参数作为 bean 属性注入的标准注释。对于 CDI,JSF 实用程序库 OmniFaces 有一个 @Param 用于此目的。另见OmniFaces @Param showcase。对于 Spring,您需要自己种植。我作为non-Spring-user 不知道该怎么做。谷歌似乎也没有透露太多信息。

或者,您也可以通过@ViewScoped 将bean 放在视图范围内。只要您回发到相同的视图,它就会一直存在。 JSF 2.2 在 javax.faces.view 包中有一个与 CDI 兼容的注解。 javax.faces.bean 包中的一个是 @ManagedBean 的旧 JSF 2.0/2.1 注释。 Spring 对此没有开箱即用的注释,否则会依赖 JSF API。你需要自己在家种植。 Google 显示 several examples

【讨论】:

    【解决方案2】:

    实现这个场景的正确方法是什么

    在支持 bean 上执行任何逻辑之前,JSF总是必须重新构建视图以获取有关要执行的内容的信息。出于显示和更新目的,最好(和正确)的解决方案当然是@ViewScoped

    不使用 View 或 Session 范围的 bean?

    如果您坚持使用@RequestScoped,我想说没有正确 方法,只有变通方法或黑客。一种方法是在 @PostConstruct 方法中初始化列表,就像您提到的那样。另一种方法可能是对删除按钮的onclick 属性使用JavaScript 函数。例如,JS 函数将使用 URL 调用服务器以请求删除。或者,你也可以使用PrimeFace's RemoteCommand作为JS函数。

    【讨论】:

      猜你喜欢
      • 2011-11-11
      • 2011-08-15
      • 1970-01-01
      • 2011-09-02
      • 2014-12-02
      • 2018-10-08
      • 2012-05-26
      • 2013-01-15
      • 2012-01-20
      相关资源
      最近更新 更多