本文介绍了Wicket 6:过期后重新创建页面时清空 PageParameters的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们遇到了 Wicket 6(即 6.22.0 版)的问题.看起来它是在这里修复的:https://issues.apache.org/jira/浏览/WICKET-5068简而言之:在页面过期后,Wicket 尝试通过调用具有页面类和 PageParameters 作为参数的构造函数来重建它,但是 PageParameters 是(错误地)为空即使一些参数随请求一起发送.

We've encountered a problem with Wicket 6 (namely version 6.22.0). It looks like it is what was fixed here: https://issues.apache.org/jira/browse/WICKET-5068In a few words: after the page expires, Wicket tries to reconstruct it by calling a constructor with page class and PageParameters as arguments, but PageParameters is (erroneously) empty even though some parameters were sent with the request.

Wicket 会话超时后 - pageParameters 为空 似乎是与同一个问题有关.

After Wicket session timeout - pageParameters are null seems to be relating to the same issue.

WICKET-5068 对 Wicket 7 进行了修复,但我们有 Wicket 6,我们需要对其进行修复.

WICKET-5068 has a fix for Wicket 7, but we are having Wicket 6 and we need a fix for it.

以下是对我们的发现和一些问题的冗长解释.

Following is a lengthy explanation of our findings and some questions.

这是发生了什么:

  1. 用户打开一个页面(它是有状态的)并在浏览器选项卡中保持打开状态.
  2. 用户打开其他页面
  3. 尽管会话仍在进行,但第 1 步的原始页面已从页面存储中驱逐(即过期).
  4. 用户返回初始浏览器选项卡并单击链接.这是链接的代码:

  1. User opens a page (it is stateful) and leaves it open in a browser tab.
  2. User opens other pages
  3. The original page from step 1 is evicted from Page Store (i.e. gets expired) although the session is still up.
  4. User returns to the initial browser tab and clicks on a link. Here is the code of the link:

AjaxLink<Void> link = new AjaxLink<Void>("link") {
    @Override
    public void onClick(AjaxRequestTarget target) {
        showWindow(dataModel, window, target);
    }
};
add(link);

  • 虽然 BookmarkableMapper 根据请求构建 IRequestHandler,但会调用以下方法 (AbstractBookmarkableMapper:294):

  • While BookmarkableMapper builds IRequestHandler from the request, the following method is called (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.

    So the ListenerInterfaceRequestHandler that is built from the request has null for PageParameters.

    Wicket 开始处理点击.它尝试恢复被点击的链接所属的页面,这是通过以下方法完成的(PageProvider,从第 252 行开始):

    Wicket starts processing the click. It tries to restore the page to which the clicked link belongs, this is done in the following method (PageProvider, starts at line 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;
    }
    

    当页面从页面存储中被逐出时,以下语句的条件成立:

    As the page is evicted from page store, the following statement's condition holds:

    if (page == null)
    

    所以它尝试从类和页面参数创建一个页面实例:

    So it tries to create a page instance from class and page parameters:

    page = getPageSource().newPageInstance(pageClass, pageParameters);
    

    但是 pageParameters 在这里是 null (因为 getPageParametersForListener() 来自第 5 项).所以页面构造函数获取空 PageParameters 并失败,因为它需要一些 id.

    But pageParameters is null here (because of getPageParametersForListener() from item 5). So the page constructor gets empty PageParameters and fails as it expects some id.

    这是从页面构造函数中的 PageParameters 中提取 id 的代码:

    Here is the code to extract an id from PageParameters in the page constructor:

    pageParameters.get("id").toLong()
    

    这是产生的异常(仅显示顶行,因为其余部分不相关):

    Here is the exception that is produced (only showing the top lines as the rest is not relevant):

    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() 方法打破了恢复过期页面处理的可能性.

    So in our case getPageParametersForListener() method breaks a possibility to restore processing of an expired page.

    为了解决这个问题,我们用我们的自定义实现替换了 BookmarkableMapper:

    Trying to fix this, we've replaced the BookmarkableMapper with our custom implementation:

    public class BookmarkableMapperThatSavesPageParametersForListener extends BookmarkableMapper {
        @Override
        protected PageParameters getPageParametersForListener(PageInfo pageInfo, PageParameters pageParameters) {
            return pageParameters;
        }
    }
    

    我们在WebApplication#init()方法中挂载:

    mount(new BookmarkableMapperThatSavesPageParametersForListener());
    

    它似乎解决了我们面临的问题:链接点击不会触发处理程序(onClick() 方法),但至少页面不会爆炸,只会自行刷新.

    It seems to fix the problem we were faced with: the link click does not fire the handler (onClick() method), but at least the page does not explode and just refreshes itself.

    问题是:

    1. 发生这种情况是因为我们做错了什么还是 Wicket 中的错误?
    2. 我们应用的修复是否符合条件?我猜 https://issues.apache.org/jira/browse/引入的变化WICKET-4594 不只是为了好玩
    3. 知道我们只有状态页面,我们的修复是否会破坏任何内容?

    推荐答案

    这是 Wicket 6.x 的限制,已在 7.x 中实现.6.x 没有得到这个改变,因为我们不确定它是否会悄悄地破坏某人的应用程序.如果升级期间需要,IIRC 可以覆盖 7.x 中的方法以恢复到旧行为.AFAIK 没有人抱怨 7.x 中的这一更改,所以我想将其向后移植到 6.x (6.27.0) 是可以的,但是 Wicket 的活跃开发人员都不再使用 6.x,并且有人这样做的机会是比较低.建议您升级到 7.x.它很稳定,并具有许多新功能和错误修复.在此之前,我猜您的选择是使用此请求映射器的自定义版本.

    This is a limitation of Wicket 6.x that has been implemented in 7.x.6.x didn't get this change because we were not sure whether it won't break someone's application silently.IIRC it is possible to override a method in 7.x to revert to the old behavior if needed during upgrade.AFAIK no one complained for this change in 7.x so I guess it is OK to backport it to 6.x (6.27.0) but none of the active developers of Wicket uses 6.x anymore and the chances someone to do it are rather low.You are recommended to upgrade to 7.x. It is stable and has many new features and bug fixes.Until then I guess your option is to use your custom version of this request mapper.

    这篇关于Wicket 6:过期后重新创建页面时清空 PageParameters的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

  • 09-01 20:17