1.问题来源

我们使用SpringMVC的时候,我们每个Controller都有一个获取分页数据的方法,但是被调用的Service实现了"extends IService<实体类>"的接口,因此分页信息"Page<实体类>"和查询条件都需要在Controller中进行组合,或者是在Controller和Service中间再添加一层,这样会对文件功能或项目结构造成破坏,于是我们需要自定义一个分页方法,并将"Page<实体类>"和查询条件都在Service层进行编写,于是出现了第二个问题,非特殊情况下除了查询条件,其他的代码都是一摸一样的,每次进行分页查询都需要编写大量的重复代码,这无疑增加了开发的复杂性和维护成本。为了解决这一问题,本文将介绍如何使用MyBatis-Plus实现一个通用的分页查询封装类,以简化分页查询的开发过程。

2.解决方案

1. 实现一个公共的分页处理类:PageHandler.java,实现多种分页方法和其他辅助方法。

2. 需要分页的Service实例化这个类

3. 组合查询条件,并调用PageHandler类中的分页方法即可

3.实现

MyBatis-plus的插件引入可以查看《SpringBoot入门二十八,添加MyBatis-Plus支持》第5部分:分页插件

MyBatis-plus实现分页查询的封装_mybatis-plus

3.1 分页处理类

import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;

/**
 * MyBatis-plus分页封装类,简化分页操作,格式化返回数据
 */
@Component
public class PageHandler<T> {

	private static String PAGE_NO = "pageNo";
	private static String PAGE_SIZE = "pageSize";

	/**
	 * 功能:无条件分页查询
	 *
	 * @param baseMapper 指定的查询接口
	 * @param pageNum    当前页页码
	 * @param pageSize   页面显示条数
	 * 
	 * @return Map<String, Object>
	 */
	public Map<String, Object> pageList(BaseMapper<T> baseMapper, int pageNum, int pageSize) {
		return pageList(baseMapper, Wrappers.emptyWrapper(), pageNum, pageSize);
	}

	/**
	 * 功能:翻页查询
	 *
	 * @param baseMapper   指定的查询接口
	 * @param queryWrapper 实体对象封装操作类
	 * @param pageNum      当前页页码
	 * @param pageSize     页面显示条数
	 * 
	 * @return Map<String, Object>
	 */
	public Map<String, Object> pageList(BaseMapper<T> baseMapper, Wrapper<T> queryWrapper, int pageNum, int pageSize) {
		// 创建分页对象,指定当前页和每页显示的记录数
		Page<T> page = new Page<>(pageNum, pageSize);
		// 执行带条件的分页查询
		page = baseMapper.selectPage(page, queryWrapper);

		return buildPageResult(page);
	}

	/**
	 * 功能:无条件分页查询
	 *
	 * @param baseMapper 指定的查询接口
	 * @param request    当前页页码
	 * 
	 * @return Map<String, Object>
	 */
	public Map<String, Object> pageList(BaseMapper<T> baseMapper, HttpServletRequest request) {
		return pageList(baseMapper, Wrappers.emptyWrapper(), request);
	}

	/**
	 * 功能:翻页查询
	 *
	 * @param baseMapper   指定的查询接口
	 * @param queryWrapper 实体对象封装操作类
	 * @param request      当前页页码
	 * 
	 * @return Map<String, Object>
	 */
	public Map<String, Object> pageList(BaseMapper<T> baseMapper, Wrapper<T> queryWrapper, HttpServletRequest request) {
		// 创建分页对象,获取分页信息
		Page<T> page = getPage(request);
		// 执行带条件的分页查询
		page = baseMapper.selectPage(page, queryWrapper);

		return buildPageResult(page);
	}

	/**
	 * 功能:根据请求获取分页对象 该方法从HTTP请求中提取分页参数,并根据这些参数创建一个分页对象
	 * 主要目的是为了简化分页查询的处理过程,将分页相关的逻辑封装到一个方法中
	 *
	 * @param request HTTP请求对象,用于获取分页参数
	 * 
	 * @return 返回一个分页对象,该对象包含了当前页码和每页大小
	 */
	public Page<T> getPage(HttpServletRequest request) {
		// 从URL中获取page参数
		String pageNo = request.getParameter(PAGE_NO);
		// 从URL中获取limit参数
		String pageSize = request.getParameter(PAGE_SIZE);

		// 将参数转换为长整数(注意:这里应该添加异常处理,以防参数不是有效的长整数)
		long current = ObjectUtils.isEmpty(pageNo) ? 1L : Long.parseLong(pageNo); // 默认为第1页
		long size = ObjectUtils.isEmpty(pageSize) ? 10L : Long.parseLong(pageSize); // 默认为每页10条
		Page<T> page = new Page<>(current, size);

		return page;
	}

