7.3 SpringBoot integrates MyBatis paging plug-in github.pageHelper: implement book list API

CSDN achieves 100 million technicians


foreword

In software development, paging is a very common requirement. Whether in web applications or mobile applications, we often need to divide a large amount of data into multiple pages for display.
This article mainly implements the book list API, uses SpringBoot to integrate the MyBatis pagination plug-in github.pageHelper , first of all, it will start from " realizing the principle of paging by itself ", then " use github.pageHelper to realize paging and attention points ", and finally return to the actual combat of the book lending system In the project, " combine with general pagination results " to realize " unified and standardized book list API ", after reading this article, you can easily handle general pagination.


1. Realize pagination by yourself

When you can make your own wheels, and then learn other paging components, you will find it very easy!

There are usually two ways to implement paging:

  1. Load all the results into the memory through sql query, and then implement paging in the memory. The disadvantage is obvious, loading all the data into memory at one time, because the result may be very large, consume a lot of resources, and may even cause memory overflow, so it is not recommended!
  2. Only load the current page data , which is what we really expect,So we implement this!

接下来,我们以Java+MySQL的「伪代码」来演示实现分页的思路!
insert image description here

The first step, count queries the total number of records (totalCount) and calculates the total number of pages (totalPages)

Receive front-end parameters:
// current page number (default page 1)
int pageNum = 1;
// number of records per page (default 10)
int pageSize = 10;

The purpose of first checking the total number of records and the total number of pages: return to the front-end display, so that users can know how many records and pages there are in total

select count(*) as totalCount from book where 。。。

Calculate the total number of pages totalPages using Java code

int totalPages = (int) Math.ceil((double) totalCount / pageSize);

In the second step, limit queries the specified page data

limit accepts one or two numeric arguments.
We mainly use two parameters: the first parameter specifies the offset of the first returned record row (optional), and the second parameter specifies the maximum number of rows returned; the basic syntax is
:

limit [offset] rows

rows is pageSize, so we need to use pageNum to calculate offset first:

if (pageNum > totalPages) {
    
    
    pageNum = totalPages;
}
int offset = (pageNum - 1) * pageSize;

Then, query the specified page data through limit.

select * from book where 。。。 limit offset, pageSize

2. Query book list Mapper without pagination

With the idea of ​​realization, in actual development, you will find that all paging scenarios have similar logic, and repeated codes can be implemented in one word: cumbersome! Quite uncomfortable, so is there a way to make you feel good? That's right, the github.pageHelper component, which can seamlessly integrate with persistence frameworks such as MyBatis, helps us quickly implement the paging function. It provides rich features and flexible configuration options, making pagination very simple. We only need to implement [main query SQL], and don’t care about other things like totalCount and totalPages, etc. These general functions are encapsulated internally by it.

In this case, we first implementQuery book list Mapper without pagination

Requirements:
First of all, this is the list of books in the management background, so all books can be queried.
Optional filter conditions : book name, book number, author, book status (0-idle 1-borrowing), book entry time (start time and end time, YYYY-MM-DD is enough)

Because it is a single-table query, we still use the 5.6 Mybatis code generator Mybatis Generator (MBG) actual combat detailed explanation example方式.

BookServiceImpl

For the example method, according to the requirements, we mainly build BookExample

/**
 * 组装图书列表查询的BookExample
 **/
private BookExample buildBookPageExample(BookListParamBO paramBO) {
    
    
    BookExample example = new BookExample();
    BookExample.Criteria criteria = example.createCriteria();
    if (!StringUtils.isEmpty(paramBO.getBookName())) {
    
    
        // 图书名称不为空, 模糊查询图书名称, 等同于sql: and book_name like 'xxx%'
        criteria.andBookNameLike(paramBO.getBookName() + "%");
    }
    if (!StringUtils.isEmpty(paramBO.getBookNo())) {
    
    
        // 图书编号不为空, 模糊查询图书编号
        criteria.andBookNoLike(paramBO.getBookNo() + "%");
    }
    if (!StringUtils.isEmpty(paramBO.getAuthor())) {
    
    
        // 作者不为空, 模糊查询作者
        criteria.andAuthorLike(paramBO.getAuthor() + "%");
    }
    if (paramBO.getStatus() != null) {
    
    
        // 图书状态不为空, 指定查询该状态
        criteria.andStatusEqualTo(paramBO.getStatus());
    }
    if (paramBO.getStartDay() != null) {
    
    
        // 录入开始时间不为空, >= 录入开始时间
        criteria.andGmtCreateGreaterThanOrEqualTo(paramBO.getStartDay());
    }
    if (paramBO.getEndDay() != null) {
    
    
        // 录入结束时间不为空, <= 录入结束时间
        criteria.andGmtCreateLessThanOrEqualTo(paramBO.getEndDay());
    }
    return example;
}

