如何让Tomahawk dataScroller与Hibernate分页协同实现按需加载?
JSF dataScroller 按需分页加载实现(配合Hibernate后端)
完全可以实现这个需求,这正是JSF dataScroller搭配后端分页的标准用法,专门解决大数据量全量加载慢的问题。核心是让dataScroller获取总记录数以生成分页导航,同时每次点击分页按钮时仅加载当前页数据。
核心实现要点
- 使用懒加载数据模型(如PrimeFaces的
LazyDataModel)作为dataTable的数据源,避免全量加载 - 给dataScroller绑定总记录数,让它能计算总页数并生成正确的导航按钮
- 后端通过Hibernate实现分页查询,每次仅返回当前页的记录
代码示例
1. 前端JSF页面(PrimeFaces为例)
<h:form> <p:dataTable id="entityTable" value="#{entityBean.lazyEntityModel}" var="entity" rows="10"> <!-- 自定义列示例 --> <p:column headerText="ID"> <h:outputText value="#{entity.id}" /> </p:column> <p:column headerText="名称"> <h:outputText value="#{entity.name}" /> </p:column> <!-- 其他业务列... --> </p:dataTable> <p:dataScroller for="entityTable" pageCount="#{entityBean.totalRecords}" paginator="true" paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}" rowsPerPageTemplate="10,20,50" /> </h:form>
关键说明:
dataTable的value绑定懒加载模型,而非全量数据列表dataScroller的pageCount绑定总记录数,用于计算分页导航
2. 后端Managed Bean(ViewScoped)
import org.primefaces.model.LazyDataModel; import org.primefaces.model.SortOrder; import javax.faces.bean.ManagedBean; import javax.faces.bean.ViewScoped; import java.util.List; import java.util.Map; @ManagedBean @ViewScoped public class EntityBean { private LazyDataModel<YourEntity> lazyEntityModel; private int totalRecords; private final YourEntityService entityService; // 构造注入Service(或用@Autowired,根据你的DI方式) public EntityBean(YourEntityService entityService) { this.entityService = entityService; initLazyModel(); } private void initLazyModel() { lazyEntityModel = new LazyDataModel<YourEntity>() { @Override public List<YourEntity> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, Object> filters) { // 调用Service获取当前页数据,first是起始索引,pageSize是每页条数 List<YourEntity> pageData = entityService.getPageData(first, pageSize, sortField, sortOrder); // 查询并设置总记录数(如果有过滤条件,这里要传过滤参数重新计算总数) totalRecords = entityService.getTotalRecords(); setRowCount(totalRecords); return pageData; } }; } // Getter方法 public LazyDataModel<YourEntity> getLazyEntityModel() { return lazyEntityModel; } public int getTotalRecords() { return totalRecords; } }
关键说明:
- 必须用
@ViewScoped(或CDI的@ViewScoped),避免每次请求重新初始化懒加载模型 load方法会在用户点击分页按钮时自动触发,传递分页、排序参数
3. Hibernate Service层实现
import org.hibernate.Session; import org.hibernate.query.Query; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import java.util.List; @Service public class YourEntityService { @PersistenceContext private EntityManager entityManager; public List<YourEntity> getPageData(int first, int pageSize, String sortField, SortOrder sortOrder) { Session session = entityManager.unwrap(Session.class); Query<YourEntity> query = session.createQuery("FROM YourEntity", YourEntity.class); // 设置分页参数 query.setFirstResult(first); query.setMaxResults(pageSize); // 处理排序(可选) if (sortField != null && !sortField.isEmpty()) { String orderDirection = sortOrder == SortOrder.ASCENDING ? "ASC" : "DESC"; query = query.addOrder(org.hibernate.criterion.Order.asc(sortField).ignoreCase()); // 或者用JPQL的ORDER BY:query.setQueryString("FROM YourEntity ORDER BY " + sortField + " " + orderDirection); } return query.list(); } public int getTotalRecords() { Session session = entityManager.unwrap(Session.class); Long total = session.createQuery("SELECT COUNT(e) FROM YourEntity e", Long.class).uniqueResult(); return total != null ? total.intValue() : 0; } }
关键说明:
- 用
setFirstResult和setMaxResults实现Hibernate分页,这是Hibernate标准的分页方式 - 总记录数通过
COUNT查询获取,确保dataScroller能正确计算总页数
注意事项
- 如果有查询过滤条件,需要在
load方法中传递过滤参数,同时在getTotalRecords中加入过滤条件重新计算总数 - 避免用
@RequestScoped,否则每次分页请求都会重新创建Bean,导致懒加载模型失效 - 若使用MyFaces等其他JSF组件库,核心逻辑一致,只需替换对应的懒加载模型和dataScroller属性
内容的提问来源于stack exchange,提问作者corneliu
相关产品推荐
相关产品推荐

