全栈角度看分页处理
分页是webapplication开发最常见的功能。在使用不同的框架和工具过程中,发现初始行页的定义不同,特意整理记录。从这个技术点去看不同层的实现。以及不同语言实现的对比。
文章会从正常的web结构分层的角度去梳理不同层的处理,分为数据库分页、服务端分页、前端分页三部分。
一、数据库分页
这里用mysql举例整理。我们常用的数据库例如OracleSQLServer等,对于分页语法的支持大同小异。不做具体一一举例。
先从数据库层梳理,也是从最根源去分析分页的最终目的,前端和后端的一起逻辑和适配,都是为了拼接合适的SQL语句。
1。MySQLLIMIT
语法:〔LIMIT{〔offset,〕rowcount}〕
LIMITrowcountisequivalenttoLIMIT0,rowcount。
Theoffsetoftheinitialrowis0(not1)
参考:MySQL::MySQL5。7ReferenceManual::13。2。9SELECTStatement
二、服务端后端分页
后端分页,简单讲,就是数据库的分页。对于mysql来讲,就是上述offsetrowcount的计算过程。
这里选用了常用的框架组件来对比各自实现的细节。
pagehelper是JavaOrm框架mybatis常用的开源分页插件
springdatajdbc是Java框架常用的数据层组件1。pagehelper计算起止行号offsetseecom。github。pagehelper。PagecalculateStartAndEndRowprivatevoidcalculateStartAndEndRow(){pageNum页码,从1开始。pageNum1,忽略计算。this。startRowthis。pageNum0?(this。pageNum1)this。pageSize:0;this。endRowthis。startRowthis。pageSize(this。pageNum0?1:0);}计算总页数pagespageCount。在赋值数据总条数的同时,也计算了总页数。可以与Math。ceil实现对比看。publicvoidsetTotal(longtotal){if(pageSize0){pages(int)(totalpageSize((totalpageSize0)?0:1));}else{pages0;}}
SQL拼接实现:com。github。pagehelper。dialect。helper。MySqlDialect2。springdatajdbc
关键类:
org。springframework。data。domain。Pageable
org。springframework。data。web。PageableDefaultoffset计算,不同于pagehelper,page页码从0开始。defaultis0seeorg。springframework。data。domain。AbstractPageRequestgetOffsetpubliclonggetOffset(){return(long)this。page(long)this。size;}总页数的计算使用Math。ceil实现。seeorg。springframework。data。domain。PagegetTotalPages()OverridepublicintgetTotalPages(){returngetSize()0?1:(int)Math。ceil((double)total(double)getSize());}offset计算,不同于pagehelper,page页码从0开始。seeorg。springframework。data。jdbc。core。convert。SqlGeneratorapplyPaginationprivateSelectBuilder。SelectOrderedapplyPagination(Pageablepageable,SelectBuilder。SelectOrderedselect){在springdatarelation,Limit抽象为SelectLimitOffsetSelectBuilder。SelectLimitOffsetlimitable(SelectBuilder。SelectLimitOffset)select;Toreadthefirst20rowsfromstartuselimitOffset(20,0)。toreadthenext20uselimitOffset(20,20)。SelectBuilder。SelectLimitOffsetlimitResultlimitable。limitOffset(pageable。getPageSize(),pageable。getOffset());return(SelectBuilder。SelectOrdered)limitResult;}
springdatacommons提供mvc层的分页参数处理器Annotationtosetdefaultswheninjectinga{linkorg。springframework。data。domain。Pageable}intoacontrollermethod。seeorg。springframework。data。web。PageableDefaultDocumentedRetention(RetentionPolicy。RUNTIME)Target(ElementType。PARAMETER)publicinterfacePageableDefault{Thedefaultsizetheinjected{linkorg。springframework。data。domain。Pageable}shouldgetifnocorrespondingparameterdefinedinrequest(defaultis10)。intsize()default10;Thedefaultpagenumbertheinjected{linkorg。springframework。data。domain。Pageable}shouldgetifnocorrespondingparameterdefinedinrequest(defaultis0)。intpage()default0;}
MVC参数处理器:org。springframework。data。web。PageableHandlerMethodArgumentResolver
三、前端分页
前端展示层,分别从服务端渲染方案以及纯前端脚本方案去看分页最终的页面呈现逻辑。
这里选取的分别是Java常用的模板引擎thymeleaf以及热门的前端框架elementui。
从用法以及组件源码角度,去理清终端处理分页的常见方式。1。thymeleaf模板引擎
ThymeleafisamodernserversideJavatemplateengineforbothwebandstandaloneenvironments。!springdataexampleswebexamplesrcmainresourcesemplatesusers。htmlnav!class样式bootstrap默认的分页用法ulclasspaginationth:withtotal{users。totalPages}lith:if{users。hasPrevious()}spanariahiddentruespanli!springdataexamples分页计算从0开始,users?page0size10!生成页码列表,呈现形式即我们常见的lith:eachpage:{numbers。sequence(0,total1)}1lilith:if{users。hasNext()}!下一页实现,因为是服务器端渲染生成。在最终生成的html中,这里的href是固定的。实现思路和纯前端技术,使用javascript脚本对比看spanariahiddentruespanliulnav2。elementui前端框架fromnodemoduleselementuipackagespaginationsrcpagination。jspagecount总页数,total和pagecount设置任意一个就可以达到显示页码的功能;computed:{internalPageCount(){if(typeofthis。totalnumber){页数计算使用Math。ceilreturnMath。max(1,Math。ceil(this。totalthis。internalPageSize));}elseif(typeofthis。pageCountnumber){returnMath。max(1,this。pageCount);}returnnull;}},起始页计算。page页码从1开始。getValidCurrentPage(value){valueparseInt(value,10);从源码的实现可以看到,一个稳定强大的开源框架,在容错、边界处理的严谨和思考。consthavePageCounttypeofthis。internalPageCountnumber;letresetValue;if(!havePageCount){if(isNaN(value)value1)resetValue1;}else{强制赋值起始值1if(value1){resetValue1;}elseif(valuethis。internalPageCount){数据越界,强制拉回到PageCountresetValuethis。internalPageCount;}}if(resetValueundefinedisNaN(value)){resetValue1;}elseif(resetValue0){resetValue1;}returnresetValueundefined?value:resetValue;}
四、总结
技术永远是关联的,思路永远是相似的,方案永远是相通的。单独的去分析某个技术或者原理,总是有边界和困惑存在。纵向拉伸,横向对比才能对技术方案有深刻的理解。在实战应用中,能灵活自如。
分页实现的方案最终是由数据库决定的,对于众多的数据库,通过SQL语法的规范去框定,以及我们常用的各种组件或者插件去适配。
纵向对比,我们可以看到不同技术层的职责和通用适配的实现过程,对于我们日常的业务通用开发以及不同业务的兼容有很大的借鉴意义。
横向对比,例如前端展示层的实现思路,其实差别非常大。如果使用thymeleaf,结构简单清晰,但交互响应上都会通过服务器。如果选用elementui,分页只依赖展示层,和服务端彻底解构。在技术选型中可以根据各自的优缺点进行适度的抉择。
作者:杨攀
来源:微信公众号:京东云开发者
出处:https:mp。weixin。qq。comsu3K7LjRNQOVQdfGxzjkvwQ
美院学生和综合性大学艺术生有什么区别?美院学生和综合性大学艺术学生有什么区别?对于这个问题,主要看学生是学习的什么专业类别。1如果学生想走纯艺术造型,例如油画类(油画板画国画雕塑),走从事画作创作的道路,那么建议学生报
当兵的战友,退伍几十年后你还同战友领导联系吗?我是四川人,79年11月入伍,在部队几年的训练,生活接识了来自湖北,河北,河南,广东,安徽,贵州,重庆的战友,与战友们结下了深深的战友情,然而铁打的营盘流水的兵,我于83年底退伍至
一定要提醒家中老人,售价7900元的艾灸凳是骗人的,你家买过吗?我觉得你这个问题提的正当时,也是各个家庭中的老人及子女应认真对待的问题。我之所以这样回答,是因艾灸店太多了。我还真没进去体验过。想去,可因人太多,还要听课,万一有个闪失,自已被感染
为什么上海最便宜的房价是金山?金山居住环境怎么样?本人金山本地人,客观的说金山的环境绝对没有传说的那么夸张,臭味是偶尔的,房价也绝对不会是5000,10000的,石化老城区2万,金山新城3万左右。我住在金山上班在徐汇,每天坐城铁(
安徽经济到底怎么样?近些年,安徽在全国范围内的存在感很强,也是我国经济发展最快的省份之一。1。从GDP累计增速看20102019年,安徽GDP累计增速达到202,在全国排名第四,仅次于贵州西藏以及云南
肇庆新区前景如何,真心话?目前新区发展不错,引进了华侨城,西江明珠大厦,优世智谷,京东,民商总部等一批大企业相信几年内看到新区的会高楼林立。肇庆新区前景是备受争议的,由于小城市政府资金不足,发展步伐较慢。肇
2021茂名市教育局直属学校选聘教师有什么防疫注意事项吗?防疫注意事项本次选聘在新冠肺炎疫情防控常态化下开展,在选聘组织实施过程中,将按照疫情防控有关要求,落实防疫措施,必要时选聘工作组可综合考虑各种因素对有关工作安排进行适当调整,并及时
深圳45岁失业卖房900万去惠州生活照顾一家4口行不?45岁,在深圳失业了,深圳房子能卖900万,想去惠州生活照顾一家4口。适合自己的,就是最好的!如果追求的是生活质量和生活氛围,那惠州肯定比深圳宜居。卖了深圳的房子到惠州买套大平米的
深二代们,你们会逃离深圳吗?为什么?我应该算是深二代吧,虽然不是在深圳出生,但是在深圳读书,98年入深户,小学四年级一直到高中毕业,到外地读完大学又回到深圳就业,后来自己创业,靠自己和爱人的努力,拥有龙岗的一套按揭房
公务员死后补四十个月的工资吗?这个问题我来回答吧,我是单位工会副主席。这个钱的处理也是我工作的一部分。退休公务员死亡后,发放的钱有两部分。一部分是其月退休工资40个月,但仅仅是基础工资。另一部分是死亡抚恤金,4
在河北邢台市,普通公务员月收入能过万吗?能,做领导的可以,普通公务员各县执行标准不一样,按照我们县说,科技干部能挣到5ooo一6ooo元,(其中包括精神文明奖,年终奖,在多领一个月工资在内),一般干部3ooo多元。可以。