【问题标题】:How to stop wicket-9 from throwing StalePageException如何阻止 wicket-9 抛出 StalePageException
【发布时间】:2021-08-12 10:39:13
【问题描述】:

只有在复制页面之前对页面执行了某些 Ajax 操作时,Wicket 才会引发 StalePageException。

可以在此处找到示例 wicket 项目,以及重现异常的步骤。

https://github.com/rjngshn/java-wicket-testing/tree/main

有没有办法确保不抛出这个异常?

谢谢

拉贾尼

【问题讨论】:

  • 您必须使您的页面无状态才能完全摆脱 Stale-Page 问题(即用户操作的页面状态不再是最新的)。无状态检票口组件有一个检票口扩展,包括 ajax 请求,但我不知道这是否仍然适用于当前检票口版本:mvnrepository.com/artifact/org.wicketstuff/…
  • WicketStuff Stateless 自 7.4.0 起已合并到 Apache Wicket
  • 据我从 wicket 文档中了解到,无状态页面主要用于与用户会话无关的地方。尽管可以使测试示例中的页面无状态,但该选项在现实生活中是不可行的。我需要显示登录用户的项目列表。用户可以在提供选择标准后刷新此列表。然后,用户可以使用浏览器提供的“复制”选项复制此页面。如果用户导航到原始页面,则打开副本后,单击任何项​​目以编辑/查看详细信息。抛出 StalePageException。我希望这能澄清我的问题。
  • 我还想提醒您,在提供的示例中,主页是无状态的。
  • 已将最新代码提交到 git。它现在具有 AjaxRequestTarget.IListener 实现,以及“isStateless”的日志记录值,当我测试时,这对于 HomePage 是正确的。

标签: java wicket


【解决方案1】:

Wicket 中提供的默认行为是在 AJAX 请求进入时对其进行排队。假设您有一个带有回调的按钮,该按钮在单击时会执行一些工作并更新 UI。这意味着如果连续快速点击按钮3次,则最后两个请求将在第一个请求完成后排队处理。

一个简单的解决方案是将 AjaxChannel 的行为从排队变为活动。这意味着如果在处理活动(未完成)请求时收到任何 AJAX 请求,它们将被忽略。

那么我们如何在一个地方覆盖 Wicket 的默认行为并确保所有 AjaxChannel 都被修改?我们使用自定义的 AjaxRequestTarget.IListener。

public class ActiveAjaxListener implements AjaxRequestTarget.IListener {
 
 private static final AjaxChannel ACTIVE_CHANNEL = new AjaxChannel(AjaxChannel.DEFAULT_NAME, AjaxChannel.Type.ACTIVE);

 @Override
 public void updateAjaxAttributes(AbstractDefaultAjaxBehavior behavior, AjaxRequestAttributes attributes) {
    attributes.setChannel(ACTIVE_CHANNEL);
 }
}

我们的 ActiveAjaxListener 类将修改每个 AJAX 行为并确保它使用活动通道。要注册它,我们只需将这一行插入到我们的 WebApplication init() 方法中:

getAjaxRequestTargetListeners().add(new ActiveAjaxListener());

(我从https://www.coderdreams.com/wicket-quick-tip-4-change-default-ajaxchannel-to-active/复制了这个解释)

另一种方法是使用面纱来防止通过 JS/CSS 进行双击。有关此方法的更多详细信息,请访问JavaScript / Wicket : How to display an overlay which prevents user interaction

【讨论】:

  • 我的问题与用户在收到响应之前单击按钮无关。如问题中所述,用户单击按钮,收到响应。收到响应后,用户使用浏览器提供的“复制”选项复制当前页面,然后在新选项卡中打开该页面的副本。之后,如果用户返回原始页面并单击按钮,则会引发“StalePageException”。即便如此,我还是尝试了这个建议,按照建议添加了侦听器,导致抛出相同的异常。
  • 在这种情况下,您需要在页面中使用 AjaxNewWindowNotifyingBehavior。此行为将呈现页面的新实例,因此不会影响旧实例的使用。
  • add(new AjaxNewWindowNotifyingBehavior(){ @Override protected void onNewWindow(AjaxRequestTarget target) { System.out.println("HomePage:AjaxNewWindowNotifyingBehavior:onNewWindow" + "render count:" + currentCount); if (currentCount > 1) setResponsePage(HomePage.class); } }); 在浏览器的另一个选项卡中复制页面会增加被复制页面的渲染计数。导航到这个原始页面,即使在页面中添加了建议的行为后,也会继续抛出异常。
  • 这是因为你没有打电话给super.onNewWindow(target);
  • 添加它并没有改变结果。我更改的代码:protected void onNewWindow(AjaxRequestTarget target) { System.out.println("Before calling super.onNewWindow" + "render count:" + currentCount); super.onNewWindow(target); setResponsePage(HomePage.class); } WARN RequestCycleExtra - 处理以下异常|#] org.apache.wicket.core.request.mapper.StalePageException: 请求页面'[Page class= uk.ac.ox.ndph.ckb。 scratch.HomePage, id = 0, render count = 2]' 是用过时的 'renderCount' 制作的。页面将被重新渲染
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-02
相关资源
最近更新 更多