0

假设以下组件树:

  • 一种
    • C

A 有一个私有字段(称为过滤器),对过滤器的引用传递给 B 和 C。在 B 类中,过滤器的属性通过 AjaxLink 修改(因此没有页面刷新)。我看到(通过)记录,在每个 ajax 调用之后,wicket 将序列化 A、B 和 C。

现在,一切正常,单击 B 中的 AjaxLinks 将很好地更新过滤器并将刷新 C 并在 C 中显示正确的信息(基于过滤器)。

但是,假设如果单击 B 中的 AjaxLink,它会将过滤器的属性更新为(例如)值 2。然后我按 F5,它仍然可以工作并且页面(以及其中的所有组件)被反序列化(然后再次序列化) )。然后我单击 AjaxLink 将上述属性的值更改为 3;这仍然可以正常工作。但是,如果我随后执行页面刷新 (F5),则该属性的值突然再次变为 2。

似乎在页面刷新时(当 wicket 将从磁盘加载页面时)wicket 正在反序列化旧版本的过滤器。

示意图:

  1. 页面初始加载:
    => filter.value = 3 -> 序列化
  2. AjaxLink:
    => filter.value = 2 -> 序列化
  3. 页面刷新:
    => filter.value = 2 ->反序列化/序列化
  4. AjaxLink:
    => filter.value = 3 -> 序列化
  5. 页面刷新:
    => filter.value = 2 ->反序列化/序列化

似乎在动作 5 上,动作 4 之后的序列化版本被忽略,而动作 3 之后的序列化版本被加载。

希望有原因,解释,如果可能的话还有解决方案:-)

代码

public class A extends Panel { //creates the filter and passes the reference on 
        Filter filter = new Filter(TypeEnum.ALL);

    public A(final String id) {
        super(id);

    add(new B("filterPanel", filter));
    add(new C("datatable", filter));
}



    public class B extends Panel { //updates the filter

        Filter filter;;
        public B(final String id, Filter filter) {
            super(id);
            this.filter = filter;
            add(new IndicatingAjaxLink<Void>("other") {

            @Override
            public void onClick(AjaxRequestTarget target) {
                filter.setType(TypeEnum.OTHER);
                            ...
            }
        };
        }

    }

public class C extends Panel { //uses the filter

    Filter filter;;
    public C(final String id, Filter filter) {
            super(id);
            this.filter = filter;
    }

    public void populateRepeatingView() {
         final List<? extends WallEntry> result = service.find(filter);
         ...
    }    
}

代码已经简化,我只保留了(我假设)相关的东西。

更新

如果我在我的页面类中添加以下内容,那么它可以工作:

@Override
public boolean isVersioned() {
    return false;
}

但是不确定这会产生什么影响以及为什么它会起作用。页面不再(反)序列化了吗?

更新

我在我的 Page 类中添加了以下内容:

private void writeObject(ObjectOutputStream oos) throws IOException { 
oos.defaultWriteObject(); 
System.err.println("Writing " + this + something to print out the type of the filter); 
} 

private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException { 
ois.defaultReadObject(); 
System.err.println("Reading " + this + something to print out the type of the filter); 
} 
  1. 第一次加载页面时会打印(实际上打印了5次,不确定是否正常):编写[Page class = com.bnpp.ecom.homepage.web.Homepage, id = 0, render count = 1]:类型 = 全部

  2. 当我单击 AjaxLink 'ALL' (将更新过滤器)时,它仍然打印:Writing [Page class = com.bnpp.ecom.homepage.web.Homepage, id = 0, render count = 1]: type = ALL

  3. 当我单击 AjaxLink 'DISCUSSIONS'(将更新过滤器)时,它仍然会打印:Writing [Page class = com.bnpp.ecom.homepage.web.Homepage, id = 0, render count = 1]: type = DISCUSSIONS

  4. 当我刷新页面 (F5) 时,pageid 会更新:写入 [Page class = com.bnpp.ecom.homepage.web.Homepage, id = 1, render count = 2]: type = DISCUSSIONS

  5. 当我单击 AjaxLink 'ALL'(将更新过滤器)时,它会打印:Writing [Page class = com.bnpp.ecom.homepage.web.Homepage, id = 1, render count = 1]: type = ALL

  6. 到目前为止一切顺利,但是当我现在刷新页面(F5)时,会打印出来:Reading [Page class = com.bnpp.ecom.homepage.web.Homepage, id = 0, render count = 1]: type = DISCUSSIONS Writing [页面类 = com.bnpp.ecom.homepage.web.Homepage,id = 2,渲染计数 = 2]:type = DISCUSSIONS

网址永远不会改变,它保持http://.../?0

因此它反序列化了 id 为 0 的页面,尽管最后一个已知的页面 id 为 1,并且为版本 1 所做的所有更改都被忽略(在这种情况下,将类型从 DISCUSSIONS 切换为 ALL)。

为此在检票口 jira 中创建了一个问题:https ://issues.apache.org/jira/browse/WICKET-4360

4

3 回答 3

1

刷新页面时观察浏览器的 url。它可能包括 Wicket 页面版本,因此当您第二次刷新时,会反序列化页面的特定版本。

由于您将过滤器保留在页面中,因此它与包含的组件一起被序列化/反序列化。

一个解决方案是将过滤器放入会话中。

于 2012-01-24T13:18:05.523 回答
1

如 jira 问题中所述:https : //issues.apache.org/jira/browse/WICKET-4360 您需要将 listviews 上的 reuseitems 设置为 true,否则当重新填充 listview 时,ajax 调用会弄脏您的页面:

在 F5 Wicket 上读取(一次)当前页面。但是由于使用了ListView(DataPanel中的PropertyListView),它会写入一个具有新页面ID的页面。通过添加“commentsListView.setReuseItems(true);” 一切皆好。有关 ListView 问题的讨论,请参阅WICKET-4286

于 2012-01-27T15:47:45.303 回答
0

在您的日志语句中,它似乎是第五个请求的唯一读数。这可能就是它在第一页刷新时起作用的原因。

Wicket 每次都会序列化页面,但它会将页面的最后一个版本保存在内存中,并且仅在请求先前版本时才对其进行反序列化。

如果您检查 A、B 和 C 组件中过滤器的 hashCode,您可能会发现它们在反序列化后是不同的对象。与其传递过滤器,不如传递一个模型,该模型从组件 A 返回过滤器。如果组件 A 是一个页面,这真的很容易,因为每个组件都可以调用 getPage().getDefaultModel() 或 getDefaultModelObject()。如果组件 A 是面板,请尝试使用 getPage().get("A").getDefaultModel() 导航到它。

我认为如果应用程序使用相同的 Filter 对象,序列化将无关紧要。

于 2012-01-27T03:53:37.503 回答