Pagination processing – Ruoyi cloud – 129

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 the MyBatis query method, this is safe. Because PageHelper automatically clears the object stored in ThreadLocal in the finally code segment. If an exception occurs before the code enters Executor, the thread will become unavailable. This is a man-made Bug (such as interface methods and XML mismatch, resulting in MappedStatement not being found). In this case, since the thread is unavailable, it will not cause the ThreadLocal parameter to be used incorrectly.