Компонент для итерации и рендеринга вложенной древовидной структуры объекта в JSF

Учитывая определение класса ниже:

public class Comment {

    String username;
    String comment;
    List<Comment> replies;

    // ...
}

Можно ли использовать конструкцию JSF-страницы, которая отображает данные, содержащиеся вComment экземпляр в древовидной структуре, как следует?

Comments
UserOne said
blah blah
----
    UserThree replied
    blah blah blah
    ----
    UserThree replied
    blah blah blah
----
UserTwo said
blah blah
----
UserOne said
blah blah

Ответы на вопрос(2)

Решение Вопроса

Если вложение имеет только один уровень глубины или имеет фиксированное количество максимальной глубины, то вы можете просто вложить компоненты повторителя 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>

I'd for clarity only rename String comment property to message or text orso.

Если вы уже используете JSF 2.x, рассмотрите<my:comments comment="#{bean.comments}"> составной компонент как ниже.

<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;
    }

}

Смотрите также блог на эту тему,рекурсивное дерево составных компонентов.

Вы можете создать новый класс, который обернет комментарий. Это будет иметь комментарий плюс атрибут глубины.

public CommentWithDepth {
   private Comment comment;
   private int depth;

   public CommentWithDepth(Comment comment, int depth) {
      this.comment = comment;
      this.depth = depth;
   }

   public Comment getComment() {
      return comment;
   }
   public int getDepth() {
      return depth;
   }
}

Затем вы создаете список CommentWithDepth со всеми комментариями в правильном порядке, а глубина атрибута - это глубина дерева комментариев (0 для базового уровня, 1 для дочерних элементов базового уровня, 2 для следующего и т. Д. ).

Теперь вы можете использовать пользовательский интерфейс: repeat для визуализации этого списка, используя свойство глубины для определения отступа.

Ваш ответ на вопрос