129 Detailed explanation of paging function implementation | RuoYi
- The front end uses the lightweight table plug-in bootstrap-table (opens new window) based on
bootstrap
- The backend uses the lightweight paging plug-in pageHelper (opens new window) based on
mybatis
hint:
Front-end and back-end paging implementation process
One front end
1 element-ui provides el-pagination, which can be used directly, no problem.
2 It just means that the project also encapsulates a pagination component, src\components\Pagination\index.vue. The encapsulated pagination component is compatible with el-pagination, that is, all properties, events, etc. of el-pagination will be supported.
<template> <div :class="{'hidden':hidden}" class="pagination-container"> <el-pagination :background="background" :current-page.sync="currentPage" :page-size.sync="pageSize" :layout="layout" :page-sizes="pageSizes" :pager-count="pagerCount" :total="total" v-bind="$attrs" @size-change="handleSizeChange" @current-change="handleCurrentChange" /> </div> </template> <script> import { scrollTo } from '@/utils/scroll-to' export default { name: 'Pagination', props: { total: { required: true, type: Number }, page: { type: Number, default: 1 }, limit: { type: Number, default: 20 }, pageSizes: { type: Array, // Different from el-pagination, some default values have been slightly modified. default() { return [10, 20, 30, 50] } }, //The number of mobile page number buttons, default value is 5. // If not mobile, it is 7 pagerCount: { type: Number, default: document.body.clientWidth < 992 ? 5 : 7 }, layout: { type: String, default: 'total, sizes, prev, pager, next, jumper' }, background: { type: Boolean, default: true }, autoScroll: { type: Boolean, default: true }, hidden: { type: Boolean, default: false } }, data() { return { }; }, computed: { currentPage: { get() { return this.page }, set(val) { this.$emit('update:page', val) } }, pageSize: { get() { return this.limit }, set(val) { this.$emit('update:limit', val) } } }, methods: { handleSizeChange(val) { if (this.currentPage * val > this.total) { this.currentPage = 1 } this.$emit('pagination', { page: this.currentPage, limit: val }) if (this.autoScroll) { // After clicking the next page, automatically scroll to the location of the first data scrollTo(0, 800) } }, handleCurrentChange(val) { this.$emit('pagination', { page: val, limit: this.pageSize }) if (this.autoScroll) { scrollTo(0, 800) } } } } </script> <style scoped> .pagination-container { background: #fff; padding: 32px 16px; } .pagination-container.hidden { display: none; } </style>
3 Globally register the encapsulated pagination component (can be used on any front-end page): main.js
// Global component mounting Vue.component('Pagination', Pagination) //Paging component import Pagination from "@/components/Pagination";
4 Use case of encapsulated pagination component: src\views\system\role\selectUser.vue
5 Front-end call implementation: front-end definition paging process
//Paging variables are generally defined in query parameters queryParams: { pageNum: 1, pageSize: 10 }, //Add paging components to the page and pass in paging variables <pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" /> // Declare paging parameters and query parameters export default { data() { return { // Query parameters queryParams: { pageNum: 1, // Page 1 pageSize: 10, // 10 items per page roleId: undefined, // Query condition 1: roleId, role id userName: undefined, // Query condition 2: User name phonenumber: undefined // Query condition 3: phone number } }; } } // Call the background method, pass in parameters and get the result //queryParams are paging parameters and query parameters listUser(this.queryParams).then(response => { this.userList = response.rows; this.total = response.total; } );
6 Extension: Generally, it is enough to directly use the encapsulated paging component in the project. If you are not satisfied, you can refer to el-pagination to customize some attributes and add them. Or you can just use Ele.me directly, both are fine.
Two backend
1 ruoyi-common-core#TableDataInfo: table paging data object, where rows is table data
public class TableDataInfo implements Serializable { private static final long serialVersionUID = 1L; /** total */ private long total; /** List data */ private List<?> rows; /** Message status code */ private int code; /** Message content */ private String msg; }
2 ruoyi-common-core#PageUtils: Solve the problem that there are no pageSize and pageNumber attributes in the entity class (such as SysPost sysPost below) to receive front-end parameters
/** *Paging tool class * * @author ruoyi */ public class PageUtils extends PageHelper { /** * Set request paging data: * Just take several parameters passed from the front end from the request. * Then set it to pageDomain. */ public static void startPage() { PageDomain pageDomain = TableSupport.buildPageRequest(); Integer pageNum = pageDomain.getPageNum(); Integer pageSize = pageDomain.getPageSize(); String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy()); Boolean reasonable = pageDomain.getReasonable(); // Call the paging plugin PageHelper.startPage(pageNum, pageSize, orderBy).setReasonable(reasonable); } }
3 ruoyi-system#SysPostController#list
/** * Get job list */ @RequiresPermissions("system:post:list") @GetMapping("/list") public TableDataInfo list(SysPost post) { // paging startPage(); //Current page data List<SysPost> list = postService.selectPostList(post); //Return to front end return getDataTable(list); }
4 [pagehelper framework] PageMethod#startPage: paging
// Current request protected static final ThreadLocal<Page> LOCAL_PAGE = new ThreadLocal(); // That is, under the current request, give us a paging // The limit paging statement with the three parameters pageNum, pageSize, and orderBy will be automatically spliced into the sql statement. // Simplify the code: no need to modify the sql statement in SysPostMapper.xml public static <E> Page<E> startPage(int pageNum, int pageSize, String orderBy) { Page<E> page = startPage(pageNum, pageSize); page.setOrderBy(orderBy); return page; }
5 Extension: If you don’t want paging, just delete the startPage(); code.
Three things to note (pitfalls)
1 Common pitfall 1: Inexplicable paging in selectPostById
. For example, the following code
startPage(); List<User> list; if(user != null){ list = userService.selectUserList(user); } else { list = new ArrayList<User>(); } // When user == null, paging will be consumed on this query. // Originally, the query was for a single query, but the result was inexplicably divided into pages for you. Post post = postService.selectPostById(1L); return getDataTable(list);
Cause analysis: In this case, due to the existence of null
in user
, pageHelper
will produce a paging parameter, but it will not be consumed. This parameter will remain on this thread. When this thread is used again, it may cause methods that should not be paginated to consume this paging parameter, which results in inexplicable paging.
The above code should be written as follows to ensure safety.
That is to say, if you use this startPage, you will not do paging, and there is no paging in this place. In that case, your next query will be the next query, and it will bring this paging, so it will be inexplicable. You don’t need to paginate this, but it is paginated, so you need to pay attention to it.
List<User> list; if(user != null){ startPage(); list = userService.selectUserList(user); } else { list = new ArrayList<User>(); } Post post = postService.selectPostById(1L); return getDataTable(list);
2 Common pitfall 2: Added startPage
method. There is no normal paging either. For example, the following code
startPage(); // Error: Pagination error added here Post post = postService.selectPostById(1L); List<User> list = userService.selectUserList(user); return getDataTable(list);
Cause analysis: Only the data obtained by the first query (Select)
statement after this statement is paginated.
The above code should be written as follows to paginate normally.
Because, what you say below must be a query method (XxxMapper.xml) of the sql statement you use for paging.
Post post = postService.selectPostById(1L); startPage(); List<User> list = userService.selectUserList(user); return getDataTable(list);
3 Tips
The default syntax of the project paging plug-in is Mysql
. If the project is changed to another database, you need to modify the properties in the configuration application.yml
file helperDialect: your database
4 Note
As long as you can ensure that the
PageHelper
method call is followed by theMyBatis
query method, this is safe. BecausePageHelper
automatically clears the object stored inThreadLocal
in thefinally
code segment. If an exception occurs before the code entersExecutor
, the thread will become unavailable. This is a man-madeBug
(such as interface methods andXML
mismatch, resulting inMappedStatement
not being found). In this case, since the thread is unavailable, it will not cause theThreadLocal
parameter to be used incorrectly.