如果嵌套只有一个级别深,或具有最大深度的一个固定的量,那么你可以只窝JSF中继器部件一样在对方<ui:repeat>
或<h:dataTable>
通常的方式。
<ul>
<ui:repeat value="#{bean.comments}" var="comment">
<li>#{comment.username} #{comment.comment}
<ul>
<ui:repeat value="#{comment.replies}" var="reply">
<li>#{reply.username} #{reply.comment}</li>
</ui:repeat>
</ul>
</li>
</ui:repeat>
</ul>
但是,如果嵌套层次是“无限的”,那么你需要一个JSF组件,而不是它可以呈现树状分层结构。这在标准的JSF组件集中不可用。您需要查看第三方组件库,例如PrimeFaces<p:tree>
或RichFaces<rich:tree>
或OmniFaces<o:tree>
。 OmniFaces可以让你完全控制树形标记,而对于其他人来说,你可能需要摆弄一些好的CSS来让它看起来像你想要的。
<o:tree value="#{bean.comments}" var="comment">
<o:treeNode>
<ul>
<o:treeNodeItem>
<li>#{comment.username} #{comment.comment}
<o:treeInsertChildren />
</li>
</o:treeNodeItem>
</ul>
</o:treeNode>
</o:tree>
我愿意为清楚起见,仅String comment
属性重命名为message
或text
公积金。
如果您已经使用JSF 2.x,请考虑下面的<my:comments comment="#{bean.comments}">
composite component。
<cc:interface componentType="commentsComposite">
<cc:attribute name="comment" type="com.example.Comment" required="true" />
</cc:interface>
<cc:implementation>
<c:if test="#{not empty cc.comment.replies}">
<ul>
<c:forEach items="#{cc.comment.replies}" var="comment" varStatus="loop">
<li>
#{comment.username} #{comment.comment}
<my:comments comment="#{cc.parent.comment.replies[loop.index]}" />
</li>
</c:forEach>
</ul>
</c:if>
</cc:implementation>
@FacesComponent("commentsComposite")
public class CommentsComposite extends UINamingContainer {
private Comment comment;
@Override
public void setValueExpression(String name, ValueExpression expression) {
if ("comment".equals(name)) {
setComment((Comment) expression.getValue(getFacesContext().getELContext()));
}
else {
super.setValueExpression(name, expression);
}
}
public Comment getComment() {
return comment;
}
public void setComment(Comment comment) {
this.comment = comment;
}
}
又见关于这一主题的博客,recursive tree of composite components。