Interpretation: There are more filtering conditions:
For Criteria, it is actually the Where condition, but the sql is converted into a Java object method. Which one do you prefer? Vote at the end of the article~

Then, the query is even simpler, just call selectByExample~

/**
 *  查询图书列表
 **/
private List<Book> getBookList(BookListParamBO paramBO) {
    
    
    // 组装Example
    BookExample example = buildBookPageExample(paramBO);
    // 查询
    return bookMapper.selectByExample(example);
}

BookListParamBO

The parameter BookListParamBO is the parameter BO of the query list, which is defined under the bo package:

@Data
public class BookListParamBO implements Serializable {
    
    
    private String bookName;
    private String bookNo;
    private String author;
    private Integer status;
    private Date startDay;
    private Date endDay;
    private int pageNum = 1;
    private int pageSize = 10;
}

3. Integrate github.pageHelper and implement paging list

The main query has been implemented in the previous paragraph. Next, we use github.pageHelper to implement general pagination!

Step 1: Introduce pom dependencies

In the 5.1 SpringBoot integration of Mybatis, the old bird teaches you to learn in five minutes: the correct and comprehensive way. It has introduced the use of various starters of SpringBoot, as well as the official starter and the starter naming convention of the third-party framework. The same is true for pageHelper. Just import pagehelper-spring-boot-starter!

<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper-spring-boot-starter</artifactId>
    <version>1.2.10</version>
</dependency>

Because it is a general function, the dependency is placed in tg-book-commonthe middle, and the version number is specified in the dependencyManagement node of the parent project. For details, see 2-1. Maven three-tier project structure construction and 2-2. SpringBoot API development details

Reminder: After adding dependencies, don't forget to refresh Maven dependencies

Step 2: Implement pagination query

BookService method definition

Page<BookBO> getBookPage(BookListParamBO bookListParamBO);

Page is the return result, which is the general pagination result defined by github.pageHelper, and the corresponding fields are mapped when the general return result is encapsulated below.

Core implementation of BookServiceImpl

This is the core and focus of this article!

How can github.pageHelper achieve pagination through a main query?

Here's how I prefer to use it:

Page<XxxBO> page = PageHelper.startPage(pgeNum, pageSize)
	.doSelectPage(() -> 你的查询方法);

It not only realizes general pagination, but also is very clear and concise. The basic knowledge here is mainly [generic] and [Lambda expression]. If these two students are not familiar with it, please add [ Java skill tree ] as soon as possible.

  • PageHelper.startPage returns Page<E>a generic object

insert image description here

  • What doSelectPage passes in is the ISelect interface parameter

The ISelect interface has only one method with no parameters and no return value.
insert image description here
The purpose is to call any of our methods.
insert image description here
Of course, you may be curious about how to process the returned results here. In fact, the Mybatis interceptor Interceptor used internally, the automatically implemented count method, and all the logic of the assembly. Interested students can view its source code, which is not the focus of this article. So without further ado!

OK, the core implementation of the pagination of the book list in this article is as follows:

@Override
public Page<BookBO> getBookPage(BookListParamBO paramBO) {
    
    
    // 组装Example
    BookExample example = buildBookPageExample(paramBO);
    // 查询并分页
    Page<Book> page = PageHelper.startPage(paramBO.getPageNum(), paramBO.getPageSize())
            .doSelectPage(() -> bookMapper.selectByExample(example));

    // Page<Book> 转成 Page<BookBO>
    Page<BookBO> pageBO = new Page<>();
    BeanUtils.copyProperties(page, pageBO);
    for (Book book : page.getResult()) {
    
    
        BookBO bookBO = new BookBO();
        BeanUtils.copyProperties(book, bookBO);
        pageBO.add(bookBO);
    }
    return pageBO;
}

