JSF 递归 ui:在多个回发中包含混乱的输出树

Posted

技术标签:

【中文标题】JSF 递归 ui:在多个回发中包含混乱的输出树【英文标题】:JSF recursive ui:include jumbles output tree on multiple postback 【发布时间】:2016-03-29 08:06:07 【问题描述】:

我有一份报告,它以可展开的树形格式显示大学课程注册信息。单击前缀时,它会显示带有摘要注册号的课程前缀和特定的课程注册号。该报告在首次运行时运行良好。但是,如果您决定为下一个会话再次运行报告,事情就会变得一团糟。

Report One 运行时是正确的。当Report Two 运行时(对于不同的会话,相同的会话运行正常),请注意第二个有重复/缺失的元素。如果这两个报告“首先”运行,即在该用户会话中没有运行其他报告,则这两个报告都将正常工作。

我正在使用递归包含的页面来构建树。这是来自于报告页面本身的注册.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>

支持bean的相关部分,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 类是我创建的,它提供了对数据、父级和子级的简单跟踪。如果需要,我可以发布该代码,但我认为此时它是多余的。

在我对这个问题进行故障排除期间,我已经验证了在支持 bean 中构建报告树的 reportData 始终是正确的。通过使用 Logger 类,我验证了树的生成是否正确(通过将正在处理到树中的每一行写入服务器日志)。我什至通过在构建树后将树写入服务器日志来验证每次运行后 reportTreeData 是否正确。

我只能得出结论,JSF 生命周期的渲染响应阶段出了点问题,因为我确实注意到,如果我将支持 bean 从 @SessionScoped 更改为 @RequestScoped,则每次都会正确生成报告。我宁愿不将此作为我的解决方案,因为我有一个“下载 CSV”链接,该链接使用支持 bean 中已经生成的报告数据,因此报告逻辑不需要重新运行来生成 CSV。

有谁知道为什么会发生这种情况以及我可以做些什么来纠正这种行为?我在 GlassFish Open Source Edition 4.1(内部版本 13)上使用 JSF 2.2 和 Java EE 7

2015 年 12 月 24 日更新

我一直在逐步完成呈现响应阶段的 JSF 代码,似乎在第二次运行报表时,正在使用错误的数据评估 EL 表达式。我可以看到它在哪里调用函数来评估 EL 表达式,并且它返回了错误的数据。我将尝试获取weld-osgi-bundle.jar 源代码,以便以后可以进入该函数调用。

【问题讨论】:

【参考方案1】:

基于大量调试和研究,特别是 answer,我认为我的问题与试图恢复的视图状态有关,并且我使用的递归使 JSF 框架变得困难正确更新组件树模型。

【讨论】:

以上是关于JSF 递归 ui:在多个回发中包含混乱的输出树的主要内容,如果未能解决你的问题,请参考以下文章

带有 ui:define 的 JSF2.0 部分渲染

在JSF中包含级联样式表(CSS)

JSF 组件绑定 - 一些混乱

在每次 JSF ajax 回发后执行 JavaScript

如何在 ARM 模板中包含外部逻辑应用实现

使用 JSF 2.2 时在每个回发请求上重新创建 @ViewScoped bean