Skip to content
This repository has been archived by the owner on Jul 28, 2022. It is now read-only.

feilongDisplay pager

feilong edited this page Oct 19, 2016 · 35 revisions

1. 文档说明

1.1 概述

分页是商城乃至整个互联网应用最常用的功能之一,好的分页标签及方案可以降低开发的复杂度和维护量,缩短工程师的开发时间.

1.2 阅读对象

面向具有一定的网站开发能力,了解 JAVA、JSP 等开发语言的网站开发、维护人员

1.3 专业术语

术语			|解释
:---- 		|:---------
taglib		|自定义标签
pager		|分页
velocity	|是apache基金会的一个java模板引擎(`template engine`),参见 http://velocity.apache.org/
Jsp			|全名为`Java Server Pages`,是由Sun 倡导、许多公司参与建立的一种动态网页技术标准,参见 http://www.oracle.com/technetwork/java/javaee/jsp/index.html
properties	|properties文件是java中的一种配置文件,主要用于表达配置信息,文件类型为*.properties,格式为文本文件,文件的内容是格式是"键=值"的格式
I18n		|来自英文单词 `internationalization` 的首末字符i和n,18为中间的字符数,是 `国际化` 的简称.
Ajax		|即 `Asynchronous Javascript And XML`(异步JavaScript和XML),是指一种创建交互式网页应用的网页开发技术

2. 特性介绍

  1. 支持 国际化

  2. 支持 Ajax 分页,参见 Ajax 分页使用步骤

  3. 当前页码永远居中

    center

  4. 内置页码输入文本框,支持快速跳转

    如可实现以下功能: goto

  5. 支持类似于淘宝最大分页码 100 这样的控制

    如可实现以下功能:

    maxsize

    见参数 maxShowPageNo

  6. 分页页码支持根据页码数字动态显示页码个数

    比如当当前页码是1001页显示6个页码,当当前页码是101,显示8个页码,见参数 dynamicNavigationPageNumberConfig

  7. 自动识别是否是forwoad 连接

  8. 支持自定义velocity分页模版

    见参数 vmPath

  9. 支持皮肤切换

    内置26种皮肤 (需要引入feilong-pager.css), 如果您的网站有自己特殊的样式,可以重新修改vm模板结构或者按照皮肤结构自定义css特殊的皮肤(建议选择后者) 内置皮肤样式参见附录部分

  10. 经过大型项目检验,通用严格的安全扫描测试

    Esprit,Nike,Underarmour,blanja,speedo 等大型项目都有使用该标签,并通过严格的安全扫描测试

3. 演示

3.1 演示

示例: 当前页面路径

	http://127.0.0.1:8088/pager?page=8&name=%E9%A3%9E%E5%A4%A9%E5%A5%94%E6%9C%88 

带皮肤的页面效果:

result

4. 跳转分页使用步骤

跳转分页顾名思义,点击分页页码,浏览器地址栏地址变更,显示新的页面

4.1 步骤1.JSP引用自定义标签

	<%@ taglib prefix="feilongDisplay" uri="http://java.feilong.com/tags-display"%>

4.2 步骤2.JSP使用自定义标签

4.2.1 精简参数写法

	<feilongDisplay:pager count="${pagination.count}"/>

仅需要总数参数 count 即可,其余参数缺省,均使用默认值

4.2.2 完整参数写法

	<feilongDisplay:pager 
		count="${pagination.count}" 

		charsetType="utf-8" 
		dynamicNavigationPageNumberConfig="1000=6&100=8&1=10"
		locale="zh_CN" 
		maxShowPageNo="-1"
		pageParamName="page" 
		pageSize="10"
		pagerHtmlAttributeName="feilongPagerHtml1" 
		skin="scott"
		vmPath="velocity/feilong-default-pager.vm" 
	/>

每个参数的含义,请参见下面 参数表格部分

5. 标签参数概览

5.1 Required Parameters(必需参数):

参数 说明 类型 Since 默认值
count 数据总数 Integer 1.0 -

5.2 Optional Parameters(可选参数):

参数 说明 类型 Since 默认值
pageSize 每一页显示多少个数据 Integer 1.0 20
pageParamName url分页页码参数 String 1.0 pageNo
pagerHtmlAttributeName vm被解析出来的文本,会被存在该变量中 String 1.0.5 "feilongPagerHtml"
locale 国际化语言,
支持 java.util.Locale 或 String 类型的实例
Locale 1.0.5 request.getLocale()
charsetType url编码 String 1.0.5 UTF-8
maxShowPageNo 显示最大的页码数,
(-1或者不设置,显示所有页数)
类似淘宝不管结果多少,最多显示100页
Integer 1.0.5 -1
vmPath 基于classpath 下面的velocity模版文件路径 String 1.0 "velocity/feilong-default-pager.vm"
skin 皮肤,内置24种常用皮肤
需要引入feilong-pager.css
String 1.0 "digg"
dynamicNavigationPageNumberConfig 动态显示导航页码数量 String 1.9.2 1000=6&100=8&1=10