It can be seen that the code for paging is very small, but the code for converting PO to BO is a bit cumbersome, don’t worry, it will be packaged separately later, and a detailed explanation will be written separately!
特别注意:For the [Lambda expression] in doSelectPage, please ensure that only the Mapper method is called, because it will only be used as an Interceptor for the result returned by Mapper, so if you call Mapper and do other processing, it will not be able to perceive it, so it will not Take effect! So please don't use that! ! !

BooKBO

Because there are [book status] and [entry time] in the filter conditions, BooKBOthese two fields are also added in :

@Data
public class BookBO implements Serializable {
    
    
    private Integer id;
    private String bookNo;
    private String bookName;
    private Integer bookType;
    private String author;
    private String description;
    private String publisher;
    private Date publishDate;
    private String coverImage;
    // 图书状态(0-闲置 1-借阅中)
    private Integer status;
    // 录入时间
    private Date gmtCreate;
}

4. Encapsulate general paging results

The Service layer is implemented above, and then the API is defined in BookAdminController:

@PostMapping("/book/list")
public TgResult<BookBO> getBookList(@RequestBody BookListParamVO bookListParamVO) {
    
    
    return TgResult.ok(bookService.getBookPage(bookListParamVO.toBO()));
}

Because there are many parameters, we use the Post Body method. If there are few parameters, it is recommended to get the request!

TgResult

In order to support paging, it is necessary to add paging-related return fields in the general result TgResult, as follows:

// 分页结果==========
// 当前页码
private int pageNum;
// 每页计录数
private int pageSize;
// 总数
private long totalCount;
// 总页数
private long totalPages;
// 分页数据列表
private List<T> dataList;

And add okoverloading to support paging result Page, that is, take out useful fields from Page and return to the front end of the result:

public static <T> TgResult<T> ok(Page<T> page) {
    
    
    TgResult<T> result = build(true, "200", "成功", null);
    result.setPageNum(page.getPageNum());
    result.setPageSize(page.getPageSize());
    result.setTotalCount(page.getTotal());
    result.setTotalPages(page.getPages());
    result.setDataList(page.getResult());
    return result;
}

BookListParamVO

@Data
public class BookListParamVO implements Serializable {
    
    
    private String bookName;
    private String bookNo;
    private String author;
    private Integer status;
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date startDay;
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date endDay;
    private int pageNum = 1;
    private int pageSize = 10;

    public BookListParamBO toBO(){
    
    
        BookListParamBO bo = new BookListParamBO();
        // 结束时间到当天的23:59:59,如果默认传入的是年月日,所以需要单独设置
        BeanUtils.copyProperties(this, bo, "endDay");
        bo.setEndDay(getDayEndTime(this.endDay));
        return bo;
    }

    /**
     * 获取指定时间的那天 23:59:59.999 的时间
     */
    private Date getDayEndTime(final Date date) {
    
    
        if (date == null) {
    
    
            return null;
        }
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.set(Calendar.HOUR_OF_DAY, 23);
        c.set(Calendar.MINUTE, 59);
        c.set(Calendar.SECOND, 59);
        c.set(Calendar.MILLISECOND, 999);
        return c.getTime();
    }
}

The main thing is to do time format processing to ensure that the end time of the query is 23:59:59.999

application.properties

The uniform return time format isyyyy-MM-dd HH:mm:ss

spring.jackson.date-format=yyyy-MM-dd HH:mm:ss

PostMan walks a wave

insert image description here


at last

If you want to read more practical articles, I still recommend my practical column –> "Based on SpringBoot+SpringCloud+Vue Separation of Front-end and Back-end Projects", a column jointly created by me and the front-end dog brother, which allows you to learn from From 0 to 1, you can quickly have practical experience in enterprise-level standardized projects!

Specific advantages, planning, and technology selection can all be read in " The Beginning "!

After subscribing to the column, you can add my WeChat, and I will provide targeted guidance for each user!

In addition, don't forget to follow me: Tiangang gg , it is not easy to miss new articles: https://blog.csdn.net/scm_2008

Guess you like

Origin blog.csdn.net/scm_2008/article/details/131374809