При работе с большими наборами данных вам часто нужно представлять данные в постраничном формате. Разбиение на страницы представляет собой интересную проблему, потому что оно имеет тенденцию проходить через все уровни вашего приложения, от уровня представления через приложения приложений до необработанных обращений к вашей базе данных.
Когда дело доходит до извлечения выгружаемых данных, есть несколько довольно хороших решений. Если вы используете JPA, то вы, вероятно, знакомы с
setFirstResult()
и setMaxResult()
доступными в javax.persistence.Query
. Еще лучше проект JPA Spring Data, который предоставляет интерфейсы org.springframework.data.domain.Pageable
и org.springframework.data.domain.Page
для использования непосредственно в ваших репозиториях. В JSF есть также несколько хорошо документированных методов отображения и извлечения выгружаемых данных. Точное решение будет зависеть от набора компонентов, который вы используете, но большинство из них основано на создании пользовательской реализации
javax.faces.model.DataModel
. Например, у MyFaces есть предложения в их вики , RichFaces ведет блог об этой проблеме, а PrimeFaces предоставляют таблицу отложенной загрузки данных . Недавно я пытался разработать что-то, чтобы облегчить бремя разработчика JSF и избавить от необходимости создавать собственные модели данных и вспомогательные компоненты, которые их представляют. Основная идея заключается в том, что компонент JSF создаст отложенную загрузку DataModel от вашего имени, используя выражения EL для извлечения данных по мере необходимости.
Вот пример:
1
2
3
4
5
|
< s:pagedData var = "myDataModel" value="#{userRepository.findByLastName( backingBean.lastName, pageRequest.offset, pageRequest.pageSize)}" pageSize = "20" /> |
Это создаст переменную
myDataModel
которая будет извлекать 20 строк данных одновременно, вызывая userRepository.findByLastName()
. Выражение EL будет вызываться несколько раз при прокрутке DataModel. (Я предполагаю, что вы используете EL 2.2, если вы используете более старый сервер, такой как Tomcat 6, вам может потребоваться установить обновленный el-impl.jar .)
Каждый раз, когда выражение EL вызывается, переменная
pageRequest
становится доступной. Эта переменная предоставляет доступ к следующей контекстной информации, которая может потребоваться при извлечении страницы данных: номер страницы | Номер страницы для отображения |
размер страницы | Запрошенный размер страницы |
смещение | Смещение (первый результат) |
sortColumn | Столбец, используемый для сортировки данных |
Сортировать по возрастанию | Если сортировка в порядке возрастания или убывания |
фильтры | Карта фильтров для применения |
Одна проблема с DataModel, созданной в приведенном выше примере, заключается в том, что общее количество строк неизвестно. Чтобы получить эту информацию, нам нужно предоставить дополнительное выражение:
1
2
3
4
|
< s:pagedData value="#{userRepository.findByLastName( backingBean.lastName,pageRequest.offset, pageRequest.pageSize)}" rowCount = "#{userRepository.countByLastName(backingBean.lastName)}" /> |
В приведенном выше примере также
pageSize
атрибуты var
и pageSize
, при этом будет использоваться размер страницы по умолчанию, pagedData
10, и будет использоваться имя переменной pagedData
. Если вы использовали Spring Data, вы могли заметить, насколько похожа переменная
org.springframework.data.domain.Pageable
интерфейс org.springframework.data.domain.Pageable
. Фактически, пока Spring Data находится на вашем пути к классам, pageRequest
может быть приведен к Pageable
. Кроме того, компонент понимает объект org.springframework.data.domain.Page
поэтому вам больше не нужно выражение rowCount
. Вот пример, который вызывает хранилище данных Spring и представляет данные с использованием компонентов ToFhawk MyFaces. Этот пример также позволяет сортировать данные, щелкая заголовок столбца:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
< s:pagedData value = "#{userRepository.findByLastName(backingBean.lastName, pageRequest)}" /> < t:dataTable value = "#{pagedData}" rows = "#{pagedData.pageSize}" sortColumn = "#{pagedData.sortColumn}" sortAscending = "#{pagedData.sortAscending}" var = "user" > < t:column > < f:facet name = "header" > < t:commandSortHeader columnName = "name" > < h:outputText value = "User Name" /> </ t:commandSortHeader > </ f:facet > < h:outputText value = "#{user.name}" /> </ t:column > < f:facet name = "footer" > < t:dataScroller paginator = "true" paginatorMaxPages = "9" /> </ f:facet > </ t:dataTable > |
И еще одна заключительная хитрость, которая заключается в том, чтобы при использовании PrimeFaces созданная DataModel была совместима с
org.primefaces.model.LazyDataModel
. Здесь тот же пример, что и выше, но с использованием компонентов PrimeFaces:
1
2
3
4
5
6
7
|
< s:pagedData value = "#{userRepository.findByLastName(backingBean.lastName, pageRequest)}" /> < p:dataTable value = "#{pagedData}" rows = "#{pagedData.pageSize}" paginator = "true" lazy = "true" var = "user" > < p:column headerText = "User Name" sortBy = "#{user.name}" > < h:outputText value = "#{user.name}" /> </ p:column > </ p:dataTable > |
Если вы хотите взглянуть на любой код для этого, он доступен на GitHub (посмотрите пакеты
org.springframework.springfaces.page.ui
и org.springframework.springfaces.model
). У меня также есть базовый пример приложения с разметкой страницы . Как всегда, этот код является движущейся целью, поэтому вы можете столкнуться с некоторыми проблемами при запуске демонстраций. Ссылка: Интеграция Spring & JavaServer Faces: Пагинация от нашего партнера по JCG Филиппа Уэбба в блоге Фила Уэбба в блоге.