我们在使用 Wicket 6(即版本 6.22.0)时遇到了问题。看起来这就是这里修复的内容:https://issues.apache.org/jira/browse/WICKET-5068
简而言之:页面过期后,Wicket 尝试通过调用以页面类和 PageParameters
作为参数的构造函数来重建它,但 PageParameters
(错误地)为空,即使一些参数随请求一起发送。
After Wicket session timeout - pageParameters are null似乎与同一个问题有关。
WICKET-5068 已修复 Wicket 7,但我们有 Wicket 6,我们需要对其进行修复。
以下是对我们的发现和一些问题的详细解释。
发生的情况是这样的:
- 用户打开一个页面(有状态)并使其在浏览器选项卡中保持打开状态。
- 用户打开其他页面
- 尽管 session 仍在运行,但第 1 步中的原始页面已从页面存储中逐出(即过期)。
用户返回到初始浏览器选项卡并单击链接。这是链接的代码:
AjaxLink<Void> link = new AjaxLink<Void>("link") { @Override public void onClick(AjaxRequestTarget target) { showWindow(dataModel, window, target); } }; add(link);
当
BookmarkableMapper
根据请求构建IRequestHandler
时,会调用以下方法 (AbstractBookmarkableMapper:294):protected PageParameters getPageParametersForListener(PageInfo pageInfo, PageParameters pageParameters) { if (pageInfo.getPageId() != null) { // WICKET-4594 - ignore the parsed parameters for stateful pages return null; } return pageParameters; }
因此,根据请求构建的
ListenerInterfaceRequestHandler
的PageParameters
为null
。Wicket 开始处理点击。它尝试恢复被单击的链接所属的页面,这是通过以下方法完成的(PageProvider,从第 252 行开始):
private void resolvePageInstance(Integer pageId, Class<? extends IRequestablePage> pageClass, PageParameters pageParameters, Integer renderCount) { IRequestablePage page = null; boolean freshCreated = false; if (pageId != null) { page = getStoredPage(pageId); } if (page == null) { if (pageClass != null) { page = getPageSource().newPageInstance(pageClass, pageParameters); freshCreated = true; } } if (page != null && !freshCreated) { if (renderCount != null && page.getRenderCount() != renderCount) { throw new StalePageException(page); } } pageInstanceIsFresh = freshCreated; pageInstance = page; }
当页面从页面存储中逐出时,以下语句的条件成立:
if (page == null)
因此它尝试从类和页面参数创建页面实例:
page = getPageSource().newPageInstance(pageClass, pageParameters);
但是
pageParameters
在这里是null
(因为第 5 项中的getPageParametersForListener()
)。因此页面构造函数得到空的PageParameters
并失败,因为它需要一些 id。
以下是从页面构造函数中的 PageParameters
中提取 id 的代码:
pageParameters.get("id").toLong()
这是生成的异常(仅显示顶行,因为其余行不相关):
org.apache.wicket.util.string.StringValueConversionException: Unable to convert 'null' to a long value
at org.apache.wicket.util.string.StringValue.toLong(StringValue.java:664)
因此,在我们的例子中,getPageParametersForListener()
方法破坏了恢复过期页面处理的可能性。
为了解决这个问题,我们用自定义实现替换了 BookmarkableMapper
:
public class BookmarkableMapperThatSavesPageParametersForListener extends BookmarkableMapper {
@Override
protected PageParameters getPageParametersForListener(PageInfo pageInfo, PageParameters pageParameters) {
return pageParameters;
}
}
我们在WebApplication#init()
方法中挂载:
mount(new BookmarkableMapperThatSavesPageParametersForListener());
它似乎解决了我们面临的问题:链接点击不会触发处理程序(onClick()
方法),但至少页面不会爆炸,只是自行刷新。
问题是:
- 发生这种情况是因为我们做错了什么还是 Wicket 中的错误?
- 我们应用的修复是否合格?我猜想 https://issues.apache.org/jira/browse/WICKET-4594 引入的变化不只是为了好玩
- 知道我们只有有状态页面,我们的修复是否会破坏任何内容?
最佳答案
这是 Wicket 6.x 的限制,已在 7.x 中实现。 6.x 没有进行此更改,因为我们不确定它是否不会默默地破坏某人的应用程序。 IIRC 如果升级期间需要,可以重写 7.x 中的方法以恢复到旧的行为。 AFAIK 没有人提示 7.x 中的这一变化,所以我想将其向后移植到 6.x (6.27.0) 是可以的,但是 Wicket 的活跃开发人员不再使用 6.x,而且有人这样做的机会是相当低。 建议您升级到7.x。它很稳定,有许多新功能和错误修复。 在那之前,我猜您的选择是使用此请求映射器的自定义版本。
关于java - Wicket 口 6 : empty PageParameters when recreating a page after expiration,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42751254/