6.标签参数详细说明

6.1 count

数据总数,(必需参数)

6.2 pageSize

每一页显示多少个数据,默认 20

6.3 locale 参数

国际化语言,支持 java.util.Locale 或 String 类型的实例

6.3.1 String 类型的示例:

注:since 1.7.2

	<feilongDisplay:pager 
		...
		locale="zh_CN" 
		.../>

6.3.2 spring-mvc 中使用的问题

6.3.2.1 背景:

假设服务器是英文语言,某网站是简体中文繁体中文两种语言,

如果是使用spring-mvc,不能直接使用 ${requestScope['org.springframework.web.servlet.i18n.CookieLocaleResolver.LOCALE']},

该属性如果用户不切换网站语言,那么值是null,那么分页标签会使用默认值 request.getLocale() ,显示英文的分页标签,但是该网站其实没有英文的站点,那么就不符合站点要求

6.3.2.2 临时方案:

在每个标签上方,使用 spel 表达式(参见 http://docs.spring.io/spring/docs/current/spring-framework-reference/html/expressions.html),获得当前的网站语言

示例:

	<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
	<spring:eval var="locale" expression="T(org.springframework.web.servlet.support.RequestContextUtils).getLocale(pageContext.request)"></spring:eval>
	
	<feilongDisplay:pager 
		...
		locale="${locale}" 
		.../>
6.3.2.3 建议方案:

使用 feilong spring el

注:since 1.7.2

示例:

	<%@ taglib prefix="flsp" uri="http://java.feilong.com/el-spring"%>

	<feilongDisplay:pager 
		...
		locale="${flsp:getLocale()}" 
		.../>

6.4 pageParamName

url分页页码参数,默认 pageNo

6.5 pagerHtmlAttributeName

vm被解析出来的文本,会被存在在这个变量中,作用域为pageContext,以便重复使用, 默认值 feilongPagerHtml

6.6 charsetType

url编码(默认是 utf-8)

6.7 maxShowPageNo

显示最大的页码数,(-1或者不设置,默认 -1 显示所有页数).

比如淘宝,不管搜索东西多少,最多显示100页

这是一种折中的处理方式,空间换时间. 数据查询越往后翻,对服务器的压力越大,速度越低,而且从业务上来讲商品质量也越差,所以就没有必要给太多了. 新浪微博的时间轴也只给出了10页,同样的折中处理.

6.8 vmPath

基于classpath 下面的velocity模版文件路径,默认的velocity\feilong-default-pager.vm ,虽然已经包含了大部分需求功能,但是可能实际项目中可能有特殊的需求,因此可以使用自定义pager vm 模板

6.9 dynamicNavigationPageNumberConfig

动态显示导航页码数量(默认是 1000=6&100=8&1=10).

  • 背景: 一般的分页标签是固定的分页页码数量,一般是10个,如果当前页码页码大于1000的时候,还是10条页码的显示(如1001,1002,1003,1004,1005,1006,1007,1008,1009,1010),那么页面分页会很长 ,可能打乱页面布局.因此使用动态显示导航页码数量

  • 规则: 示例:1000=6&100=8&1=10

    1. 含义:当当前页码>=1000的时候,显示6个页码;当当前页码>=100的时候显示8个页码;当当前页码>=1的时候,显示10个页码
    2. 设置规则类似于url的参数规则
    3. 分隔之后,key是当前页码参考值,value是显示页码数量,如果当前页码大于等于key的时候,那么页码的数量会显示值的数量,
      比如上例中,如果当前页码是1001,那么分页页码会显示成6个, 而如果当前页码是5,那么会显示10个页码
    4. 顺序不限制,不需要值大的写前面,程序会自动排序,比如你可以写成 1=10&100=8&1000=6
    5. 如果参数里面有相同名字的key,那么转换的时候取第一个值,比如1000=6&1000 =7&100=8&1=10,有效数据为1000=6&100=8&1=10
    6. 默认是 1000=6&100=8&1=10,如果设置为empty或者blank, 那么表示不使用动态显示的功能,永远显示10个页码
    7. 当然如果你需要不管什么时候都显示10个,除了将此值设置为empty或者blank外,你还可以设置为 1000=10&100=10&1=10,值设置为相同

6.10 skin

皮肤,默认 digg

7 Ajax分页使用步骤

参见 Ajax分页

8. 自定义velocity pager分页模板

在Pager vm模板中可以使用的参数有 6.1 PagerVMParam对象 以及 6.2 i18nMap对象 (国际化使用的文案)

8.1 PagerVMParam对象

变量名称 说明 类型 since 示例数据
totalCount 数据总数 int 1.0 1024
skin 设定的皮肤 String 1.0 digg
currentPageNo 当前页码 int 1.0 12
allPageNo 总页数 int 1.0 103
prePageNo 上一页页码 int 1.4.0 11
nextPageNo 下一页页码 int 1.4.0 13
pagerType 分页类型 PagerType 1.4.0 REDIRECT
preUrl 上一页链接 String 1.0 /pager?page=7&name=%E9%A3%9E%E5%A4%A9%E5%A5%94%E6%9C%88
nextUrl 下一页链接 String 1.0 /pager?page=9&name=%E9%A3%9E%E5%A4%A9%E5%A5%94%E6%9C%88
firstUrl 第一页的链接 String 1.0 /pager?page=1&name=%E9%A3%9E%E5%A4%A9%E5%A5%94%E6%9C%88
lastUrl 最后一页的链接 String 1.0 /pager?page=1000&name=%E9%A3%9E%E5%A4%A9%E5%A5%94%E6%9C%88
hrefUrlTemplate 链接的模板,以便前端js替换 1.0 /pager?page=-8888888&name=%E9%A3%9E%E5%A4%A9%E5%A5%94%E6%9C%88
startIteratorIndex 开始迭代索引编号 int 1.0 7
endIteratorIndex 结束迭代索引编号 int 1.0 9
iteratorIndexMap 循环 迭代索引map key是编号,value 是页面链接 LinkedHashMap<Integer, String> 1.0 "7": "/pager?page=7&name=%E9%A3%9E%E5%A4%A9%E5%A5%94%E6%9C%88",
"8": "/pager?page=8&name=%E9%A3%9E%E5%A4%A9%E5%A5%94%E6%9C%88",
"9": "/pager?page=9&name=%E9%A3%9E%E5%A4%A9%E5%A5%94%E6%9C%88"
pageParamName 分页参数名称 String 1.0.6 pageNo
pagerUrlTemplate 分页链接模板 PagerUrlTemplate 1.0.6 "pagerUrlTemplate": {
"href": "/pager?page=-88888888&name=%E9%A3%9E%E5%A4%A9%E5%A5%94%E6%9C%88",
"templateValue": -88888888
},

8.2 i18nMap对象 (国际化使用的文案)

将messages/feilong-pager.properties配置文件的key和value转成了i18nMap对象,可以在vm模板中直接使用配置文件中的参数

示例参见 8.3.messages/feilong-pager.properties  

9 附录

9.1 内置皮肤样式说明

如:

	div.digg a                  {border:1px solid #aad;padding:2px 5px;margin:2px;color:#009;text-decoration:none}
	div.digg a:link             {color:#009;}
	div.digg a:visited          {color:#009;}
	div.digg a:hover            {border:1px solid #009;color:#000;}
	div.digg a:active           {border:1px solid #009;color:#000;}
	div.digg span.current       {border:1px solid #009;padding:2px 5px;margin:2px;font-weight:bold;color:#fff;background:#009}
	div.digg span.disabled      {border:1px solid #999;padding:2px 5px;margin:2px;color:#777;}

其中 digg是 皮肤名称,你也可以根据这样的层级结构,建个自己的皮肤

下图是内置皮肤 默认样式,您可以指定皮肤名字使用

css

9.2 默认的feilong-default-pager.vm代码

	#**
	    这是个示例或者默认的模板,通过这个模板,可以看到哪些变量可以使用
	    每个商城可以使用这个模板,也可以自定义模板来使用
		
		该VM 可以取到两个变量:
		
	    	pagerVMParam	:	包含各种显示数字/链接 参数
	    	i18nMap			:	包含国际化信息
		
	    @version 1.0.0 2010-2-3 下午01:03:14
	    @version 1.0.5 May 3, 2014 1:44:08 PM
	    @since 1.0.0
	*#
	<div class="div_feilongPager ${pagerVMParam.skin}" style="text-align:left">
		##总数
		<span class="span_pagerInfo">${i18nMap.get('feilong-pager.text.totalCount')}${pagerVMParam.totalCount}</span>
		##当前第${pagerVMParam.currentPageNo}/共${pagerVMParam.allPageNo}
		<span class="span_pagerInfo" title="${i18nMap.get('feilong-pager.text.current')}${pagerVMParam.currentPageNo}${i18nMap.get('feilong-pager.text.pager')}/${i18nMap.get('feilong-pager.text.total')}${pagerVMParam.allPageNo}${i18nMap.get('feilong-pager.text.pager')}">${pagerVMParam.currentPageNo}/${pagerVMParam.allPageNo}</span>
	
	##第一页不显示首页和上一页
	#if(1 != ${pagerVMParam.currentPageNo})
		<a pageNoValue="${pagerVMParam.prePageNo}" title="${i18nMap.get('feilong-pager.text.goto.pre')}" href="${pagerVMParam.preUrl}">${i18nMap.get('feilong-pager.text.prev')}</a>
	    ##// 如果导航编号里面没有首页 则添加首页
		##// 导航里面 是否有第一页, 如果从开始1索引 则已经包含的首页包含
		
		#if (${pagerVMParam.startIteratorIndex} != 1)
			<a pageNoValue="1" title="${i18nMap.get('feilong-pager.text.goto.first')}" href="${pagerVMParam.firstUrl}">1</a>
		#end
	#end
	
	##开始迭代索引不等于1,并且开始迭代索引不等于2,显示3点
	#if (${pagerVMParam.startIteratorIndex} != 1 && ${pagerVMParam.startIteratorIndex} != 2)
		<span class="color_666">...</span>
	#end
	
	##循环所有的页码 显示导航编号
	#foreach( ${entry} in ${pagerVMParam.iteratorIndexMap.entrySet()} )
		##当前 直接是数字编号
	    #if(${entry.key}==${pagerVMParam.currentPageNo})
			<span class="current">${entry.key}</span>
	    #else
			##不是当前页面
			<a pageNoValue="${entry.key}" title="${i18nMap.get('feilong-pager.text.goto')}${entry.key}${i18nMap.get('feilong-pager.text.pager')}" href="${entry.value}">${entry.key}</a>
	    #end
	#end
	
	##如果最后一个迭代索引不等于总页数,且最后一个迭代索引不等于总也是-1,那么 显示3点
	#set($allPageNoTo1=${pagerVMParam.allPageNo} - 1)
	#if (${pagerVMParam.endIteratorIndex} != ${pagerVMParam.allPageNo} && ${pagerVMParam.endIteratorIndex} != $allPageNoTo1)
		<span class="color_666">...</span>
	#end
	
	##最后一页不显示下一页和末页
	#if(${pagerVMParam.allPageNo}!=${pagerVMParam.currentPageNo})
		## 如果导航编号里面没有尾页 则添加尾页
		##导航里面是否有最后一页, 如果结束的位置是allPageNo 则已经包含的尾页
		#if(${pagerVMParam.endIteratorIndex} != ${pagerVMParam.allPageNo})
			##跳转到最后一页
			<a pageNoValue="$!{pagerVMParam.allPageNo}" title="${i18nMap.get('feilong-pager.text.goto.last')}" href="${pagerVMParam.lastUrl}">$!{pagerVMParam.allPageNo}</a>
		#end
	
		##跳转到下一页
		<a pageNoValue="${pagerVMParam.nextPageNo}" title="${i18nMap.get('feilong-pager.text.goto.next')}" href="${pagerVMParam.nextUrl}">${i18nMap.get('feilong-pager.text.next')}</a>
	#end
	
		<input type="text" value="${pagerVMParam.currentPageNo}" class="feilongGotoInput" pagerUrlTemplateHref="${pagerVMParam.pagerUrlTemplate.href}" templateValue="${pagerVMParam.pagerUrlTemplate.templateValue}" pageParamName="${pagerVMParam.pageParamName}"/>/${pagerVMParam.allPageNo}<button value="go">Go</button>
	</div>
	
	<script type="text/javascript">
	    $(function() {
		##回车事件
			$(".feilongGotoInput").keydown( function() { 
				if (event.keyCode == 13) { 
	    			var pageNoValue=$(this).val();
					if(""!=pageNoValue&&pageNoValue>0){
					
						var templateValue=$(this).attr("templateValue");
						var pageParamName=$(this).attr("pageParamName");
						var pagerUrlTemplateHref=$(this).attr("pagerUrlTemplateHref");
						
	    				location.href=pagerUrlTemplateHref.replace(pageParamName+"="+templateValue,pageParamName+"="+pageNoValue);
					}
				}
			});
	});
	</script>

9.3 messages/feilong-pager.properties

i18n

10.参考

Clone this wiki locally