如何在呈现响应之前处理多个提交?

问题描述 投票:10回答:2

从测试中可以看出,如果响应速度不够快,有时可能会多次按下一个按钮,导致后端代码的多次调用,这是我们不想要的。

应用程序是使用Glassfish 3.1.1中的JSF 2.0的Java EE 6 Web Profile。

我想知道如何正确处理这个问题,并想到了几个场景:

  • 提交应该在呈现响应时使用javascript禁用所有按钮。
  • 会话范围中的一个标志表示它已经处于活动状态,因此会跳过敏感代码,然后继续重新呈现先前提交的响应。
  • 同步块延迟处理直到前一个请求完成。然后应该检测到它已经被处理和跳过。
  • 使用其中一个“新”范围,如转换来处理检测?

我的直觉是,最好的方法是让敏感的代码块原子化,但问题在于呈现正确的响应。

我该怎么做呢?

jsf jsf-2 java-ee-6
2个回答
10
投票

提交应该在呈现响应时使用javascript禁用所有按钮。

这是以通用方式实现的最简单方法。如果您恰好使用<f:ajax>,您可以使用jsf.ajax.addOnEvent()以通用方式执行该作业。另一种JavaScript方法是创建一种“加载”覆盖,它阻止UI,以便最终用户不再能够与底层页面交互。这基本上是一个绝对定位隐藏的<div>,跨越整个视口与一些opacity(透明度)。您可以在提交时显示它并在渲染时隐藏它。这种技术的关键词是"modal dialog"。面向UI的JSF组件库至少已经在它们的组合中具有这样的组件。例如。 PrimeFaces<p:dialog modal="true">内有<p:ajaxStatus>,或<p:blockUI>

唯一的缺点是,如果客户端已禁用JS或不使用它,它将无法工作,因此它不会阻止HTTP客户端进行双重提交。


会话范围中的一个标志表示它已经处于活动状态,因此会跳过敏感代码,然后继续重新呈现先前提交的响应。

这被称为"synchronizer token pattern",并且spec issue 559曾经要求JSF,目前它的目标是2.2,但似乎没有任何活动。检测和阻塞部分在技术上易于实现,但如果您希望最终用户最终检索由初始请求生成的响应,则不容易实现同步响应处理部分。异步响应处理很简单:只是不要指定要更新的任何组件,即清空PartialViewContext#getRenderIds()返回的集合。毕竟,这比使用JS禁用按钮或阻止UI更强大。

据我所知,Seam 2是唯一为此提供可重复使用的JSF组件的人,<s:token>。但我必须承认,对于一个新的OmniFaces组件,这是一个有趣的想法。也许我会亲自看看它。


同步块延迟处理直到前一个请求完成。然后应该检测到它已经被处理和跳过。

这通常不容易实现,这需要更改所有操作方法以检查作业是否已完成。如果webapp在多个服务器上运行,它也将无法工作。同步器令牌比在调用操作方法之前执行更容易。同步器令牌也更便宜,因为您不会在队列中结束多个请求,这只会花费线程/资源。


使用其中一个“新”范围,如转换来处理检测?

通过使用托管bean作用域无法解决此问题。托管bean作用域有不同的用途:bean实例的生命周期。


3
投票

正如Adrian所说,我也会使用BlockUI。 Primefaces有一个BlockUI component。当您通过ajax提交表单时,您还可以在请求期间使用叠加层。有关示例,请参阅Primefaces的Ajax Status

© www.soinside.com 2019 - 2024. All rights reserved.