Wicket 6:过期后重新创建页面时清空 PageParameters
Wicket 6: empty PageParameters when recreating a page after expiration
我们遇到了 Wicket 6(即版本 6.22.0)的问题。看起来这是这里修复的:https://issues.apache.org/jira/browse/WICKET-5068
简而言之:页面过期后,Wicket 尝试通过以页面 class 和 PageParameters
作为参数调用构造函数来重建它,但是 PageParameters
是(错误地)空的,即使一些参数随请求一起发送。
After Wicket session timeout - pageParameters are null 似乎与同一问题有关。
WICKET-5068 修复了 Wicket 7,但我们有 Wicket 6,我们需要修复它。
以下是对我们的发现和一些问题的详细解释。
事情是这样的:
- 用户打开一个页面(它是有状态的)并在浏览器选项卡中保持打开状态。
- 用户打开其他页面
- 步骤 1 中的原始页面已从页面存储中逐出(即过期),尽管会话仍在进行中。
用户 returns 到初始浏览器选项卡并单击 link。这是 link:
的代码
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
具有 null
for PageParameters
。
Wicket 开始处理点击。它尝试恢复被点击的 link 所属的页面,这是通过以下方法完成的(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)
因此它尝试从 class 和页面参数创建页面实例:
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());
它似乎解决了我们面临的问题:link 单击不会触发处理程序(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 的活跃开发者的 none 使用 6.x 并且有人这样做的机会相当低。
建议升级到7.x。它很稳定,有许多新功能和错误修复。
在那之前,我想您的选择是使用此请求映射器的自定义版本。
我们遇到了 Wicket 6(即版本 6.22.0)的问题。看起来这是这里修复的:https://issues.apache.org/jira/browse/WICKET-5068
简而言之:页面过期后,Wicket 尝试通过以页面 class 和 PageParameters
作为参数调用构造函数来重建它,但是 PageParameters
是(错误地)空的,即使一些参数随请求一起发送。
After Wicket session timeout - pageParameters are null 似乎与同一问题有关。
WICKET-5068 修复了 Wicket 7,但我们有 Wicket 6,我们需要修复它。
以下是对我们的发现和一些问题的详细解释。
事情是这样的:
- 用户打开一个页面(它是有状态的)并在浏览器选项卡中保持打开状态。
- 用户打开其他页面
- 步骤 1 中的原始页面已从页面存储中逐出(即过期),尽管会话仍在进行中。
用户 returns 到初始浏览器选项卡并单击 link。这是 link:
的代码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
具有null
forPageParameters
。Wicket 开始处理点击。它尝试恢复被点击的 link 所属的页面,这是通过以下方法完成的(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)
因此它尝试从 class 和页面参数创建页面实例:
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());
它似乎解决了我们面临的问题:link 单击不会触发处理程序(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 的活跃开发者的 none 使用 6.x 并且有人这样做的机会相当低。 建议升级到7.x。它很稳定,有许多新功能和错误修复。 在那之前,我想您的选择是使用此请求映射器的自定义版本。