In this post we will write a pagination using mybatis and Spring MVC 4.
Create Controller
package com.npf.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import com.npf.model.entity.Student;
import com.npf.model.vo.PageParams;
import com.npf.service.StudentService;
@Controller
public class StudentController {
@Autowired
private StudentService studentService;
@RequestMapping("/student/find")
public ModelAndView findStudentPagination(ModelAndView modelAndView,PageParams pageParams){
List<Student> stuList = studentService.fetchStudentPagination(pageParams);
modelAndView.addObject("stuList", stuList);
modelAndView.addObject("pageParams", pageParams);
modelAndView.setViewName("list");
return modelAndView;
}
}
Configuration
sqlMapConfig.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<plugins>
<plugin interceptor="com.npf.plugin.PaginationPlugin">
<property name="defaultPage" value="1"/>
<property name="defaultPageSize" value="5"/>
<property name="defaultUseFlag" value="true"/>
<property name="defaultCheckFlag" value="true"/>
</plugin>
</plugins>
<mappers>
<package name="com.npf.dao"/>
</mappers>
</configuration>
mybatis plugin:
package com.npf.plugin;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.apache.ibatis.scripting.defaults.DefaultParameterHandler;
import org.apache.ibatis.session.Configuration;
import com.npf.model.vo.PageParams;
/**
*
* @author Jack
*
*/
@Intercepts({@Signature(
type = StatementHandler.class,
method="prepare",
args={Connection.class,Integer.class}
)})
public class PaginationPlugin implements Interceptor {
/**
* 默认页码
*/
private Integer defaultPage;
/**
* 默认每页条数
*/
private Integer defaultPageSize;
/**
* 默认是否启用插件
*/
private Boolean defaultUseFlag;
/**
* 默认是否检测当前页码的正确性
*/
private Boolean defaultCheckFlag;
@Override
public Object intercept(Invocation invocation) throws Throwable {
StatementHandler stmtHandler = getUnProxyObject(invocation);
MetaObject metaStatementHandler = SystemMetaObject.forObject(stmtHandler);
String sql = (String) metaStatementHandler.getValue("delegate.boundSql.sql");
if(!checkSelect(sql)){
return invocation.proceed();
}
BoundSql boundSql = (BoundSql) metaStatementHandler.getValue("delegate.boundSql");
Object parameterObject = boundSql.getParameterObject();
PageParams pageParams = getPageParams(parameterObject);
if(pageParams == null){
return invocation.proceed();
}
Integer pageNum = pageParams.getPage() == null ? this.defaultPage : pageParams.getPage();
Integer pageSize = pageParams.getPageSize() == null ? this.defaultPageSize : pageParams.getPageSize();
Boolean useFlag = pageParams.getUseFlag() == null ? this.defaultUseFlag : pageParams.getUseFlag();
Boolean checkFlag = pageParams.getCheckFlag() == null ? this.defaultCheckFlag : pageParams.getCheckFlag();
if(!useFlag){
return invocation.proceed();
}
int total = getTotal(invocation,metaStatementHandler,boundSql);
setTotalToPageParams(pageParams,total,pageSize);
checkPage(checkFlag,pageNum,pageParams.getTotalPage());
return changeSQL(invocation,metaStatementHandler,boundSql,pageNum,pageSize);
}
private Object changeSQL(Invocation invocation,MetaObject metaStatementHandler, BoundSql boundSql,Integer pageNum, Integer pageSize) throws Exception {
String sql = (String) metaStatementHandler.getValue("delegate.boundSql.sql");
String newSql = "select * from ("+sql+") $paging_table limit ?,?";
metaStatementHandler.setValue("delegate.boundSql.sql", newSql);
java.sql.PreparedStatement ps = (java.sql.PreparedStatement) invocation.proceed();
int count = ps.getParameterMetaData().getParameterCount();
ps.setInt(count-1, (pageNum-1)*pageSize);
ps.setInt(count, pageSize);
return ps;
}
private void checkPage(Boolean checkFlag, Integer pageNum, Integer totalPage) throws Exception {
if(checkFlag){
if(pageNum > totalPage){
throw new Exception("fauil");
}
}
}
private void setTotalToPageParams(PageParams pageParams, int total,Integer pageSize) {
pageParams.setTotal(total);
int totalPage = total % pageSize == 0 ? total / pageSize : total / pageSize + 1;
pageParams.setTotalPage(totalPage);
}
private int getTotal(Invocation invocation,MetaObject metaStatementHandler, BoundSql boundSql) throws SQLException {
MappedStatement mappedStatement = (MappedStatement) metaStatementHandler.getValue("delegate.mappedStatement");
Configuration configuration = mappedStatement.getConfiguration();
String sql = (String) metaStatementHandler.getValue("delegate.boundSql.sql");
String countSql = "select count(*) as total from ("+sql+") $_paging";
Connection connection = (Connection) invocation.getArgs()[0];
java.sql.PreparedStatement ps = null;
int total = 0;
try {
ps = connection.prepareStatement(countSql);
BoundSql countBoundSql = new BoundSql(configuration,countSql,boundSql.getParameterMappings(),boundSql.getParameterObject());
ParameterHandler handler = new DefaultParameterHandler(mappedStatement, boundSql.getParameterObject(), countBoundSql);
handler .setParameters(ps);
ResultSet rs = ps.executeQuery();
while(rs.next()){
total = rs.getInt("total");
}
} finally{
if(ps != null){
ps.close();
}
}
return total;
}
@SuppressWarnings("unchecked")
private PageParams getPageParams(Object parameterObject) {
if(parameterObject == null){
return null;
}
PageParams pageParams = null;
if(parameterObject instanceof Map){
Map<String,Object> paramMap = (Map<String,Object>)parameterObject;
Set<String> keySet = paramMap.keySet();
Iterator<String> iterator = keySet.iterator();
while(iterator.hasNext()){
String key = iterator.next();
Object value = paramMap.get(key);
if(value instanceof PageParams){
return (PageParams) value;
}
}
}else if(parameterObject instanceof PageParams){
pageParams = (PageParams)parameterObject;
}
return pageParams;
}
private boolean checkSelect(String sql) {
String trimSql = sql.trim();
int idx = trimSql.toLowerCase().indexOf("select");
return idx == 0;
}
/**
* 从代理对象中分离出真实对象
* @param invocation
* @return
*/
private StatementHandler getUnProxyObject(Invocation invocation) {
StatementHandler stmtHandler = (StatementHandler) invocation.getTarget();
MetaObject metaStatementHandler = SystemMetaObject.forObject(stmtHandler);
Object object = null;
//分离代理对象链,由于目标类可能被对个拦截器拦截,从而形成多次代理
//通过循环可以分离出最原始的目标类
while(metaStatementHandler.hasGetter("h")){
object = metaStatementHandler.getValue("h");
}
if(object == null){
return stmtHandler;
}
return (StatementHandler) object;
}
@Override
public Object plugin(Object statementHandler) {
return Plugin.wrap(statementHandler, this);
}
@Override
public void setProperties(Properties properties) {
String defaultPage = properties.getProperty("defaultPage", "1");
String defaultPageSize = properties.getProperty("defaultPageSize", "5");
String defaultUseFlag = properties.getProperty("defaultUseFlag", "false");
String defaultCheckFlag = properties.getProperty("defaultCheckFlag", "false");
this.defaultPage = Integer.valueOf(defaultPage);
this.defaultPageSize = Integer.valueOf(defaultPageSize);
this.defaultUseFlag = Boolean.valueOf(defaultUseFlag);
this.defaultCheckFlag = Boolean.valueOf(defaultCheckFlag);
}
public Integer getDefaultPage() {
return defaultPage;
}
public void setDefaultPage(Integer defaultPage) {
this.defaultPage = defaultPage;
}
public Integer getDefaultPageSize() {
return defaultPageSize;
}
public void setDefaultPageSize(Integer defaultPageSize) {
this.defaultPageSize = defaultPageSize;
}
public Boolean getDefaultUseFlag() {
return defaultUseFlag;
}
public void setDefaultUseFlag(Boolean defaultUseFlag) {
this.defaultUseFlag = defaultUseFlag;
}
public Boolean getDefaultCheckFlag() {
return defaultCheckFlag;
}
public void setDefaultCheckFlag(Boolean defaultCheckFlag) {
this.defaultCheckFlag = defaultCheckFlag;
}
}
Add View
list.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<table align="left" border="1">
<tr>
<td>id</td>
<td>userName</td>
<td>password</td>
</tr>
<c:forEach var="stu" items="${stuList}">
<tr>
<td>${stu.id}</td>
<td>${stu.name}</td>
<td>${stu.password}</td>
</tr>
</c:forEach>
</table>
<br/><br/><br/><br/><br/><br/><br/><br/><br/>
<table>
<tr>
<c:if test="${pageParams.page > 1}">
<a href="${pageContext.request.contextPath}/student/find?page=${pageParams.page - 1}">上一页</a>
</c:if>
</tr>
<tr>
<c:if test="${pageParams.page < pageParams.totalPage}">
<a href="${pageContext.request.contextPath}/student/find?page=${pageParams.page + 1}">下一页</a>
</c:if>
</tr>
</table>
</body>
</html>
Open browser and browse: http://localhost:8080/mybatispagination/student/find
click the next button:
the source code link : mybatispagination