	/**
	 * 功能:构建分页查询结果
	 *
	 * 该方法用于将MyBatis-Plus的Page对象转换为一个包含分页信息和数据的Map对象 主要用于接口返回,以便前端可以获取到分页查询的相关信息和数据
	 *
	 * @param page MyBatis-Plus的Page对象,包含了分页查询的结果和分页信息
	 *
	 * @return 返回一个Map对象,包含了分页码、总记录数、每页记录数和数据列表
	 */
	public Map<String, Object> buildPageResult(Page<T> page) {
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("code", 0);
		map.put("count", page.getTotal());
		map.put("page_count", page.getPages());
		map.put("data", page.getRecords());

		return map;
	}
}

3.2 调用

可以直接new工具类对象,也可以通过注入方式

import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qfx.modules.common.handler.PageHandler;
import com.qfx.modules.system.dao.SysUserDao;
import com.qfx.modules.system.entity.SysUser;
import com.qfx.modules.system.service.SysUserSer;

@Service
public class SysUserSerImpl extends ServiceImpl<SysUserDao, SysUser> implements SysUserSer {

	@Autowired
	private HttpServletRequest request;
	@Autowired
	private PageHandler<SysUser> pageHandler;
	@Autowired
	private SysUserDao sysUserDao;

	@Override
	public Map<String, Object> page(SysUser sysUser) {
		// 方式一,使用QueryWrapper
		// 将user_name设置为like条件,其他sysUser对象参数eq条件
//		QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>();
//		if (!ObjectUtils.isEmpty(sysUser.getUserName())) {
//			queryWrapper.like("user_name", sysUser.getUserName());
//			sysUser.setUserName(null);
//		}
//		queryWrapper.setEntity(sysUser);

		// 方式二,使用LambdaQueryWrapper(推荐)
		// 将user_name设置为like条件,其他sysUser对象参数eq条件
		LambdaQueryWrapper<SysUser> lambdaQueryWrapper = new LambdaQueryWrapper<>();
		if (!ObjectUtils.isEmpty(sysUser.getUserName())) {
			lambdaQueryWrapper.like(SysUser::getUserName, sysUser.getUserName());
			sysUser.setUserName(null);
		}
		lambdaQueryWrapper.setEntity(sysUser);

		return pageHandler.pageList(baseMapper, lambdaQueryWrapper, request);
	}
}

MyBatis-plus实现分页查询的封装_分页查询_02

核心代码:pageHandler.pageList(baseMapper, lambdaQueryWrapper, request);

第一个参数baseMapper是固定写法:com.baomidou.mybatisplus.extension.service.impl.ServiceImpl.baseMapper

4.自定义sql分页

4.1 xxxMapper.java编写接口方法

必须类型必须是:Page<实体类> 格式

import org.springframework.stereotype.Repository;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.qfx.modules.system.entity.SysUser;

@Repository
public interface SysUserDao extends BaseMapper<SysUser> {
	
	/**
	 * 自定义分页查询
	 * @param page MyBatis-plus分页插件信息
	 * @return IPage<SysUser>
	 */
	Page<SysUser> selectList(Page<SysUser> page, SysUser sysUser);
}

MyBatis-plus实现分页查询的封装_分页查询_03

4.2 调用

调用方式基本一致,只不过是要将对应的xxxMapper接口实例化,建议通过注入方式实现,同样需要实例化pageHandler类

import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qfx.modules.common.handler.PageHandler;
import com.qfx.modules.system.dao.SysUserDao;
import com.qfx.modules.system.entity.SysUser;
import com.qfx.modules.system.service.SysUserSer;

@Service
public class SysUserSerImpl extends ServiceImpl<SysUserDao, SysUser> implements SysUserSer {
	
	@Autowired
  private HttpServletRequest request;
  @Autowired
  private PageHandler<SysUser> pageHandler;
  @Autowired
  private SysUserDao sysUserDao;

	@Override
	public Map<String, Object> pageExtTwo(SysUser sysUser) {
		// 获取分页对象
		Page<SysUser> page = pageHandler.getPage(request);
		
		// 调用自定义分页查询方法
		page = sysUserDao.selectList(page, sysUser);
		
		// 构建分页查询结果
		return pageHandler.buildPageResult(page);
	}
}

MyBatis-plus实现分页查询的封装_mybatis-plus_04