Java tutorial
/* * * * Copyright 2015-2016 the original author or authors. * * * * Licensed under the Apache License, Version 2.0 (the "License"); * * you may not use this file except in compliance with the License. * * You may obtain a copy of the License at * * * * http://www.apache.org/licenses/LICENSE-2.0 * * * * Unless required by applicable law or agreed to in writing, software * * distributed under the License is distributed on an "AS IS" BASIS, * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * * See the License for the specific language governing permissions and * * limitations under the License. * */ package com.yqboots.web.thymeleaf.processor.element; import org.apache.commons.lang3.StringUtils; import org.springframework.data.domain.Page; import org.thymeleaf.Arguments; import org.thymeleaf.Configuration; import org.thymeleaf.context.IWebContext; import org.thymeleaf.dom.Element; import org.thymeleaf.dom.Node; import org.thymeleaf.dom.Text; import org.thymeleaf.processor.element.AbstractMarkupSubstitutionElementProcessor; import org.thymeleaf.spring4.processor.attr.SpringHrefAttrProcessor; import org.thymeleaf.standard.expression.IStandardExpression; import org.thymeleaf.standard.expression.IStandardExpressionParser; import org.thymeleaf.standard.expression.StandardExpressions; import java.util.ArrayList; import java.util.List; /** * The element processor which generates the paged elements, such as first/previous/next/last buttons, pages button, etc. * * @author Eric H B Zhan * @since 1.0.0 */ public class PaginationElementProcessor extends AbstractMarkupSubstitutionElementProcessor { public static final String ATTR_PAGE = "page"; private static final int DEFAULT_STEPS = 5; public PaginationElementProcessor() { super("pagination"); } /** * Gets the pagination url based on the context path. * * @param contextPath current context path of servlet * @param page the result page number * @param size the size per page * @return the url */ private static String getPagedParams(final String contextPath, final int page, final int size) { final StringBuilder sb = new StringBuilder(contextPath); // can contain params, as it should be if (contextPath.contains("?")) { sb.append("&"); } else { sb.append("?"); } sb.append("page=").append(page).append("&size=").append(size); return sb.toString(); } /** * {@inheritDoc} */ @Override public int getPrecedence() { // process after SpringHrefAttrProcessor return SpringHrefAttrProcessor.ATTR_PRECEDENCE + 10; } /** * {@inheritDoc} */ @Override protected List<Node> getMarkupSubstitutes(final Arguments arguments, final Element element) { final List<Node> nodes = new ArrayList<>(); final Configuration configuration = arguments.getConfiguration(); // Obtain the attribute value final IWebContext context = (IWebContext) arguments.getContext(); final String contextPath = StringUtils.defaultIfEmpty( element.getAttributeValue(SpringHrefAttrProcessor.ATTR_NAME), context.getServletContext().getContextPath()); // Obtain the Thymeleaf Standard Expression parser final IStandardExpressionParser parser = StandardExpressions.getExpressionParser(configuration); // Parse the attribute value as a Thymeleaf Standard Expression final String pageAttrValue = element.getAttributeValue(ATTR_PAGE); final IStandardExpression expression = parser.parseExpression(configuration, arguments, pageAttrValue); Page<?> page = (Page<?>) expression.execute(configuration, arguments); final Element container = new Element("ul"); container.setAttribute("class", "pagination"); container.addChild(getFirstElement(page, contextPath)); container.addChild(getPreviousElement(page, contextPath)); addStepElements(page, contextPath, container); container.addChild(getNextElement(page, contextPath)); container.addChild(getLastElement(page, contextPath)); nodes.add(container); return nodes; } /** * Adds elements for steps. * * @param page the pagination object * @param contextPath current context path of servlet * @param container the container node of the element */ private void addStepElements(final Page<?> page, final String contextPath, final Element container) { for (int step = 0; step < DEFAULT_STEPS; step++) { // beyond total pages is not allowed if (page.getTotalPages() < step + 1) { continue; } String url; int stepValue; if ((page.getNumber() + DEFAULT_STEPS) <= page.getTotalPages()) { // calculate by page number url = getPagedParams(contextPath, page.getNumber() + step, page.getSize()); stepValue = page.getNumber() + step + 1; } else if (page.getTotalPages() < DEFAULT_STEPS && page.getTotalPages() >= step + 1) { // between step and DEFAULT_STEPS url = getPagedParams(contextPath, step, page.getSize()); stepValue = step + 1; } else { // calculate by totalPages url = getPagedParams(contextPath, page.getTotalPages() - DEFAULT_STEPS + step, page.getSize()); stepValue = page.getTotalPages() - DEFAULT_STEPS + step + 1; } final Element a = new Element("a"); a.setAttribute("href", url); a.addChild(new Text(Integer.toString(stepValue))); final Element li = new Element("li"); li.addChild(a); // set active if (page.getNumber() + 1 == stepValue) { li.setAttribute("class", "active"); } container.addChild(li); } } /** * Gets the link node of the first page. * * @param page the pagination object * @param contextPath current context path of servlet * @return the node */ private Element getFirstElement(final Page<?> page, final String contextPath) { final Element result = new Element("li"); final Element a = new Element("a"); a.setAttribute("href", getPagedParams(contextPath, 0, page.getSize())); result.addChild(a); final Element icon = new Element("i"); icon.setAttribute("class", "glyphicon glyphicon-step-backward"); a.addChild(icon); if (page.isFirst()) { result.setAttribute("class", "disabled"); } return result; } /** * Gets the link node of the previous page. * * @param page the pagination object * @param contextPath current context path of servlet * @return the node */ private Element getPreviousElement(final Page<?> page, final String contextPath) { final Element result = new Element("li"); String url; if (!page.hasPrevious()) { url = getPagedParams(contextPath, 0, page.getSize()); } else { url = getPagedParams(contextPath, page.getNumber() - 1, page.getSize()); } final Element a = new Element("a"); a.setAttribute("href", url); result.addChild(a); final Element icon = new Element("i"); icon.setAttribute("class", "glyphicon glyphicon-triangle-left"); a.addChild(icon); if (!page.hasPrevious()) { result.setAttribute("class", "disabled"); } return result; } /** * Gets the link node of the next page. * * @param page the pagination object * @param contextPath current context path of servlet * @return the node */ private Element getNextElement(final Page<?> page, final String contextPath) { final Element result = new Element("li"); String url; if (!page.hasNext()) { int pageNumber = page.getTotalPages() - 1; url = getPagedParams(contextPath, pageNumber < 0 ? 0 : pageNumber, page.getSize()); } else { url = getPagedParams(contextPath, page.getNumber() + 1, page.getSize()); } final Element a = new Element("a"); a.setAttribute("href", url); result.addChild(a); final Element icon = new Element("i"); icon.setAttribute("class", "glyphicon glyphicon-triangle-right"); a.addChild(icon); if (!page.hasNext()) { result.setAttribute("class", "disabled"); } return result; } /** * Gets the link node of the last page. * * @param page the pagination object * @param contextPath current context path of servlet * @return the node */ private Element getLastElement(final Page<?> page, final String contextPath) { final Element result = new Element("li"); final Element a = new Element("a"); a.setAttribute("href", getPagedParams(contextPath, page.getTotalPages() - 1, page.getSize())); result.addChild(a); final Element icon = new Element("i"); icon.setAttribute("class", "glyphicon glyphicon-step-forward"); a.addChild(icon); if (page.isLast()) { result.setAttribute("class", "disabled"); } return result; } }