how2j.cn

相关下载
文件名 文件大小
tmall_springboot.rar 1m
使用站长秘制下载工具

工具版本兼容问题
分页单独拿出来讲解


21分48秒
本视频采用html5方式播放,如无法正常播放,请将浏览器升级至最新版本,推荐火狐,chrome,360浏览器 如果装有迅雷,播放视频呈现直接下载状态,请调整 迅雷系统设置-基本设置-启动-监视全部浏览器 (去掉这个选项)

步骤 1 : 先运行,看到效果,再学习   
步骤 2 : 模仿和排错   
步骤 3 : Page4Navigator   
步骤 4 : CategoryService   
步骤 5 : CategoryController   
步骤 6 : listCategory.html   
步骤 7 : adminPage.html   
步骤 8 : 自己做一遍   

步骤 1 :

先运行,看到效果,再学习

老规矩,先下载右上角的可运行项目,配置运行起来,确认可用之后,再学习做了哪些步骤以达到这样的效果。

如图所示,每页显示5条数据。

注: 没有分类图片是正常的,在接下来的知识点就会做增加图片功能了
先运行,看到效果,再学习
步骤 2 :

模仿和排错

在确保可运行项目能够正确无误地运行之后,再严格照着教程的步骤,对代码模仿一遍。
模仿过程难免代码有出入,导致无法得到期望的运行结果,此时此刻通过比较正确答案 ( 可运行项目 ) 和自己的代码,来定位问题所在。
采用这种方式,学习有效果,排错有效率,可以较为明显地提升学习速度,跨过学习路上的各个槛。

推荐使用diffmerge软件,进行文件夹比较。把你自己做的项目文件夹,和我的可运行项目文件夹进行比较。
这个软件很牛逼的,可以知道文件夹里哪两个文件不对,并且很明显地标记出来
这里提供了绿色安装和使用教程:diffmerge 下载和使用教程
步骤 3 :

Page4Navigator

