JSF嵌套ui:repeat/DataTable问题:子列表无法按行对应显示
解决JSF DataTable嵌套ui:repeat显示全部子列表的问题
这个问题我之前也碰到过,核心问题在于你当前的子列表和DataTable的行没有建立对应关系——你的getList()返回的是完整的差值集合,而ui:repeat在每一行都会遍历整个集合,所以才会每行都显示所有差值。下面给你两个实用的解决方案:
方案一:通过行索引关联差值列表
这种方式不需要修改实体类,只需要在Bean里缓存查询结果,并通过行索引获取对应差值:
1. 修改ReadingBean,缓存数据并添加差值获取方法
首先在Bean中初始化时只查询一次数据库,避免重复查询影响性能,然后添加根据行索引获取对应差值的方法:
import javax.annotation.PostConstruct; import javax.persistence.EntityManager; import javax.inject.Inject; import java.util.ArrayList; import java.util.List; public class ReadingBean { @Inject private EntityManager em; private String name; // 假设这个变量已经正确赋值 private List<Reading> readingData; private List<Double> differences; @PostConstruct public void init() { // 一次性查询数据并缓存 readingData = em.createNamedQuery("Reading.findByMeter") .setParameter("meter", name) .getResultList(); // 预计算所有差值 differences = new ArrayList<>(); for (int i = 1; i < readingData.size(); i++) { double diff = (readingData.get(i).getReading().doubleValue() - readingData.get(i - 1).getReading().doubleValue()) / 50; differences.add(diff); } } public List<Reading> getReadingData() { return readingData; } // 根据行索引获取对应差值(注意行索引从0开始) public Double getDifference(int rowIndex) { // 第一行没有前一个元素,返回null或0,根据你的需求调整 if (rowIndex > 0 && rowIndex <= differences.size()) { return differences.get(rowIndex - 1); } return null; } }
2. 修改JSF页面,使用行索引调用差值方法
在DataTable中通过rowIndexVar获取当前行的索引,然后调用Bean的getDifference()方法:
<h:dataTable value="#{readingBean.readingData}" var="reading" rowIndexVar="rowIdx"> <!-- 显示原Reading的属性列 --> <h:column> <f:facet name="header">Reading Value</f:facet> #{reading.reading} </h:column> <!-- 显示对应差值的列 --> <h:column> <f:facet name="header">Amount Used</f:facet> <!-- 只从第二行开始显示差值 --> <h:outputText value="#{readingBean.getDifference(rowIdx)}" rendered="#{rowIdx > 0}" /> </h:column> </h:dataTable>
方案二:创建DTO关联Reading和差值
如果希望代码更清晰、解耦,可以创建一个DTO类,把Reading对象和对应的差值绑定在一起:
1. 创建ReadingWithDifference DTO类
public class ReadingWithDifference { private Reading reading; private Double difference; public ReadingWithDifference(Reading reading, Double difference) { this.reading = reading; this.difference = difference; } // Getter方法 public Reading getReading() { return reading; } public Double getDifference() { return difference; } }
2. 修改ReadingBean生成DTO列表
import javax.annotation.PostConstruct; import javax.persistence.EntityManager; import javax.inject.Inject; import java.util.ArrayList; import java.util.List; public class ReadingBean { @Inject private EntityManager em; private String name; // 假设已赋值 private List<ReadingWithDifference> readingWithDiffList; @PostConstruct public void init() { List<Reading> readingData = em.createNamedQuery("Reading.findByMeter") .setParameter("meter", name) .getResultList(); readingWithDiffList = new ArrayList<>(); if (!readingData.isEmpty()) { // 第一行没有差值,先添加进去 readingWithDiffList.add(new ReadingWithDifference(readingData.get(0), null)); // 从第二行开始计算并添加差值 for (int i = 1; i < readingData.size(); i++) { double diff = (readingData.get(i).getReading().doubleValue() - readingData.get(i - 1).getReading().doubleValue()) / 50; readingWithDiffList.add(new ReadingWithDifference(readingData.get(i), diff)); } } } public List<ReadingWithDifference> getReadingWithDiffList() { return readingWithDiffList; } }
3. 修改JSF页面遍历DTO列表
<h:dataTable value="#{readingBean.readingWithDiffList}" var="item"> <h:column> <f:facet name="header">Reading Value</f:facet> #{item.reading.reading} </h:column> <h:column> <f:facet name="header">Amount Used</f:facet> #{item.difference} </h:column> </h:dataTable>
为什么原来的代码不行?
你之前的ui:repeat绑定的是#{readingBean.list},这个列表是全局的、和当前行的reading对象没有任何关联,所以DataTable的每一行都会完整遍历整个差值列表,导致所有差值都显示在每一行里。上面的两种方案都是通过建立行与差值的一一对应关系解决了这个问题。
内容的提问来源于stack exchange,提问作者Broken
相关产品推荐
相关产品推荐

