浏览 774 次
|
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
|---|---|
| 作者 | 正文 |
|
最后更新时间:2007-08-28 关键字: JSF
我的系统里采用了左树右表的形式来展示我们的用户界面,点击左树的节点,右边会根据点击的节点生成相应表的数据,使用JSF实现右边的动态生成时(使用同一份代码来满足所有的需求),当在右表页面中点击分页按钮,重新显示右表页面时确出现了如下类似的问题:“在视图中找到了重复的组件 ID "dynform:_id0:_id4"。”。
以下用类似代码来说明这个问题: 1、使用一个页面来模拟我们的左树的点击功能,这个中只有一个按钮,点击它后会生成右边表格显示所需的Bean。 JSP页面(welcome.jsp):
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<f:view>
<body>
<h:form id="welcomeform">
<h:commandButton value="jump" action="#{welcomeForm.execute}"/>
</h:form>
</body>
</f:view>
JAVA代码:
package com.savage.dynweb;
import javax.faces.context.FacesContext;
import javax.faces.el.ValueBinding;
public class WelcomePage {
public String execute() {
DynPage dynPage = new DynPage();
dynPage.init();
FacesContext context = FacesContext.getCurrentInstance();
ValueBinding vb = context.getApplication().createValueBinding("#{requestScope.dynPage}");
vb.setValue(context, dynPage);
return "success";
}
}
faces-config.xml: <managed-bean> <managed-bean-name>welcomeForm</managed-bean-name> <managed-bean-class>com.savage.dynweb.WelcomePage</managed-bean-class> <managed-bean-scope>request</managed-bean-scope> </managed-bean> <navigation-rule> <from-view-id>/pages/test.jsp</from-view-id> <navigation-case> <from-outcome>success</from-outcome> <to-view-id>/pages/dynpage.jsp</to-view-id> </navigation-case> </navigation-rule> 右表页面展示表格中的数据,还有分页按钮,点击分页按钮,使用如下代码模拟: JSP页面(dynpage.jsp):
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<f:view>
<body>
<h:form id="dynform">
<h:dataTable binding="#{dynPage.dynTable }" var="row" value="#{dynPage.records }"/>
<h:commandButton value="next" actionListener="#{dynPage.execute}"/>
</h:form>
</body>
</f:view>
JAVA代码:
package com.savage.dynweb;
import java.util.*;
import javax.faces.application.Application;
import javax.faces.component.*;
import javax.faces.context.FacesContext;
import javax.faces.el.ValueBinding;
import javax.faces.event.ActionEvent;
public class DynPage {
private UIData dynTable;
private List<Map<String, String>> records;
public void init() {
String[] headers = new String[] {"name", "age", "sex", "birthday"};
//由于不想在构造方法做过多的业务,我单独写了个初始化方法,在页面展示前必定先调用这个方法
//虚拟生成数据的代码
records = new ArrayList<Map<String, String>>(10);
for(int i = 0; i < 10; i++) {
Map<String, String> record = new HashMap<String, String>(4);
record.put("name", "name" + i);
record.put("age", "age" + i);
record.put("sex", "sex" + i);
record.put("birthday", "birthday" + i);
records.add(record);
}
FacesContext.getCurrentInstance().getViewRoot().getChildren().clear();
Application app = FacesContext.getCurrentInstance().getApplication();
//以下代码生成页面上要展示的表格内容
dynTable = new UIData();
for(String header : headers) {
UIColumn column = new UIColumn();
UIOutput output = new UIOutput();
ValueBinding vb = app.createValueBinding("#{requestScope.row." + header + "}");
output.setValueBinding("value", vb);
UIOutput facet = new UIOutput();
facet.setValue(header);
column.setHeader(facet);
column.getChildren().add(output);
dynTable.getChildren().add(column);
}
}
public void execute(ActionEvent event) {
init();
}
public UIData getDynTable() {
return dynTable;
}
public void setDynTable(UIData dynTable) {
this.dynTable = dynTable;
}
public List<Map<String, String>> getRecords() {
return records;
}
public void setRecords(List<Map<String, String>> records) {
this.records = records;
}
}
faces-config.xml: <managed-bean> <managed-bean-name>dynPage</managed-bean-name> <managed-bean-class>com.savage.dynweb.DynPage</managed-bean-class> <managed-bean-scope>request</managed-bean-scope> </managed-bean> 就上面的代码,在我从welcome.jsp点击按钮进入dynpage.jsp时,没有任何问题,一切都和我期望的一样,但当我在dynpage.jsp页面中点击了next按钮调用了execute方法后,重新进入dynpage.jsp页面时,确出现了如下异常: java.lang.IllegalStateException: 在视图中找到了重复的组件 ID "dynform:_id0:_id4"。 com.sun.faces.application.StateManagerImpl.checkIdUniqueness(StateManagerImpl.java:201) com.sun.faces.application.StateManagerImpl.checkIdUniqueness(StateManagerImpl.java:204) com.sun.faces.application.StateManagerImpl.checkIdUniqueness(StateManagerImpl.java:204) com.sun.faces.application.StateManagerImpl.saveSerializedView(StateManagerImpl.java:97) com.sun.faces.taglib.jsf_core.ViewTag.doAfterBody(ViewTag.java:189) org.apache.jsp.pages.dynpage_jsp._jspx_meth_f_005fview_005f0(dynpage_jsp.java:104) org.apache.jsp.pages.dynpage_jsp._jspService(dynpage_jsp.java:67) 我自己试了些方法,最终以在DynPage的init()方法中加了如下一个代码解决了问题: FacesContext.getCurrentInstance().getViewRoot().getChildren().clear(); 虽然问题解决了,看了一些书,但对于为何会有这种结果,还是没搞太懂,请们解答下,非常感谢! 我在圈子里发表了这个帖子,没有人恢复,把我郁闷坏了,难道学JSF的人就那么人才凋零,连这种问题都不会吗? 希望这里有人能帮我解答,我很想学好JSF,但一直都JSF的一些东东卡在那,希望能有所突破。 是不是只能去看看JSF的代码了啊? 声明:JavaEye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
|
|
| 返回顶楼 | |
|
最后更新时间:2007-08-29
我想这是生命周期的问题:
在 class WelcomePage 里面 DynPage dynPage = new DynPage(); dynPage.init(); dynPage 是构造了再执行init()的。 当你从welcome.jsp跳到dynpage.jsp,这是正常的。 但是当你再次提交dynpage.jsp的时候,jsf会先恢复视图,然后才执行 public void execute(ActionEvent event) { init(); } 可能在恢复视图的时候自动的执行了一次init(),所以必须加上上面那句话,否则会导致重复创建组件而出错。 我想除了这么想,好像也没其他的可能了。 |
|
| 返回顶楼 | |
|
最后更新时间:2007-08-30
我想也可能是生命周期的问题。
但我想更具体的了解JSF一些内在的机制。 我看了JSF生成的HTML页面,页面好像有个隐藏域,id是com.sun.faces.VIEW,好像是JSF将视图中的所有UI都序列化到了这里,当提交form时,JSF生命周期的第一个阶段是恢复试图,这时它是不是就通过反序列化这个id为com.sun.faces.VIEW的隐藏域中的内容来恢复各个组间的呢。 有无高手讲解下这个内在的处理? 另外还有个问题: 我曾试过将一个inputText的disabled属性通过值binding的形式赋了值,如下: <h:inputText id="next" disabled="#{!dynPage.hasNext}" value=#{dynPage.name}> 结果当我在页面上通过JS将其激活,并提交form时,dynPage的name属性没有被更新为最新的值。 我自己试了几次,好像是只要在JSF渲染响应时UI的disabled属性为true,那么再提交form,那么这些disabled属性为true的UI就不会用最新的值进行更新了,即使你在页面上通过JS将UI激活。 而当commandButton的disabled为true,然后你在页面上用JS将其激活,这时点击这个按钮,那么JSF并不会执行你指定的action、actionListener,而只是简单的重新刷新本页面而已。 JSF中有那么多奇怪的东西,是否有哪个可以帮我们大概讲下其中的一些原理啊? |
|
| 返回顶楼 | |



