Mybatis单表分页查询

本文以user表为例来记录一种Mybatis单表分页查询实现。
文中关于扩展文件的内容请参考:Spring Boot整合Mybatis框架在扩展文件编写自己的sql语句

1、在扩展查询接口基类BaseMapperExt.java中定义单表查询接口,但是针对某张表一定要有对应的扩展Mapper类继承它,比如要实现user表分页查询,一定要有接口类UserMapperExt.java继承BaseMapperExt.java,然后还要有与之对应的UserMapperExt.xml,具体请看下文。

package com.beibei.doc.dao.base;

import java.util.List;
import com.beibei.doc.util.Page;

/**
 * 扩展基类
 * @author beibei
 *
 * @param <M> 实体类
 * @param <E> 实体类对应的example类
 */
public interface BaseMapperExt<M, E> {

/**
 * 单表分页查询
 * @param page
 *            分页对象
 * @return
 * @throws Exception
 */
public List<M> selectByExampleListPage(Page<M, E> page);

}

2、让UserMapperExt类继承BaseMapperExt,并且将泛型设置为User, UserExample类

package com.beibei.doc.dao.user.ext;

import com.beibei.doc.dao.base.BaseMapperExt;
import com.beibei.doc.model.user.User;
import com.beibei.doc.model.user.UserExample;

public interface UserMapperExt extends BaseMapperExt<User, UserExample> {

}

3、在与UserMapperExt.java类对应的扩展文件UserMapperExt.xml中加入分页查询代码。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.beibei.doc.dao.user.ext.UserMapperExt" >
  <resultMap id="ExtResultMap" extends="com.beibei.doc.dao.user.UserMapper.BaseResultMap" type="com.beibei.doc.model.user.User" >

  </resultMap>

  <select id="selectByExampleListPage" resultMap="ExtResultMap" parameterType="com.beibei.doc.util.Page">
    select
    <include refid="com.beibei.doc.dao.user.UserMapper.Base_Column_List" />
    from user
    <if test="_parameter != null">
        <include refid="com.beibei.doc.dao.user.UserMapper.Update_By_Example_Where_Clause" />
    </if>
    <if test="orderBy != null">
        order by ${orderBy}
    </if>
    <if test="limit != null">
        limit ${start} , ${limit}
    </if>
    </select>

</mapper>

至此,我们已经在dao层有了分页查询的方法,接下来介绍怎么在业务层实现分页查询。

4、创建分页辅助类Page.java,这个类至关重要,基本上关于分页的核心逻辑都封装在这个类里。

package com.beibei.doc.util;

import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 分页辅助类
 * @author beibei
 *
 * @param <M> 查询结果对应的实体类
 * @param <E> 单表对应的example
 */
public class Page<M, E> implements Serializable {

/**
 * 
 */
private static final long serialVersionUID = 1959424260780112289L;


public Page() {
    
}

/**
 * 初始化nextPage和limit
 * @param param --分页查询参数map
 */
public Page(Map<String, Object> param) {
    String limitStr = StringUtil.getStr(param.get("limit"));
    if(!"".equals(limitStr)){
        this.limit = StringUtil.getInt(param.get("limit"));
        this.nextPage = StringUtil.getInt(param.get("nextPage"));
    }
}

/** 每页默认显示数据条数 */
public static int defaultLimit = 20;

/**是否 distinct */
private boolean distinct = false;

/** 
 * 下一页码,如需要当前页码则该属性减1 
 */
private int nextPage;

/** 
 * 每页显示记录数
 */
private Integer limit;

/** 
 * 起始记录,因为引用的时候不会调用其get方法,因此要通过调用
 */
private int start;

/** 
 * 排序
 */
private String orderBy;

/**
 * 查询参数
 */
private String search;

/**
 * example查询参数
 */
private E example;

/**
 * 其它查询参数,适用于联表查询时候设置条件参数
 */
private Map<String, Object> map = new HashMap<String, Object>();

/**
 * 记录总数
 */
private long total;

/**
 * 总页数
 */
private int pages;

/**
 * 查询结果列表
 */
private List<M> list;

public boolean isDistinct() {
    return distinct;
}
public void setDistinct(boolean distinct) {
    this.distinct = distinct;
}

/**
 * 获取下一页页码必须先初始化:nextPage、limit、total
 * @return
 */
public int getNextPage() {
    if(limit == null){
        return 0;
    }
    if(nextPage*limit >= total){
        return 0;
    } else {
        return nextPage+1;
    }
}
public void setNextPage(int nextPage) {
    this.nextPage = nextPage;
}

public Integer getLimit() {
    return limit;
}
public void setLimit(Integer limit) {
    this.limit = limit;
}

public int getStart() {
    if(this.nextPage < 1){
        this.nextPage = 1;
    }
    if(limit == null){
        return 0;
    }
    this.start = (nextPage - 1) * limit;
    return start;
}
/**
 * 查询页起始记录,分页查询必须设置起始页
 * @param start
 */
public void setStart(int start) {
    this.start = start;
}

public String getOrderBy() {
    return orderBy;
}
/**
 * <pre>
 * 设置排序方式
 * 严格按照sql语句关键词 ORDER BY 后面的排序字段和顺序编写
 * 例如:
 *     以 username 和 age 两个字段的倒序排序, 
 *     应该给orderBy赋值  username DESC, age DESC
 * </pre>
 * @param order
 */
public void setOrderBy(String orderBy) {
    if(orderBy != null){
        orderBy = " " + orderBy + " ";//加空格
    }
    this.orderBy = orderBy;
}

public String getSearch() {
    return search;
}
public void setSearch(String search) {
    this.search = search;
}

public E getExample() {
    return example;
}
public void setExample(E example) {
    this.example = example;
}

/**
 * 其它过滤参数,适用于个性化参数查询
 * @return
 */
public Map<String, Object> getMap() {
    return map;
}
/**
 * 其它过滤参数,适用于个性化参数查询
 * @param map
 */
public void setMap(Map<String, Object> map) {
    this.map = map;
}

public long getTotal() {
    return total;
}
public void setTotal(long total) {
    this.total = total;
}

/**
 * 返回总页数
 * @return
 */
public int getPages() {
    this.pages = 1;
    if(this.limit != null && limit > 0){
        int a = (int) (this.total / this.limit);
        int b = (int) (this.total % this.limit);
        if(b > 0){
            pages = a + 1;
        } else {
            pages = a;
        }
    }
    return pages;
}

public void setPages(int pages) {
    this.pages = pages;
}

public List<M> getList() {
    return list;
}
public void setList(List<M> list) {
    this.list = list;
}

/**
 * <pre>
 * 获取分页查询结果,数据结构如下
 * {
 *       "total": 4,    数据总量
 *       "nextPage": 0, 下一页页码,没有下一页值为 0
 *       "limit": 3,    每页数量
 *       "list": [      查询结果列表
 *       
 *       ]
 * }
 * </pre>
 * 
 * @return
 */
public Map<String, Object> getPageData(){
    Map<String, Object> data = new HashMap<>();
    data.put("nextPage", this.getNextPage());
    data.put("total", this.getTotal());
    data.put("limit", this.getLimit());
    data.put("list", this.getList());
    return data;
}

@Override
public String toString() {
    return "Page [distinct=" + distinct + ", limit=" + limit + ", start="
            + start + ", orderBy=" + orderBy + ", nextPage=" + nextPage
            + ", total=" + total + ", pages=" + pages
            + ", search=" + search + ", example=" + example + ", map="
            + map + "]";
}
}

