MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变。
添加依赖如下,需要注意的是,不要再次配置其他分页插件,否则可能导致分页返回结果total=0:
1.0.5
2.2.0
com.baomidou
mybatisplus-spring-boot-starter
${mybatisplus.spring.boot.version}
com.baomidou
mybatis-plus
${mybatisplus.version}
根据自己的需求,在 application.properties
配置相关信息:
mybatis-plus.mapper-locations=classpath:mapper/*.xml #配置xml文件扫描
mybatis-plus.typeAliasesPackage=com.df.dsell.mobile.pojo #配置实体扫描
mybatis-plus.global-config.db-column-underline=true
mybatis-plus.global-config.sql-injector=com.baomidou.mybatisplus.mapper.LogicSqlInjector
mybatis-plus.configuration.map-underscore-to-camel-case=true
mybatis-plus.configuration.cache-enabled=false
mybatis-plus.configuration.call-setters-on-nulls=true
代码也配置一把:
import com.baomidou.mybatisplus.plugins.PaginationInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@MapperScan("com.df.dsell.mobile.dao") //配置dao扫描
public class MapperScanConfig {
@Bean
public PaginationInterceptor paginationInterceptor() { //分页插件
PaginationInterceptor page = new PaginationInterceptor();
page.setDialectType("mysql"); //指定数据库类型
return page;
}
}
单表分页很简单,这里只写核心部分。
import com.baomidou.mybatisplus.mapper.BaseMapper;
@Mapper
public interface BkXcOrderDao extends BaseMapper { //dao接口继承BaseMapper,BkXcOrder为pojo
}
public interface BkXcOrderService {
/**
* @描叙: 分页查询 历史记录
* 传递分页参数 如下:
* page :当前页,默认是1
* limit: 每页的数量 默认10
* sidx: 排序字段
* order: ASC || DESC 即按排序字段 升序或降序
*/
PageUtils queryPage(Map params);
}
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
@Service("BkXcOrderServiceImpl")
public class BkXcOrderServiceImpl extends ServiceImpl implements BkXcOrderService {//service 实现类继承ServiceImpl,BkXcOrderService 为service 基类
@Override
public PageUtils queryPage(Map params) {//param为前端传过来的查询参数
String staffGid = (String) params.get("staffGid");
//单表分页
Page page = this.selectPage(
new Query(params).getPage(), //Query为自定义参数提取类
new EntityWrapper()
.eq(StringUtils.isNotBlank(staffGid), "STAFF_GID", staffGid)
);
return new PageUtils(page); //PageUtils自定义page结果封装类
}
}
多表分页有两种,第一种是将多表分页分两次查询,第一次利用单表在主表中查询出分页信息(如total等字段)以及关联的id列表,然后根据这些id列表,使用in条件查询,做关联查询。第二种是一次性操作,只有一条关联查询加上Pagination来实现分页。个人觉得第二种更简单。
下面先看第一种分页查询,在上面已经做了单表分页的基础上,再进一步来关联查询。
逻辑如下:
//先查分页数据
PageUtils page = bkXcOrderService.queryPage(params);
List bkXcOrderList = (List) page.getList();
List ids = new ArrayList<>();
//拼接参数
bkXcOrderList.forEach(item -> {
ids.add(item.getGid());
});
//查询分页service调用
page.setList(bkXcOrderService.queryListByPage(ids, staffGid));
queryListByPage
public interface BkXcOrderService {
...
/**
* @描叙: 根据分页参数查列表
*/
List queryListByPage(List ids, String staffGid);
}
@Service("BkXcOrderServiceImpl")
public class BkXcOrderServiceImpl extends ServiceImpl implements BkXcOrderService {
@Override
public List queryListByPage(List ids, String staffGid) {
return baseMapper.queryListByPage(ids, staffGid);//BkXcOrderDao 中自定义的方法
}
}
import com.baomidou.mybatisplus.mapper.BaseMapper;
@Mapper
public interface BkXcOrderDao extends BaseMapper { //dao接口继承BaseMapper,BkXcOrder为pojo
/**
* @描叙: 根据分页参数查列表
*/
List queryListByPage(@Param("ids") List ids, @Param("staffGid") String staffGid);
}
也就是一次数据查询解决问题,这种很简单
import com.baomidou.mybatisplus.mapper.BaseMapper;
import com.baomidou.mybatisplus.plugins.pagination.Pagination;
import com.df.dsell.mobile.dao.vo.OrderQueryVo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* @ClassName: 中文名:【订单表】
* @description: 订单表 CRUD 操作
*/
@Mapper
public interface DsellOrderFormMapper extends BaseMapper {
/**
* 根据分页插件来实现分页。OrderQueryVo自定义VO
*
* @param page Pagination
* @param userId 用户id
* @param orderStatus 订单状态
* @return
*/
List queryListByPage(Pagination page, @Param("userId") String userId, @Param("orderStatus") Integer orderStatus);
}
xml文件为很简单的关联查询操作
public interface DsellOrderFormService {
/**
* 根据分页插件来实现分页
* @param page Pagination
* @param userId 用户id
* @param orderStatus 订单状态
* @return
*/
List queryListByPage(Pagination page, String userId, Integer orderStatus);
}
import com.baomidou.mybatisplus.plugins.pagination.Pagination;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.df.dsell.mobile.dao.DsellOrderFormMapper;
import com.df.dsell.mobile.dao.vo.OrderQueryVo;
import com.df.dsell.mobile.pojo.DsellOrderForm;
import com.df.dsell.order.service.DsellOrderFormService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class DsellOrderFormServiceImpl extends ServiceImpl implements DsellOrderFormService {
@Override
public List queryListByPage(Pagination page, String userId, Integer orderStatus) {
return baseMapper.queryListByPage(page,userId,orderStatus);
}
}
//构建分页参数
Page page = new Query(params).getPage();
//调用分页查询
List orderQueryVoList = dsellOrderFormService.queryListByPage(page, userId, orderStatus);
//设置结果
page.setRecords(orderQueryVoList);
//结果转换为自己公司规范的分页字段
return new PageUtils(page);
上面用到了两个自定义的辅助类Query和PageUtils
package com.df.dsell.common.utils;
import com.baomidou.mybatisplus.plugins.Page;
import com.df.dsell.common.xss.SQLFilter;
import org.apache.commons.lang.StringUtils;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* @ClassName: 中文名:【分页查询参数】
*/
public class Query extends LinkedHashMap {
private static final long serialVersionUID = 1L;
/**
* mybatis-plus分页参数
*/
private Page page;
/**
* 当前页码
*/
private int pageNum = 1;
/**
* 每页条数
*/
private int pageSize = 10;
public Query(Map params) {
this.putAll(params);
//分页参数
if (params.get("pageNum") != null) {
pageNum = (Integer) params.get("pageNum");
}
if (params.get("pageSize") != null) {
pageSize = (Integer) params.get("pageSize");
}
this.put("offset", (pageNum - 1) * pageSize);
this.put("page", pageNum);
this.put("limit", pageSize);
//防止SQL注入(因为sidx、order是通过拼接SQL实现排序的,会有SQL注入风险)
String sidx = SQLFilter.sqlInject((String) params.get("sidx")); //排序字段
String order = SQLFilter.sqlInject((String) params.get("order")); //ASC | DESC 两个值中的一种
this.put("sidx", sidx);
this.put("order", order);
//mybatis-plus分页
this.page = new Page<>(pageNum, pageSize);
//排序
if (StringUtils.isNotBlank(sidx) && StringUtils.isNotBlank(order)) {
this.page.setOrderByField(sidx);
this.page.setAsc("ASC".equalsIgnoreCase(order));
}
}
public Page getPage() {
return page;
}
public int getPageNum() {
return pageNum;
}
public int getPageSize() {
return pageSize;
}
}
package com.df.dsell.common.utils;
import com.baomidou.mybatisplus.plugins.Page;
import lombok.Data;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
/**
* @description: mybatis-plus专用分页工具
*/
@Data
public class PageUtils implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 当前页数
*/
private Long pageNum = 1L;
/**
* 每页记录数
*/
private Integer pageSize = 10;
/**
* 列表数据
*/
private List> entities;
/**
* 总页数
*/
private Long count = 1L;
/**
* 总记录数
*/
private Long total = 1L;
/**
* 第一页
*/
private boolean isFirstPage = false;
/**
* 最后一页
*/
private boolean isLastPage = false;
/**
* 分页
*
* @param entities 列表数据
* @param total 总记录数
* @param pageSize 每页记录数
* @param pageNum 当前页数
*/
public PageUtils(List> entities, Long total, int pageSize, Long pageNum) {
this.entities = entities;
this.total = total;
this.pageSize = pageSize;
this.pageNum = pageNum;
this.count = (long) Math.ceil((double) total / pageSize);
if (entities instanceof Collection) {
this.judgePageBoudary();
}
}
/**
* 分页
*/
public PageUtils(Page> page) {
this.entities = page.getRecords();
this.total = page.getTotal();
this.pageSize = page.getSize();
this.pageNum = (long) page.getCurrent();
this.count = page.getPages();
this.judgePageBoudary();
}
/**
* 参数
*/
private void judgePageBoudary() {
this.isFirstPage = this.pageNum == 1L;
this.isLastPage = this.pageNum == this.count;
}
}
package com.df.dsell.common.xss;
import com.df.dsell.common.exception.ParameterException;
import com.df.framework.core.vo.ResponseConstant;
import org.apache.commons.lang.StringUtils;
/**
* @description: SQL过滤
*/
public class SQLFilter {
/**
* SQL注入过滤
*
* @param str 待验证的字符串
*/
public static String sqlInject(String str) {
if (StringUtils.isBlank(str)) {
return null;
}
//去掉'|"|;|\字符
str = StringUtils.replace(str, "'", "");
str = StringUtils.replace(str, "\"", "");
str = StringUtils.replace(str, ";", "");
str = StringUtils.replace(str, "\\", "");
//转换成小写
str = str.toLowerCase();
//非法字符
String[] keywords = {"master", "truncate", "insert", "select", "delete", "update", "declare", "alert", "drop"};
//判断是否包含非法字符
for (String keyword : keywords) {
if (str.indexOf(keyword) != -1) { //ParameterException为继承RuntimeException的自定义异常
throw new ParameterException(ResponseConstant.VALIDATE_EXCEPTION,"包含非法字符");
}
}
return str;
}
}
文章比较长,需要耐心看才能看明白,尤其是那多表分页两种分页的第一种。不过个人还是推荐使用第二种,因为一个查询能解决的问题,为何要用两个查询呢!