2015-12-22 2 views
1

У меня есть отчет, в котором отображается информация о зачислении в колледж в расширяемом древовидном формате. При нажатии префикса отображается префикс курса с суммами регистрации и номерами конкретных курсов. Отчет работает нормально, когда он запускается впервые. Если вы решите снова запустить отчет еще на один сеанс, все начнет мешать.JSF recursive ui: include jumbles output tree on multiple postback

При запуске Report One, это правильно. Когда запускается Report Two (для другого сеанса одни и те же сеансы работают нормально), обратите внимание, что во втором есть дублированные/отсутствующие элементы. Оба этих отчета будут работать правильно, если они запускаются «сначала», т. Е. Никакой другой отчет не был запущен в этом сеансе пользователей.

Я использую рекурсивно включенную страницу для построения дерева. Вот подходящий код из enrollment.xhtml, страница отчета само по себе:

<div id="resultSet" class="treeContainer"> 
    <c:if test="${EnrollmentBean.reportRan}"> 
     <ui:include src="/WEB-INF/includes/reportTree.xhtml"> 
     <ui:param name="nodes" value="#{EnrollmentBean.reportTreeData.getChildren()}" /> 
     <ui:param name="isHidden" value="false" /> 
     </ui:include> 
    </c:if> 
</div> 

Прилагаемый reportTree.xhtml (код расширения дерева сделано с CSS/JQuery) Код:

<ul class="${isHidden ? 'hidden' : ''}"> 
    <c:forEach items="#{nodes}" var="node"> 
     <li><a href="#" class="reportTreeLabel">#{node.getData().getKey()} 
       <span class="reportTreeData">#{node.getData().getValue()}</span> 
      </a> 

      <c:if test="#{node.hasChildren()}"> 
       <ui:include src="/WEB-INF/includes/reportTree.xhtml"> 
       <ui:param name="nodes" value="#{node.getChildren()}" /> 
       <ui:param name="isHidden" value="true" /> 
       </ui:include> 
      </c:if> 
     </li> 
    </c:forEach> 
</ul> 

Соответствующие части из резервная фасоль, EnrollmentBean.java:

@Named("EnrollmentBean") 
@SessionScoped 
public class EnrollmentBean implements Serializable { 
    /** Holds Report Data */ 
    private List< List<String> > reportData; 
    /** Hold Report Data in tree format */ 
    private TreeNode<SimpleEntry<String, Integer>> reportTreeData; 

    private void buildReportTree() { 
     this.reportTreeData = new TreeNode<SimpleEntry<String,Integer>>(); 

     String prefix = ""; 
     Integer prefixEnrollSum = 0;  
     // Stores the tree data for the prefix being processed. Once all the data has been processed, this is added as a child to the reportTreeData field. 
     TreeNode<SimpleEntry<String,Integer>> PrefixTree = null; 
     SimpleEntry<String,Integer> data = null; 

     for (List<String> line : this.reportData) { // for each raw data line 
     String course = line.get(0); 
     Integer enrollments = Integer.parseInt(line.get(1)); 

     if (!prefix.equals(this.getPrefix(course))) { // if the prefix changed since the last line that was processed 
      prefix = this.getPrefix(course); // set the new prefix 

      if (PrefixTree != null) { // if we're not dealing with the very first line of data 
       // set the sum of enrollments gathered for this prefix and reset the counter for the next prefix. 
       PrefixTree.getData().setValue(prefixEnrollSum); 
       prefixEnrollSum = 0; 
      } 

      // prepare a data element for the prefix summary node, then create the node, passing in the data and the parent for this node. 
      data = new SimpleEntry<String,Integer>(prefix, 0); 
      PrefixTree = new TreeNode<SimpleEntry<String,Integer>>(data); 
      this.reportTreeData.addChild(PrefixTree); 
     } // end prefix changed 

     data = new SimpleEntry<String,Integer>(course, enrollments); 
     PrefixTree.addChild(data); 
     prefixEnrollSum += enrollments; 
     } // end for each data line 

     // If there was data to process, upon processing the final row, assign the summed enrollments to the final prefix tree. 
     if (PrefixTree != null) { PrefixTree.getData().setValue(prefixEnrollSum); } 
    } 
} 

класс TreeNode является тот, который я создал, и это обеспечивает простое отслеживание данных, родителей и детей. Я могу опубликовать этот код, если это необходимо, но я считаю, что в настоящее время он лишний.

Во время моего устранения неполадок этой проблемы я проверил отчет. Данные, которые дерево отчетов построено в бэкэнде, всегда верны. Используя класс Logger, я проверил, что дерево генерируется правильно (путем записи на сервер журнала каждой строки, которая обрабатывалась в дереве). Я даже подтвердил, что ReportTreeData верна после каждого запуска, выписав дерево в журнал сервера после того, как было построено дерево.

я могу только сделать вывод, что что-то не так в рендер фазе реагирования жизненного цикла JSF, как я заметил, что если я изменю подкладочный боб от @SessionScoped к @RequestScoped, отчет генерируется правильно каждый раз. Я бы предпочел не использовать это как мое исправление, поскольку у меня есть ссылка «Загрузить CSV», которая использует уже сгенерированные данные отчета в компоненте резервного копирования, поэтому логике отчета не нужно повторно запускать, чтобы генерировать CSV.

Кто-нибудь знает, почему это происходит и что я могу сделать, чтобы исправить это поведение? Я использую JSF 2.2 с Java EE 7 на GlassFish Open Source Edition 4.1 (сборка 13)

UPDATE 12/24/15

Я пошагового визуализации ответа кода фазы JSF и кажется, что выражение EL просто оценивается с неправильными данными во втором прогоне отчета. Я могу видеть, где это делает вызов функции для оценки выражения EL, и он возвращается с неправильными данными. Я попытаюсь получить источник сварки-osgi-bundle.jar, чтобы я мог позже войти в этот вызов функции.

ответ

0

Основываясь на большой части отладки и исследований, но в частности, это answer, я полагаю, что моя проблема имеет какое-то отношение к состоянию представления, которое пытается восстановить, а рекурсия, которую я использую, усложняет структуру JSF для правильно обновить модель дерева компонентов.