Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
想必大家都有過(guò)這樣的體驗(yàn),在使用Mybatis時(shí),最頭痛的就是寫(xiě)分頁(yè)了,需要先寫(xiě)一個(gè)查詢count的select語(yǔ)句,然后再寫(xiě)一個(gè)真正分頁(yè)查詢的語(yǔ)句,當(dāng)查詢條件多了之后,會(huì)發(fā)現(xiàn)真的不想花雙倍的時(shí)間寫(xiě) count 和 select,幸好我們有 pagehelper 分頁(yè)插件,pagehelper 是一個(gè)強(qiáng)大實(shí)用的 MyBatis 分頁(yè)插件,可以幫助我們快速的實(shí)現(xiàn)MyBatis分頁(yè)功能,而且pagehelper有個(gè)優(yōu)點(diǎn)是,分頁(yè)和Mapper.xml完全解耦,并以插件的形式實(shí)現(xiàn),對(duì)Mybatis執(zhí)行的流程進(jìn)行了強(qiáng)化,這有效的避免了我們需要直接寫(xiě)分頁(yè)SQL語(yǔ)句來(lái)實(shí)現(xiàn)分頁(yè)功能。那么,接下來(lái)我們就來(lái)一起體驗(yàn)下吧。
接下來(lái),我們就通過(guò)實(shí)際案例來(lái)講解如何使用pagehelper來(lái)實(shí)現(xiàn)MyBatis分頁(yè),為了避免重復(fù)篇幅,此篇教程的源碼基于《Spring Boot:整合MyBatis框架》一篇的源碼實(shí)現(xiàn),讀者請(qǐng)先參考并根據(jù)教程鏈接先行獲取基礎(chǔ)源碼和數(shù)據(jù)庫(kù)內(nèi)容。
首先,我們需要在 pom.xml 文件中添加分頁(yè)插件依賴包。
pom.xml
<!-- pagehelper -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.5</version>
</dependency>
然后在 application.yml 配置文件中添加分頁(yè)插件有關(guān)的配置。
application.yml
# pagehelper
pagehelper:
helperDialect: mysql
reasonable: true
supportMethodsArguments: true
params: count=countSql
首先,在 DAO 層添加一個(gè)分頁(yè)查找方法。這個(gè)查詢方法跟查詢?nèi)繑?shù)據(jù)的方法除了名稱幾乎一樣。
SysUserMapper.java
package com.louis.springboot.demo.dao;
import java.util.List;
import com.louis.springboot.demo.model.SysUser;
public interface SysUserMapper {
int deleteByPrimaryKey(Long id);
int insert(SysUser record);
int insertSelective(SysUser record);
SysUser selectByPrimaryKey(Long id);
int updateByPrimaryKeySelective(SysUser record);
int updateByPrimaryKey(SysUser record);
/**
* 查詢?nèi)坑脩? * @return
*/
List<SysUser> selectAll();
/**
* 分頁(yè)查詢用戶
* @return
*/
List<SysUser> selectPage();
}
然后在 SysUserMapper.xml 中加入selectPage的實(shí)現(xiàn),當(dāng)然你也可以直接用@Select注解將查詢語(yǔ)句直接寫(xiě)在DAO代碼,但我們這里選擇寫(xiě)在XML映射文件,這是一個(gè)普通的查找全部記錄的查詢語(yǔ)句,并不需要寫(xiě)分頁(yè)SQL,分頁(yè)插件會(huì)攔截查詢請(qǐng)求,并讀取前臺(tái)傳來(lái)的分頁(yè)查詢參數(shù)重新生成分頁(yè)查詢語(yǔ)句。
SysUserMapper.xml
<select id="selectPage" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from sys_user
</select>
服務(wù)層通過(guò)調(diào)用DAO層代碼完成分頁(yè)查詢,這里統(tǒng)一封裝分頁(yè)查詢的請(qǐng)求和結(jié)果類,從而避免因?yàn)樘鎿QORM框架而導(dǎo)致服務(wù)層、控制層的分頁(yè)接口也需要變動(dòng)的情況,替換ORM框架也不會(huì)影響服務(wù)層以上的分頁(yè)接口,起到了解耦的作用。
SysUserService.java
package com.louis.springboot.demo.service;
import java.util.List;
import com.louis.springboot.demo.model.SysUser;
import com.louis.springboot.demo.util.PageRequest;
import com.louis.springboot.demo.util.PageResult;
public interface SysUserService {
/**
* 根據(jù)用戶ID查找用戶
* @param userId
* @return
*/
SysUser findByUserId(Long userId);
/**
* 查找所有用戶
* @return
*/
List<SysUser> findAll();
/**
* 分頁(yè)查詢接口
* 這里統(tǒng)一封裝了分頁(yè)請(qǐng)求和結(jié)果,避免直接引入具體框架的分頁(yè)對(duì)象, 如MyBatis或JPA的分頁(yè)對(duì)象
* 從而避免因?yàn)樘鎿QORM框架而導(dǎo)致服務(wù)層、控制層的分頁(yè)接口也需要變動(dòng)的情況,替換ORM框架也不會(huì)
* 影響服務(wù)層以上的分頁(yè)接口,起到了解耦的作用
* @param pageRequest 自定義,統(tǒng)一分頁(yè)查詢請(qǐng)求
* @return PageResult 自定義,統(tǒng)一分頁(yè)查詢結(jié)果
*/
PageResult findPage(PageRequest pageRequest);
}
服務(wù)實(shí)現(xiàn)類通過(guò)調(diào)用分頁(yè)插件完成最終的分頁(yè)查詢,關(guān)鍵代碼是 PageHelper.startPage(pageNum, pageSize),將前臺(tái)分頁(yè)查詢參數(shù)傳入并攔截MyBtis執(zhí)行實(shí)現(xiàn)分頁(yè)效果。
SysUserServiceImpl.java
package com.louis.springboot.demo.service.impl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.louis.springboot.demo.dao.SysUserMapper;
import com.louis.springboot.demo.model.SysUser;
import com.louis.springboot.demo.service.SysUserService;
import com.louis.springboot.demo.util.PageRequest;
import com.louis.springboot.demo.util.PageResult;
import com.louis.springboot.demo.util.PageUtils;
@Service
public class SysUserServiceImpl implements SysUserService {
@Autowired
private SysUserMapper sysUserMapper;
@Override
public SysUser findByUserId(Long userId) {
return sysUserMapper.selectByPrimaryKey(userId);
}
@Override
public List<SysUser> findAll() {
return sysUserMapper.selectAll();
}
@Override
public PageResult findPage(PageRequest pageRequest) {
return PageUtils.getPageResult(pageRequest, getPageInfo(pageRequest));
}
/**
* 調(diào)用分頁(yè)插件完成分頁(yè)
* @param pageQuery
* @return
*/
private PageInfo<SysUser> getPageInfo(PageRequest pageRequest) {
int pageNum = pageRequest.getPageNum();
int pageSize = pageRequest.getPageSize();
PageHelper.startPage(pageNum, pageSize);
List<SysUser> sysMenus = sysUserMapper.selectPage();
return new PageInfo<SysUser>(sysMenus);
}
}
在控制器SysUserController中添加分頁(yè)查詢方法,并調(diào)用服務(wù)層的分頁(yè)查詢方法。
SysUserController.java
package com.louis.springboot.demo.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.louis.springboot.demo.service.SysUserService;
import com.louis.springboot.demo.util.PageRequest;
@RestController
@RequestMapping("user")
public class SysUserController {
@Autowired
private SysUserService sysUserService;
@GetMapping(value="/findByUserId")
public Object findByUserId(@RequestParam Long userId) {
return sysUserService.findByUserId(userId);
}
@GetMapping(value="/findAll")
public Object findAll() {
return sysUserService.findAll();
}
@PostMapping(value="/findPage")
public Object findPage(@RequestBody PageRequest pageQuery) {
return sysUserService.findPage(pageQuery);
}
}
分頁(yè)查詢請(qǐng)求封裝類。
PageRequest.java
package com.louis.springboot.demo.util;
/**
* 分頁(yè)請(qǐng)求
*/
public class PageRequest {
/**
* 當(dāng)前頁(yè)碼
*/
private int pageNum;
/**
* 每頁(yè)數(shù)量
*/
private int pageSize;
public int getPageNum() {
return pageNum;
}
public void setPageNum(int pageNum) {
this.pageNum = pageNum;
}
public int getPageSize() {
return pageSize;
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
}
分頁(yè)查詢結(jié)果封裝類。
PageResult.java
package com.louis.springboot.demo.util;
import java.util.List;
/**
* 分頁(yè)返回結(jié)果
*/
public class PageResult {
/**
* 當(dāng)前頁(yè)碼
*/
private int pageNum;
/**
* 每頁(yè)數(shù)量
*/
private int pageSize;
/**
* 記錄總數(shù)
*/
private long totalSize;
/**
* 頁(yè)碼總數(shù)
*/
private int totalPages;
/**
* 數(shù)據(jù)模型
*/
private List<?> content;
public int getPageNum() {
return pageNum;
}
public void setPageNum(int pageNum) {
this.pageNum = pageNum;
}
public int getPageSize() {
return pageSize;
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
public long getTotalSize() {
return totalSize;
}
public void setTotalSize(long totalSize) {
this.totalSize = totalSize;
}
public int getTotalPages() {
return totalPages;
}
public void setTotalPages(int totalPages) {
this.totalPages = totalPages;
}
public List<?> getContent() {
return content;
}
public void setContent(List<?> content) {
this.content = content;
}
}
分頁(yè)查詢相關(guān)工具類。
PageUtils.java
package com.louis.springboot.demo.util;
import com.github.pagehelper.PageInfo;
public class PageUtils {
/**
* 將分頁(yè)信息封裝到統(tǒng)一的接口
* @param pageRequest
* @param page
* @return
*/
public static PageResult getPageResult(PageRequest pageRequest, PageInfo<?> pageInfo) {
PageResult pageResult = new PageResult();
pageResult.setPageNum(pageInfo.getPageNum());
pageResult.setPageSize(pageInfo.getPageSize());
pageResult.setTotalSize(pageInfo.getTotal());
pageResult.setTotalPages(pageInfo.getPages());
pageResult.setContent(pageInfo.getList());
return pageResult;
}
}
啟動(dòng)應(yīng)用,訪問(wèn):localhost:8088/swagger-ui.html,找到對(duì)應(yīng)接口,模擬測(cè)試,結(jié)果如下。
參數(shù):pageNum: 1, pageSize: 5
參數(shù):pageNum: 2, pageSize: 4
學(xué)習(xí)更多JAVA知識(shí)與技巧,關(guān)注與私信博主(學(xué)習(xí))
xcel表格頁(yè)圍與頁(yè)角這個(gè)地方就是設(shè)置頁(yè)角的地方,可以增加頁(yè)數(shù),可以減少頁(yè)數(shù)。這里可以輸入公式加與減,但是輸入乘號(hào)或者除號(hào)是不行的,只能輸入加號(hào)和減號(hào)。
大家看一下,我把頁(yè)碼減到三,總頁(yè)碼加到二,然后大家看一下結(jié)果,第一頁(yè)就變成負(fù)二了,總頁(yè)數(shù)在二十六頁(yè)基礎(chǔ)上加了二變成二十八了。這個(gè)有什么用?如果想在表格預(yù)覽看一下,想在任何一頁(yè)的時(shí)候插入分頁(yè)符,想從分頁(yè)符那一頁(yè)開(kāi)始算作一,就需要這種設(shè)置。
舉個(gè)例子,從這里隨便找個(gè)地方插入一個(gè)分頁(yè)符,預(yù)覽一下,這就是半張了,第一張不想讓它拍頁(yè)碼,只想讓這一張拍頁(yè)碼,這樣拍總頁(yè)碼還是二十六頁(yè)的總頁(yè)碼,這個(gè)時(shí)候在預(yù)覽的時(shí)候就可以從這設(shè)置了。
頁(yè)面距記憶一般就是頁(yè)眉頁(yè)角,頁(yè)碼減個(gè)一,總頁(yè)數(shù)減個(gè)一,這個(gè)時(shí)候再看,放大一下再看一下,袋就變成第一頁(yè)二十五頁(yè)了,一共二十五張,其中這是第一頁(yè),但是看這下邊一共這是第二頁(yè),一共第二十六頁(yè),所以這種辦法就可以實(shí)現(xiàn)插入分頁(yè)符的時(shí)候按照自己想的頁(yè)開(kāi)始算頁(yè)碼。
設(shè)計(jì)目的就是為了加速開(kāi)發(fā),減少xml的配置。如果你不想寫(xiě)配置文件只需要在配置文件添加相對(duì)應(yīng)的配置就能快速地啟動(dòng)的程序。
通用mapper只支持對(duì)單表的操作,對(duì)單表的增刪改查,無(wú)需在mapper.xml寫(xiě)對(duì)應(yīng)的sql語(yǔ)句,只需要我們調(diào)用相應(yīng)的接口即可。
pagehelper主要是在對(duì)查詢的數(shù)據(jù)進(jìn)行一個(gè)分頁(yè)查詢。
<!-- pagehelp -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.3</version>
</dependency>
<!-- 通用mapper -->
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>1.0.0</version>
</dependency>
2 新建一個(gè)mymapper.java文件,繼承mapper接口
public interface MyMapper<T> extends Mapper<T>, MySqlMapper<T>,ConditionMapper<T> {
//FIXME 特別注意,該接口不能被掃描到,否則會(huì)出錯(cuò)
}
這個(gè)java文件不能和其它mapper放在一起,以免被掃描到。獲取單表數(shù)據(jù)的操作都直接調(diào)用這個(gè)方法。
3 在配置文件上添加以后屬性字段
#jdbc
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/news
spring.datasource.username=數(shù)據(jù)庫(kù)用戶名
spring.datasource.password=數(shù)據(jù)庫(kù)密碼
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.freemarker.request-context-attribute=request
#mapper
mapper.mappers=com.imooc.springboot.mapper.util.MyMapper
mapper.not-empty=false
mapper.identity=MYSQL
#pagehelper
pagehelper.helper-dialect = mysql
pagehelper.reasonable = true
pagehelper.support-methods-arguments = true
pagehelper.params= count= countSql
上面的配置mapper.mappers 是第2步里面文件所在的路徑。
4 添加了controller文件之后,由controller里面的方法去調(diào)用server里面的方法。雖然是有通用mapper方法,但是每次添加一個(gè)server方法之后都要添加對(duì)應(yīng)的mapper方法,這樣開(kāi)發(fā)的也顯得比較繁瑣,所以我們需要一個(gè)通用server類,用這個(gè)類去調(diào)用第二步的方法就可以了。
public interface BaseService<T> {
/**
* 查詢所有
*
* @return 返回所有數(shù)據(jù)
*/
List<T> findAll();
/**
* 添加
*
* @param t 實(shí)體
*
* @return
*/
int save(T t);
/**
* 修改
*
* @param t
* 實(shí)體
* @return
*/
int updateByPrimaryKey(T t);
/**
* 根據(jù)主鍵刪除
*
* @param t 主鍵
*
* @return
*/
int deleteByPrimaryKey(int t);
/**
* 查詢表格列表
* @param t 分頁(yè)參數(shù)
* @return
*/
TableData<T> getTableData(PageBean pageBean);
}
上面只是封裝基本增刪改查的方法,后續(xù)可自行添加方法。
然后添加實(shí)現(xiàn)類
public abstract class BaseServiceImpl<T> implements BaseService<T> {
@Autowired
protected MyMapper<T> mapper;
@Override
public List<T> findAll() {
return mapper.selectAll();
}
@Override
public int save(T t) {
return mapper.insert(t);
}
@Override
public int updateByPrimaryKey(T t) {
return mapper.updateByPrimaryKey(t);
}
@Override
public int deleteByPrimaryKey(int t) {
return mapper.deleteByPrimaryKey(t);
}
@Override
public TableData<T> getTableData(PageBean bean) {
int count = mapper.selectAll().size();
if (count > 0) {
PageHelper.startPage((bean.getOffset()/bean.getLimit()) + 1, bean.getLimit());
List<T> list = this.findAll();
return TableData.bulid(count, list);
}
return TableData.empty();
}
}
注意:我用的編輯器是eclipse,如果用idea編輯器,這里可把a(bǔ)bstract去掉。
然后添加對(duì)應(yīng)的接口和實(shí)現(xiàn)類繼承上面的接口和方法就可以了,比如添加一個(gè)newsserver 接口和newsserverImpl類
public interface NewsService extends BaseService<SysUser> {
}
@Service
public class NewsServiceImpl extends BaseServiceImpl<SysUser> implements NewsService{
}
5 為了減少數(shù)據(jù)庫(kù)服務(wù)器的壓力,一般我們查詢數(shù)據(jù)的時(shí)候都會(huì)使用pagehelper進(jìn)行分頁(yè)查詢,為了更加清晰的顯示我們展示的數(shù)據(jù),使用bootstrap table展示數(shù)據(jù),bootstrap table獲取數(shù)據(jù)有兩種途徑,一種是客戶端模式,即獲取全部數(shù)據(jù)之后,在前端進(jìn)行分頁(yè)展示。另外一種,也就是我們接下來(lái)要說(shuō)的服務(wù)端模式:要獲取的數(shù)據(jù)信息,比如獲取數(shù)據(jù)頁(yè)碼,每一頁(yè)數(shù)據(jù)的大小,都可以通過(guò)前端發(fā)送以上的參數(shù)向后臺(tái)發(fā)請(qǐng)求,后臺(tái)得到這些參數(shù)信息之后返回?cái)?shù)據(jù)。
6 引入bootstrap table相關(guān)的js css文件之后,開(kāi)始在網(wǎng)上找了一些資料之后發(fā)現(xiàn)很多都是要在前端頁(yè)面添加如下繁瑣的配置,
$('#mytable').bootstrapTable({
//請(qǐng)求方法
method: 'get',
//是否顯示行間隔色
striped: true,
//是否使用緩存,默認(rèn)為true,所以一般情況下需要設(shè)置一下這個(gè)屬性(*)
cache: false,
//是否顯示分頁(yè)(*)
pagination: true,
//是否啟用排序
sortable: false,
//排序方式
sortOrder: "desc",
//初始化加載第一頁(yè),默認(rèn)第一頁(yè)
//我設(shè)置了這一項(xiàng),但是貌似沒(méi)起作用,而且我這默認(rèn)是0,- -
//pageNumber:1,
//每頁(yè)的記錄行數(shù)(*)
pageSize: 10,
//可供選擇的每頁(yè)的行數(shù)(*)
pageList: [10, 25, 50, 100],
//這個(gè)接口需要處理bootstrap table傳遞的固定參數(shù),并返回特定格式的json數(shù)據(jù)
url: "${contextPath}/mapper/getTableData",
//默認(rèn)值為 'limit',傳給服務(wù)端的參數(shù)為:limit, offset, search, sort, order Else
//queryParamsType:'',
////查詢參數(shù),每次調(diào)用是會(huì)帶上這個(gè)參數(shù),可自定義
queryParams: queryParams : function(params) {
var subcompany = $('#subcompany option:selected').val();
var name = $('#name').val();
return {
pageNumber: params.offset+1,
pageSize: params.limit,
companyId:subcompany,
name:name
};
},
//分頁(yè)方式:client客戶端分頁(yè),server服務(wù)端分頁(yè)(*)
sidePagination: "server",
//是否顯示搜索
search: false,
//Enable the strict search.
strictSearch: true,
//Indicate which field is an identity field.
idField : "id",
columns: [],
pagination:true
});
每次添加一個(gè)頁(yè)面如果都要添加以上的配置信息也顯得繁瑣,不過(guò)bootstrap-table.js里面有個(gè)默認(rèn)的配置,只需要修改里面的幾個(gè)配置。
contentType: 'application/json',//post請(qǐng)求頭 application/x-www-form-urlencoded; charset=UTF-8'
dataType: 'json',
sidePagination: 'server', // 改成server
當(dāng)我們點(diǎn)擊表格分頁(yè)頁(yè)碼的時(shí)候,獲取改變每頁(yè)顯示的頁(yè)碼時(shí)候,前端會(huì)自動(dòng)調(diào)用queryParams()方法,我們需要將這些數(shù)據(jù)傳遞給后臺(tái),
function queryParams(params) {
var query={};
query["limit"] = params.limit;//第幾條數(shù)據(jù)開(kāi)始
query["offset"] = params.offset;//數(shù)據(jù)大小
return query;
}
6 配合上一步前端的分頁(yè),我們就需要使用pagehelp插件了,同樣我們把這個(gè)分頁(yè)的方法放在通用server類上,
public TableData<T> getTableData(PageBean bean) {
int count = mapper.selectAll().size();
if (count > 0) {
PageHelper.startPage((bean.getOffset()/bean.getLimit()) + 1, bean.getLimit());
List<T> list = this.findAll();
return TableData.bulid(count, list);
}
return TableData.empty();
}
上面的pagehelper.startpage需要做一點(diǎn)改變,前端傳過(guò)來(lái)的是顯示第幾條數(shù)據(jù),但是startpage方法第一個(gè)參數(shù)是顯示第幾頁(yè)的數(shù)據(jù),所以做一個(gè)轉(zhuǎn)換pageoffset/limit +1,然后在查詢數(shù)據(jù),需要注意的是,一定要將startpage方法方法查詢數(shù)據(jù)語(yǔ)句的前一行,不能空行,或者換行。
github源碼:https://github.com/jeremylai7/springboot-bootstrap.git
demo展示:https://www.jeremy7.cn/bootstrap/
*請(qǐng)認(rèn)真填寫(xiě)需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。