5、在BaseService.java中加入单表分页查询接口的定义

/**
 * 单表分页查询
 * @param page
 * @return
 */
public Page<M, E> selectByExampleListPage(Page<M, E> page);

/**
 * 分页查询
 * @param param
 * @return
 */
public RespData selectListPage(Map<String, Object> param);

6、在BaseServiceImpl.java中实现selectByExampleListPage接口,在这里封装对dao层数据库查询。

@Autowired
protected BaseMapperExt<M, E> baseMapperExt;
@Override
public Page<M, E> selectByExampleListPage(Page<M, E> page) {
    //查询数据总数
    Integer total = this.countByExample(page.getExample());
    
    //设置数据总数
    page.setTotal(total);
    List<M> list = this.baseMapperExt.selectByExampleListPage(page);
    page.setList(list);
    return page;
}

7、让UserService.java接口类继承BaseService.java

UserService.java

package com.beibei.doc.service.user;

import com.beibei.doc.model.user.User;
import com.beibei.doc.model.user.UserExample;
import com.beibei.doc.service.base.BaseService;

public interface UserService extends BaseService<User, UserExample> {

}

8、让UserServiceImpl.java类继承BaseServiceImpl.java,并且实现selectListPage接口。

package com.beibei.doc.service.user.impl;

import java.util.Map;

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

import com.beibei.doc.dao.user.ext.UserMapperExt;
import com.beibei.doc.model.user.User;
import com.beibei.doc.model.user.UserExample;
import com.beibei.doc.model.user.UserExample.Criteria;
import com.beibei.doc.service.base.impl.BaseServiceImpl;
import com.beibei.doc.service.user.UserService;
import com.beibei.doc.util.Page;
import com.beibei.doc.util.RespData;

@Service
public class UserServiceImpl extends BaseServiceImpl<User, UserExample> implements UserService {

@Autowired
private UserMapperExt userMapperExt;

@Override
public RespData selectListPage(Map<String, Object> param) {
    RespData data = new RespData();
    
    //构建分页查询对象
    Page<User, UserExample> page = new Page<>(param);
    
    //设置查询条件
    UserExample example = new UserExample();
    Criteria criteria = example.createCriteria();
    criteria.andAgeEqualTo(18);
    
    //设置分页数据
    page.setOrderBy("id desc");
    page.setExample(example);
    
    //执行查询提取结果
    page = this.selectByExampleListPage(page);
    Map<String, Object> result = page.getPageData();
    data.setData(result);
    
    return data;
}
}

至此,就可以在Controller中调用分页查询接口对user表数据进行分页查询了,特别注意两个参数:nextPage是查询页码,从1开始;limit是每页数量,如果不传会默认查询全部。

@RequestMapping(value="/list")
public RespData list(@RequestParam Map<String, Object> param){
    RespData data = this.userService.selectListPage(param);
    return data;
}

最后,文中各个文件目录结构如下图

Paste_Image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,200评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,526评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,321评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,601评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,446评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,345评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,753评论 3 387
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,405评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,712评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,743评论 2 314
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,529评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,369评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,770评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,026评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,301评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,732评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,927评论 2 336

推荐阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,514评论 18 399
  • 一. Java基础部分.................................................
    wy_sure阅读 3,778评论 0 11
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,517评论 18 139
  • 昨天结束了自己的2017研究生入学考试初试,走出考场的时候,自己蛮平静的,倒不是自己考的好,而且自己考的太差了,...
    hallelujah666阅读 194评论 0 2
  • 时代变了,你如何跟上节奏? 风口变了,你如何把握机遇? 玩法变了,你如何应对自如? 2017年的微商第一步我们要以...
    肖红千金阅读 409评论 0 0