JPA 默认提供了一个分页类:org.springframework.data.domain.Page, 这个分页类已经能够满足各种分页需要了,所以大部分收用它就足够了。
但是除了一点,就是如图所示的,比如当前是第8页,前面要显示3个,后面要显示3个,总共7条分页点,这个类默认就不提供了。
所以我们做了一个 Page4Navigator, 首先对 Page 类进行了封装,然后在构造方法里提供了一个 navigatePages 参数。 这个参数如果传7,就表示如图所示的效果,前面3个,后面3个。
在构造方法里,还调用了 calcNavigatepageNums, 就是用来计算这个数值,并返回到一个int 数组变量 navigatepageNums ,方便前端遍历展示。
Page4Navigator
package com.how2java.tmall.util; import java.util.List; import org.springframework.data.domain.Page; public class Page4Navigator<T> { Page<T> pageFromJPA; int navigatePages; int totalPages; int number; long totalElements; int size; int numberOfElements; List<T> content; boolean isHasContent; boolean first; boolean last; boolean isHasNext; boolean isHasPrevious; int[] navigatepageNums; public Page4Navigator() { //这个空的分页是为了 Redis 从 json格式转换为 Page4Navigator 对象而专门提供的 } public Page4Navigator(Page<T> pageFromJPA,int navigatePages) { this.pageFromJPA = pageFromJPA; this.navigatePages = navigatePages; totalPages = pageFromJPA.getTotalPages(); number = pageFromJPA.getNumber() ; totalElements = pageFromJPA.getTotalElements(); size = pageFromJPA.getSize(); numberOfElements = pageFromJPA.getNumberOfElements(); content = pageFromJPA.getContent(); isHasContent = pageFromJPA.hasContent(); first = pageFromJPA.isFirst(); last = pageFromJPA.isLast(); isHasNext = pageFromJPA.hasNext(); isHasPrevious = pageFromJPA.hasPrevious(); calcNavigatepageNums(); } private void calcNavigatepageNums() { int navigatepageNums[]; int totalPages = getTotalPages(); int num = getNumber(); //当总页数小于或等于导航页码数时 if (totalPages <= navigatePages) { navigatepageNums = new int[totalPages]; for (int i = 0; i < totalPages; i++) { navigatepageNums[i] = i + 1; } } else { //当总页数大于导航页码数时 navigatepageNums = new int[navigatePages]; int startNum = num - navigatePages / 2; int endNum = num + navigatePages / 2; if (startNum < 1) { startNum = 1; //(最前navigatePages页 for (int i = 0; i < navigatePages; i++) { navigatepageNums[i] = startNum++; } } else if (endNum > totalPages) { endNum = totalPages; //最后navigatePages页 for (int i = navigatePages - 1; i >= 0; i--) { navigatepageNums[i] = endNum--; } } else { //所有中间页 for (int i = 0; i < navigatePages; i++) { navigatepageNums[i] = startNum++; } } } this.navigatepageNums = navigatepageNums; } public int getNavigatePages() { return navigatePages; } public void setNavigatePages(int navigatePages) { this.navigatePages = navigatePages; } public int getTotalPages() { return totalPages; } public void setTotalPages(int totalPages) { this.totalPages = totalPages; } public int getNumber() { return number; } public void setNumber(int number) { this.number = number; } public long getTotalElements() { return totalElements; } public void setTotalElements(long totalElements) { this.totalElements = totalElements; } public int getSize() { return size; } public void setSize(int size) { this.size = size; } public int getNumberOfElements() { return numberOfElements; } public void setNumberOfElements(int numberOfElements) { this.numberOfElements = numberOfElements; } public List<T> getContent() { return content; } public void setContent(List<T> content) { this.content = content; } public boolean isHasContent() { return isHasContent; } public void setHasContent(boolean isHasContent) { this.isHasContent = isHasContent; } public boolean isFirst() { return first; } public void setFirst(boolean first) { this.first = first; } public boolean isLast() { return last; } public void setLast(boolean last) { this.last = last; } public boolean isHasNext() { return isHasNext; } public void setHasNext(boolean isHasNext) { this.isHasNext = isHasNext; } public boolean isHasPrevious() { return isHasPrevious; } public void setHasPrevious(boolean isHasPrevious) { this.isHasPrevious = isHasPrevious; } public int[] getNavigatepageNums() { return navigatepageNums; } public void setNavigatepageNums(int[] navigatepageNums) { this.navigatepageNums = navigatepageNums; } }
步骤 4 :

CategoryService

CategoryService 增加带参的 list 方法。
package com.how2java.tmall.service; import java.util.List; import com.how2java.tmall.util.Page4Navigator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; import com.how2java.tmall.dao.CategoryDAO; import com.how2java.tmall.pojo.Category; @Service public class CategoryService { @Autowired CategoryDAO categoryDAO; public Page4Navigator<Category> list(int start, int size, int navigatePages) { Sort sort = new Sort(Sort.Direction.DESC, "id"); Pageable pageable = new PageRequest(start, size,sort); Page pageFromJPA =categoryDAO.findAll(pageable); return new Page4Navigator<>(pageFromJPA,navigatePages); } public List<Category> list() { Sort sort = new Sort(Sort.Direction.DESC, "id"); return categoryDAO.findAll(sort); } }
步骤 5 :

CategoryController

CategoryController 修改原 list 方法,接受 start 和 size 参数。
业务逻辑上就调用 CategoryService 的新的 list 方法了。
然后返回的是 Page4Navigator 类型,并通过 RestController 转换为 json 对象抛给浏览器。
package com.how2java.tmall.web; import com.how2java.tmall.pojo.Category; import com.how2java.tmall.service.CategoryService; import com.how2java.tmall.util.Page4Navigator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import java.util.List; @RestController public class CategoryController { @Autowired CategoryService categoryService; @GetMapping("/categories") public Page4Navigator<Category> list(@RequestParam(value = "start", defaultValue = "0") int start, @RequestParam(value = "size", defaultValue = "5") int size) throws Exception { start = start<0?0:start; Page4Navigator<Category> page =categoryService.list(start, size, 5); //5表示导航分页最多有5个,像 [1,2,3,4,5] 这样 return page; } }
步骤 6 :

listCategory.html

listCategory.html 做了如下修改:
1. list方法带上了参数 start
2. 通过 categories 获取数据的时候,带上了这个参数
3. 获取到的参数,以前是 json 化后的 category数组,现在是 Page4Navigator 对象,而数据,要重 Page4Navigator 对象的 .content 上获取出来。
4. 增加了两个跳转方法,分别是 jump和 jumpByNumber,而这两个方法的定义在 前面讲解的 adminHeader.html 里。
5. 包含adminPage.html
<div th:replace="include/admin/adminPage::html" ></div>
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head th:include="include/admin/adminHeader::html('分类管理')" ></head> <body> <div th:replace="include/admin/adminNavigator::html" ></div> <script> $(function(){ var data4Vue = { uri:'categories', pagination:{}, beans: [] }; //ViewModel var vue = new Vue({ el: '#workingArea', data: data4Vue, mounted:function(){ //mounted 表示这个 Vue 对象加载成功了 this.list(0); }, methods: { list:function(start){ var url = this.uri+ "?start="+start; axios.get(url).then(function(response) { vue.pagination = response.data; vue.beans = response.data.content ; }); }, jump: function(page){ jump(page,vue); //定义在adminHeader.html 中 }, jumpByNumber: function(start){ jumpByNumber(start,vue); } } }); }); </script> <div id="workingArea" > <h1 class="label label-info" >分类管理</h1> <br> <br> <div class="listDataTableDiv"> <table class="table table-striped table-bordered table-hover table-condensed"> <thead> <tr class="success"> <th>ID</th> <th>图片</th> <th>分类名称</th> <th>属性管理</th> <th>产品管理</th> <th>编辑</th> <th>删除</th> </tr> </thead> <tbody> <tr v-for="bean in beans "> <td>{{bean.id}}</td> <td> <img height="40px" :src="'img/category/'+bean.id+'.jpg'"> </td> <td> {{bean.name}} </td> <td> <a :href="'admin_property_list?cid=' + bean.id "><span class="glyphicon glyphicon-th-list"></span></a> </td> <td> <a :href="'admin_product_list?cid=' + bean.id "><span class="glyphicon glyphicon-shopping-cart"></span></a> </td> <td> <a :href="'admin_category_edit?id=' + bean.id "><span class="glyphicon glyphicon-edit"></span></a> </td> <td> <a href="#nowhere" @click="deleteBean(bean.id)"><span class=" glyphicon glyphicon-trash"></span></a> </td> </tr> </tbody> </table> </div> <div th:replace="include/admin/adminPage::html" ></div> </div> <div th:replace="include/admin/adminFooter::html" ></div> </body> </html>
步骤 7 :

adminPage.html

被包含的分页 html :

<li :class="{ disabled: pagination.first }">
<a href="#nowhere" @click="jump('first')">&laquo;</a>
</li>

这是首页,当 pagination.first 为真的时候,就表示当前是首页,那么首页对应的 li 的 class 就会是 disabled, 就点击不了。

<a href="#nowhere" @click="jump('first')">&laquo;</a>

点击的时候,会调用jump 函数,并且传 'first' 进去。 这个函数,先是调用 listCategory.html 里新增的 jump 函数,然后间接地调用 adminHeader.html 里的 jump(page,vue) 函数。
jump(page,vue) 函数如下:

function jump(page,vue){
if('first'== page && !vue.pagination.first)
vue.list(0);

else if('pre'== page && vue.pagination.hasPrevious )
vue.list(vue.pagination.number-1);

else if('next'== page && vue.pagination.hasNext)
vue.list(vue.pagination.number+1);

else if('last'== page && !vue.pagination.last)
vue.list(vue.pagination.totalPages-1);
}

当调用的时候传递的参数是 'first' 的时候,就调用 vue.list(0) 函数,并且传参数:0进去,这样就从服务器获取了首页的数据,vue.js 会自动刷新 table 里的数据。
除了 first, 其他的 pre, next, last 分别表示 上一页,下一页,最后一页,都是类似的用法,就不赘述了。

然后讲讲中间的遍历:

<li v-for="i in pagination.navigatepageNums">
<a href="#nowhere" @click="jumpByNumber(i-1)" >
{{i}}
</a>
</li>

中间这个遍历,就是遍历的 Page4Navigator 中新增加的 navigatepageNums 数组。 遍历出来之后,点击超链会调用 jumpByNumber 函数,并间接地调用adminHeader.html 里的jumpByNumber 函数:

function jumpByNumber(start,vue){
if(start!=vue.pagination.number)
vue.list(start);
}

一旦 vue.list 根据新的 start 获取到的数据, vue.js 就会自动刷新table 里的数据了。
如此这般就达到了分页的效果。
<div class="pageDiv" th:fragment="html"> <nav> <ul class="pagination"> <li :class="{ disabled: pagination.first }"> <a href="#nowhere" @click="jump('first')">«</a> </li> <li :class="{ disabled: !pagination.hasPrevious }"> <a href="#nowhere" @click="jump('pre')">‹</a> </li> <li v-for="i in pagination.navigatepageNums"> <a href="#nowhere" @click="jumpByNumber(i-1)" > {{i}} </a> </li> <li :class="{ disabled: !pagination.hasNext }"> <a href="#nowhere" @click="jump('next')">›</a> </li> <li :class="{ disabled: pagination.last }"> <a href="#nowhere" @click="jump('last')"> »</a> </li> </ul> </nav> </div>
步骤 8 :

自己做一遍

分页这个功能做起来还是相当考验细节的,下载上一个知识点查询右上角的tmall_springboot.rar, 在其基础之上,按照当前的步骤,自己做一遍,把效果做出来,理解和消化各个步骤的内容,转化为自己的技能。


HOW2J公众号,关注后实时获知布最新的教程和优惠活动,谢谢。


问答区域    
2018-10-29 emm
yutongxue
相当考验细节




1 个答案

how2j 答案时间:2018-10-30
如果是第一次学分页,会觉得东西比较多。 其实分页也就这样,多做几遍就好了,以后再做分页,就全是这些元素,就很容易触类旁通了。




答案 或者 代码至少填写一项, 如果是自己有问题,请重新提问,否则站长有可能看不到








提问之前请登陆
关于 实践项目-天猫整站Springboot-分页 的提问

尽量提供截图代码异常信息,有助于分析和解决问题。 也可进本站QQ群交流: 902680467
提问尽量提供完整的代码,环境描述,越是有利于问题的重现,您的问题越能更快得到解答。
对教程中代码有疑问,请提供是哪个步骤,哪一行有疑问,这样便于快速定位问题,提高问题得到解答的速度
在已经存在的几千个提问里,有相当大的比例,是因为使用了和站长不同版本的开发环境导致的,比如 jdk, eclpise, idea, mysql,tomcat 等等软件的版本不一致。
请使用和站长一样的版本,可以节约自己大量的学习时间。 站长把教学中用的软件版本整理了,都统一放在了这里, 方便大家下载: http://how2j.cn/k/helloworld/helloworld-version/1718.html

上传截图