假设以下组件树:
A有一个私有字段(称为过滤器),对过滤器的引用传递给B和C. 在B类中,通过AjaxLink修改过滤器的属性(因此不进行页面刷新)。 我看到(通过)记录在每次ajax调用wicket之后将序列化A,B和C.
现在,一切正常,单击B中的AjaxLinks将很好地更新过滤器并刷新C并在C中显示正确的信息(基于过滤器)。
但是,假设在B中单击一个AjaxLink,它会将过滤器的属性更新为(例如)值2.然后我按F5,它仍然有效并且页面(及其中的所有组件)被反序列化(和之后再次序列化)。然后我点击一个AjaxLink,将提到的属性的值更改为3;这仍然很好。但是,如果我然后进行页面刷新(F5),则该属性的值突然再次变为2。
似乎在页面刷新时(当wicket将从磁盘加载页面时)wicket正在反序列化旧版本的过滤器。
示意性地:
似乎在操作5中,操作4之后的序列化版本被忽略,并且在操作3之后的序列化版本被加载。
希望找到原因,解释以及可能的解决方案: - )
CODE
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;
}
不确定这个的含义以及为什么这会使它起作用。页面(de)不再序列化了吗?
更新
我在页面课程中添加了以下内容:
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);
}
首先加载页面时会打印出来(实际打印5次,不确定是否正常): 写[Page class = com.bnpp.ecom.homepage.web.Homepage,id = 0,render count = 1]:type = ALL
当我点击AjaxLink'ALL'(将更新过滤器)时,它仍会打印: 写[Page class = com.bnpp.ecom.homepage.web.Homepage,id = 0,render count = 1]:type = ALL
当我点击AjaxLink'DISCUSSIONS'(将更新过滤器)时,它仍会打印: 写[Page class = com.bnpp.ecom.homepage.web.Homepage,id = 0,render count = 1]:type = DISCUSSIONS
当我刷新页面(F5)时,更新了pageid: 写[Page class = com.bnpp.ecom.homepage.web.Homepage,id = 1,render count = 2]:type = DISCUSSIONS
当我点击AjaxLink'ALL'(将更新过滤器)时,它会打印: 写[Page class = com.bnpp.ecom.homepage.web.Homepage,id = 1,render count = 1]:type = ALL
到目前为止一直很好但是当我现在刷新页面(F5)时会打印出来: 阅读[Page class = com.bnpp.ecom.homepage.web.Homepage,id = 0,render count = 1]:type = DISCUSSIONS 写[Page class = com.bnpp.ecom.homepage.web.Homepage,id = 2,render count = 2]:type = DISCUSSIONS
网址永远不会改变,它会保持http://.../?0
因此,它将ID为0的页面反序列化,尽管最后一个已知的页面ID为1,并且忽略了对版本1所做的所有更改(在这种情况下,将类型从DISCUSSIONS切换为ALL)。
在wicket jira中为此创建了一个问题:https://issues.apache.org/jira/browse/WICKET-4360
答案 0 :(得分:1)
观看浏览器的网址刷新页面时。它可能包含Wicket页面版本,因此当您第二次刷新时,将对该页面的特定版本进行反序列化。
由于您将过滤器保留在页面中,因此会对其包含的组件进行序列化/反序列化。
解决方案是将过滤器放入会话中。
答案 1 :(得分:1)
正如jira问题所述:https://issues.apache.org/jira/browse/WICKET-4360您需要将listview上的setreuseitems设置为true,否则当重新填充listview时,ajax调用会弄脏您的页面:
在F5上,Wicket读取(一次)当前页面。但后来它写了一个 由于ListView的使用,页面具有新的页面ID (DataPanel中的PropertyListView)。通过增加 “commentsListView.setReuseItems(真)”;一切都很好。见WICKET-4286 有关ListView问题的讨论。
答案 2 :(得分:0)
在您的日志语句中,它似乎是第五次请求的唯一读数。这可能就是为什么它适用于第一页刷新。
Wicket每次都会序列化页面,但它会将页面的最后一个版本保留在内存中,并且只有在请求以前的版本时才会对其进行反序列化。
如果检查A,B和C组件中的过滤器的hashCode,您可能会在反序列化后看到它们是不同的对象。而不是传递一个Filter,而是传递一个模型,该模型从组件A返回Filter。如果组件A是一个Page,那么它非常简单,因为每个Component都可以调用getPage()。getDefaultModel()或getDefaultModelObject()。如果组件A是Panel,请尝试使用getPage()导航到它.get(“A”)。getDefaultModel()。
我认为如果应用程序使用相同的Filter对象,则序列化无关紧要。