У меня есть отчет, в котором отображается информация о зачислении в колледж в расширяемом древовидном формате. При нажатии префикса отображается префикс курса с суммами регистрации и номерами конкретных курсов. Отчет работает нормально, когда он запускается впервые. Если вы решите снова запустить отчет еще на один сеанс, все начнет мешать.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, чтобы я мог позже войти в этот вызов функции.