Русский English Тэги View Sergey Zolotaryov's profile on LinkedIn Вход
Простой пейджинг с JSP
Постоянная ссылка 25-04-2008 anydoby java

Каждый раз, когда вознимает вопрос о постраничной разбивке результатов приходится сталкиваться с одной и той же проблемой - как красиво нарисовать стрелочки, вывести номера страниц и т.д. Недавно написал наконец тэг, который делает это с минимальными усилиями. Первое, что нам нужно, это объект, в котором будут находиться данные для пейджинга и информация о максимальном размере страницы и общем объеме результатов:


package com.anydoby.dao;

import java.util.List;

/**
 * @author SergeyZ
 */
public class ListPage<T> {

    private int page;

    private List<T> data;

    private int total;

    private int maxPerPage;

    public ListPage(List<T> data, int page, int total, int maxPerPage) {
        this.data = data;
        this.page = page;
        this.total = total;
        this.maxPerPage = maxPerPage;
    }

    public int getPage() {
        return page;
    }

    public void setPage(int page) {
        this.page = page;
    }

    public List<T> getData() {
        return data;
    }

    public void setData(List<T> data) {
        this.data = data;
    }

    public int getTotal() {
        return total;
    }

    public void setTotal(int total) {
        this.total = total;
    }

    public int getMaxPerPage() {
        return maxPerPage;
    }

    public void setMaxPerPage(int maxPerPage) {
        this.maxPerPage = maxPerPage;
    }

}

Тривиальная обертка списка с необходимой нам информацией: data - список с результатами, page - текущий индекс страницы (начиная с 0), total - сколько всего результатов в выборке (не меньше, чем длина списка), maxPerPage - максимальное число результатов, выводимое на странице.

А теперь пишем тэг, который будет отображать индексы страниц со ссылками на них:


package com.anydoby.utils;

import java.io.IOException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.jsp.JspContext;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.SimpleTagSupport;

import com.anydoby.spingmvc.dao.ListPage;

/**
 * @author SergeyZ
 */
public class PagerTag extends SimpleTagSupport {

    @SuppressWarnings("unchecked")
    private ListPage page;

    private String pageParam;

    public String getPageParam() {
        return pageParam;
    }

    public void setPageParam(String pageParam) {
        this.pageParam = pageParam;
    }

    @SuppressWarnings("unchecked")
    public ListPage getPage() {
        return page;
    }

    @SuppressWarnings("unchecked")
    public void setPage(ListPage page) {
        this.page = page;
    }

    @Override
    public void doTag() throws JspException, IOException {
        StringBuffer requestURL = getRequestUrl();

        int pagesTotal = page.getTotal() / page.getMaxPerPage();
        if (page.getTotal() % page.getMaxPerPage() != 0) {
            pagesTotal++;
        }

        if (pagesTotal > 1) {
            int startOfPageParam = requestURL.indexOf(pageParam + "=");
            if (startOfPageParam != -1) {
                int endOfPageParam = requestURL.indexOf("&", startOfPageParam + pageParam.length());
                if (endOfPageParam == -1) {
                    endOfPageParam = requestURL.length();
                }
                requestURL.delete(startOfPageParam, endOfPageParam);
            }
            char lastQueryChar = requestURL.charAt(requestURL.length() - 1);
            if (lastQueryChar != '?' && lastQueryChar != '&') {
                requestURL.append('&');
            }
            requestURL.append(pageParam).append('=');
            String url = requestURL.toString();
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < pagesTotal; i++) {
                if (page.getPage() != i) {
                    sb.append("<a href=\"").append(url).append(i).append("\">");
                    sb.append(i + 1);
                    sb.append("</a> ");
                } else {
                    sb.append("<b>");
                    sb.append(i + 1);
                    sb.append("</b> ");
                }
            }

            getJspContext().getOut().append(sb.toString());
        }
    }

    private StringBuffer getRequestUrl() {
        StringBuffer construct = construct(getJspContext(), "javax.servlet.forward.");
        if (construct == null) {
            construct = construct(getJspContext(), "javax.servlet.include.");
        }
        if (construct == null) {
            PageContext ctx = (PageContext) getJspContext();
            HttpServletRequest request = (HttpServletRequest) ctx.getRequest();
            construct = request.getRequestURL();
            construct.append('?');
            if (request.getQueryString() != null) {
                construct.append(request.getQueryString());
            }
        }
        return construct;
    }

    private StringBuffer construct(JspContext context, String prefix) {
        Object uri = context.getAttribute(prefix + "request_uri", PageContext.REQUEST_SCOPE);
        if (uri != null) {
            Object ctxPath = context.getAttribute(prefix + "context_path", PageContext.REQUEST_SCOPE);
            Object servletPath = context.getAttribute(prefix + "servlet_path", PageContext.REQUEST_SCOPE);
            Object pathInfo = context.getAttribute(prefix + "path_info", PageContext.REQUEST_SCOPE);
            Object query = context.getAttribute(prefix + "query_string", PageContext.REQUEST_SCOPE);
            StringBuffer buffer = new StringBuffer();
            buffer.append(ctxPath).append(servletPath);
            if (pathInfo != null) {
                buffer.append(pathInfo);
            }
            buffer.append('?');
            if (query != null) {
                buffer.append(query);
            }
            return buffer;
        }
        return null;
    }

}

В коде тэга учитывается, что сам тэг может использоваться на вложенной странице (через dispatch или include) и корректно определяется тот путь, который человек видит в браузере.

И вот кусочек taglib.tld, который нужно поместить в WEB-INF/tags:


<?xml version="1.0" encoding="UTF-8" ?>

<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
  version="2.0">
   <tlib-version>1.0</tlib-version>
   <short-name>r</short-name>
   <uri>http://anydoby.com/simpletags</uri>
   <tag>
      <description>
        Prints a simple pager
      </description>
      <name>pager</name>
      <tag-class>com.anydoby.utils.PagerTag</tag-class>
      <body-content>empty</body-content>
      <attribute>
        <name>page</name>
        <required>true</required>
        <rtexprvalue>true</rtexprvalue>
        <type>com.anydoby.dao.ListPage</type>
      </attribute>
      <attribute>
        <name>pageParam</name>
        <required>true</required>
        <type>java.lang.String</type>
      </attribute>      
   </tag>
</taglib>

в JSP странице этот тэг будет выглядеть вот так:


<%@ taglib prefix="r" uri="http://anydoby.com/simpletags" %>

... results displayed ...

<r:pager page="${results}" pageParam="page"/>

Тэг конструирует ссылки с текущим url (сохраняя все параметры запроса) и добавляет к нему параметр page (или любой другой по вашему усмотрению), в котором содержится нужный индекс страницы.

Добавить комментарий

Предыдущая статья DWR 2.0.3 не работает со Spring 2.5 Следующая статья Как заставить IE не кэшировать страницы