Пейджинг/пейджер JSF2 для повторителя

Знаете ли вы это чувство, когда каждый написанный вами код работает сразу, и вы недооцениваете свое расписание: -P Это похоже на "о, да, теперь у меня есть время, чтобы сделать его совершенным". То, что я сейчас нахожу ^^

Итак, я реализовал ретранслятор с JSF (ui: repeat), и я подумал о пейджинге для всех объектов. Может быть, простой способ сделать это? О чем я должен думать?

Было бы хорошо, если бы кто-то мне помог. Мои googleskills пока не помогли мне:-P

Приветствие...

Ответы

Ответ 1

Вот простой пример, который должен дать вам представление о том, как реализовать это.

RepeatPaginator:

public class RepeatPaginator {

    private static final int DEFAULT_RECORDS_NUMBER = 2;
    private static final int DEFAULT_PAGE_INDEX = 1;

    private int records;
    private int recordsTotal;
    private int pageIndex;
    private int pages;
    private List<?> origModel;
    private List<?> model;

    public RepeatPaginator(List<?> model) {
        this.origModel = model;
        this.records = DEFAULT_RECORDS_NUMBER;
        this.pageIndex = DEFAULT_PAGE_INDEX;        
        this.recordsTotal = model.size();

        if (records > 0) {
            pages = records <= 0 ? 1 : recordsTotal / records;

            if (recordsTotal % records > 0) {
                pages++;
            }

            if (pages == 0) {
                pages = 1;
            }
        } else {
            records = 1;
            pages = 1;
        }

        updateModel();
    }

    public void updateModel() {
        int fromIndex = getFirst();
        int toIndex = getFirst() + records;

        if(toIndex > this.recordsTotal) {
            toIndex = this.recordsTotal;
        }

        this.model = origModel.subList(fromIndex, toIndex);
    }

    public void next() {
        if(this.pageIndex < pages) {
            this.pageIndex++;
        }

        updateModel();
    }

    public void prev() {
        if(this.pageIndex > 1) {
            this.pageIndex--;
        }

        updateModel();
    }   

    public int getRecords() {
        return records;
    }

    public int getRecordsTotal() {
        return recordsTotal;
    }

    public int getPageIndex() {
        return pageIndex;
    }

    public int getPages() {
        return pages;
    }

    public int getFirst() {
        return (pageIndex * records) - records;
    }

    public List<?> getModel() {
        return model;
    }

    public void setPageIndex(int pageIndex) {
        this.pageIndex = pageIndex;
    }

}

Bean:

public class TestBean {

    private List<String> list;
    private RepeatPaginator paginator;

    @PostConstruct
    public void init() {
        this.list = new ArrayList<String>();
        this.list.add("Item 1");
        this.list.add("Item 2");
        this.list.add("Item 3");
        this.list.add("Item 4");
        this.list.add("Item 5");
        this.list.add("Item 6");
        this.list.add("Item 7");
        this.list.add("Item 8");
        this.list.add("Item 9");
        this.list.add("Item 10");
        this.list.add("Item 11");
        paginator = new RepeatPaginator(this.list);
    }

    public RepeatPaginator getPaginator() {
        return paginator;
    }

}

XHTML:

<ui:composition xmlns="http://www.w3.org/1999/xhtml"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html"
    template="/WEB-INF/template/default.xhtml">

<ui:define name="content">
    <h:form>
        <ui:repeat value="#{testBean.paginator.model}" var="listItem">
            <div>
                <h:outputText value="#{listItem}"/>
            </div>
        </ui:repeat>
        <h:commandButton value="&lt; prev" action="#{testBean.paginator.prev}"/>
        <h:outputText value="#{testBean.paginator.pageIndex} / #{testBean.paginator.pages}"/>
        <h:commandButton value="next &gt;" action="#{testBean.paginator.next}"/>
        <h:inputHidden value="#{testBean.paginator.pageIndex}"/>
    </h:form>
</ui:define>
</ui:composition>

Ответ 2

Разметка на самом деле проста. Вам просто нужно продолжать передавать один или два параметра: firstrow и необязательно rowcount (который также может храниться на стороне сервера). Когда конечный пользователь нажимает "Далее", вы просто увеличиваете значение firstrow со значением rowcount. Когда конечный пользователь нажимает "Назад", вы просто уменьшаете значение firstrow со значением rowcount. Вам нужно только проверить, не превышает ли границы 0 и totalrows и соответственно изменить.

Затем, основываясь на желаемых firstrow и rowcount, вы точно знаете, какие данные должны отображаться. Если все данные уже находятся в некотором List в памяти Java, то вы просто используете List#subList(), чтобы получить подсписок от него для отображения, Однако неэффективно дублировать всю таблицу базы данных в память Java. Это может не нанести вреда, когда он составляет всего 100 строк, но когда он намного больше этого и/или вы дублируете его для каждого отдельного пользователя, то приложение скоро закончится.

В этом случае вы предпочитаете разбивать страницы на уровне DB. Например, в MySQL вы можете использовать предложение LIMIT для получения подмножества результатов из БД. JPA/Hibernate даже предоставляет способы с использованием методов setFirstResult() и setMaxResults() Query и Criteria соответственно. Вы можете найти примеры в этом и этот ответ.

Вы можете найти основной пример JSF 1.2, ориентированный на Google-подобную разбивку на страницы (и сортировку) в в этой статье. Он использует компоненты Tomahawk, но в JSF 2.0 вы можете просто оставить их, сделав bean @ViewScoped (заменяет t:saveState) и используя ui:repeat (заменяет t:dataList).

И последнее, но не менее важное: существует множество библиотек компонентов, которые выполняют все работы в одном компоненте. Например RichFaces <rich:datascroller> и PrimeFaces <p:dataTable paginator="true"> (также может быть сделано ajaxical).