Wicket 6:在到期后重新创建页面时为空PageParameters

时间:2017-03-12 18:16:39

标签: java wicket

我们遇到过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,我们需要修复它。

以下是对我们的调查结果和一些问题的冗长解释。

以下是发生的事情:

  1. 用户打开一个页面(它是有状态的)并在浏览器选项卡中打开它。
  2. 用户打开其他页面
  3. 虽然会话仍在运行,但步骤1中的原始页面已逐出页面存储(即过期)。
  4. 用户返回初始浏览器标签并点击链接。以下是链接的代码:

    AjaxLink<Void> link = new AjaxLink<Void>("link") {
        @Override
        public void onClick(AjaxRequestTarget target) {
            showWindow(dataModel, window, target);
        }
    };
    add(link);
    
  5. 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 nullPageParameters

  6. 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);
    

    但此处pageParametersnull(因为第5项中的getPageParametersForListener())。所以页面构造函数变为空PageParameters并失败,因为它需要一些id。

  7. 以下是在页面构造函数中从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()方法),但至少页面不会爆炸并只刷新自己。

    问题

    1. 这是否因为我们做错了或者是Wicket中的错误而发生?
    2. 我们申请的修订是否合格?我想https://issues.apache.org/jira/browse/WICKET-4594引入的更改不仅仅是为了好玩
    3. 我们的修复是否会破坏任何知道我们只有状态页面的东西?

1 个答案:

答案 0 :(得分:2)

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