如何实现后端开发框架(四)-分页查询

1. 问题描述

后端查询数据库都少不了分页查询功能,那么如何在框架层面上实现一个通用的分页查询功能,让开发人员方便的使用呢?

2. 实现思路

内部使用Mybatis-Plus的分页插件,外部需要封装一下便于开发人员使用。

3. 实现步骤

3.1 添加分页插件

添加Mybatis-Plus分页插件,实现分页相关功能。

@Configuration
public class MybatisPlusConfig {
  /** 添加分页插件 */
  @Bean
  public MybatisPlusInterceptor mybatisPlusInterceptor() {
    MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
    // 如果配置多个插件, 切记分页最后添加
    interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
    // 如果有多数据源可以不配具体类型, 否则都建议配上具体的 DbType
    return interceptor;
  }
}

3.2 添加分页查询参数

分页查询时都需要设置2个参数:当前页号(currentPage)和每页显示记录数量(pageSize),将这两个参数放入实体基类中,这样后端接收的传参对象和返回的结果对象都可以用同一个实体类。

@Data
@EqualsAndHashCode()
public class MyBaseEntity implements Serializable {
  private static final long serialVersionUID = 1L;

  @TableId(value = "ID")
  protected String id;

  @TableField(exist = false)
  protected long pageSize;

  @TableField(exist = false)
  protected long currentPage;
}

3.3 自定义分页对象

Mybatis-Plus内置的分页对象是Page,但为了框架以后的扩展性还是要使用自定义分页对象MyPage封装下,同时将Page的当前页号(current)和每页显示记录数量(size)用MyPage的currentPage和pageSize属性替换下。

/** 自定义分页类,序列化时需要去掉mybatis-plus Page类上的原生size和current字段 */
@JsonIgnoreProperties({"size", "current"})
public class MyPage<T> extends Page<T> {
  /** 每页显示记录数量 */
  protected long pageSize;

  /** 当前页号 */
  protected long currentPage;

  public MyPage() {}

  public MyPage(long currentPage, long pageSize) {
    super(currentPage, pageSize);
    this.currentPage = currentPage;
    this.pageSize = pageSize;
  }

  public MyPage(long currentPage, long pageSize, long total) {
    super(currentPage, pageSize, total);
    this.currentPage = currentPage;
    this.pageSize = pageSize;
  }

  public MyPage(long currentPage, long pageSize, boolean isSearchCount) {
    super(currentPage, pageSize, isSearchCount);
    this.currentPage = currentPage;
    this.pageSize = pageSize;
  }

  public MyPage(long currentPage, long pageSize, long total, boolean isSearchCount) {
    super(currentPage, pageSize, total, isSearchCount);
    this.currentPage = currentPage;
    this.pageSize = pageSize;
  }

  public long getPageSize() {
    return pageSize;
  }

  public void setPageSize(long pageSize) {
    this.pageSize = pageSize;
    this.size = pageSize;
  }

  public long getCurrentPage() {
    return currentPage;
  }

  public void setCurrentPage(long currentPage) {
    this.currentPage = currentPage;
    this.current = currentPage;
  }
}

3.4 实现自己的分页方法

在Service基类上实现通用的分页方法,这样便于开发人员使用。

public interface MyBaseService<T> extends IService<T> {
  default MyPage myPage(MyPage page, Wrapper<T> queryWrapper) {
    MyPage myPage = getBaseMapper().selectPage(page, queryWrapper);
    myPage.setCurrentPage(myPage.getCurrent());
    myPage.setPageSize(myPage.getSize());
    return myPage;
  }
}

4. 测试代码

@RestController
@RequestMapping("/test/user")
public class UserController extends MyBaseController<UserService, User> {
  /**
   * 根据条件查询所有记录
   *
   * @param user
   * @return
   */
  @RequestMapping(value = "/list", method = RequestMethod.POST)
  public List<User> list(@RequestBody(required = false) User user) {
    List<User> result = myBaseService.list(new QueryWrapper(user));
    return result;
  }

  /**
   * 根据条件分页查询记录
   *
   * @param user
   * @return
   */
  @RequestMapping(value = "/pageList", method = RequestMethod.POST)
  public MyPage<User> pageList(@RequestBody User user) {
    MyPage<User> page = new MyPage<>(user.getCurrentPage(), user.getPageSize());
    MyPage<User> result = myBaseService.myPage(page, new QueryWrapper(user));
    return result;
  }
}

5. 完整代码

完整代码见以下Git仓库中的page-list子项目:

https://github.com/randy0098/framework-samples