MyBatis 简单的分页

MyBatis

MyBatis内部大概实现原理是用一个List 保存Key的位置,然后用一个Map对应Key的值

复制粘贴网上代码,终于出来了。。。

==========================

一定要紧跟要分页的dao查询语句的上面,如果有多个查询语句以startPage下面第一个才会被分页
public Page getBySoftware(int softwareId,int pageNum,int pageSize,int oprId) {
Page page=PageHelper.startPage(pageNum, pageSize, SoftwareUser.class);
dao.selectBySoftware(softwareId);//这里也会返回分页后的 数据 page中的result 中也有保存
return page;
}

或者

Page page=PageHelper.startPage(1, 10, User.class);
List list = dao.selectList();
page.setResult(list);
return page;

Page page=PageHelper.startPage(1, 10, User.class);
dao.selectList();
return page;

Page page=PageHelper.startPage(1, 10,”user_name”,OrderByType.DESC User.class);
dao.selectList();
return page;





**Mysql 分页实现**
--------------

package isxiatian.mybatis.plugin.parser;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.session.Configuration;

import isxiatian.mybatis.plugin.Page;

/**
* mysql 分页
* @author xia
*
*/
public class MySqlParser implements Parser {

//setParameterKeys 是设置sql 的预编译 参数 key  必须是有序列表
//比如 select * from user where name=? limit ?,?      第一个?=key1 第二个?=key2 ....以此类推
//key1,key2 自己随便取,和sql 语句中的  ? 顺序对应就可以了


//setParameterValues 是设置 sql key值  是Map字典 对应上面设置的key 添加对应的 key值就可以了
//比如:key1=李白 , key2=0 key3=10





@Override
public List<ParameterMapping> setParameterKeys(Configuration configuration,
        List<ParameterMapping> parameterMappings, Page page) {
    List<ParameterMapping> newParameterMappings = new ArrayList<ParameterMapping>();
    newParameterMappings.addAll(parameterMappings);
    String orderby=page.getOrderby();
    if(orderby != null && !orderby.equals("")){
        newParameterMappings.add(new ParameterMapping.Builder(configuration, PAGEPARAMETER_ORDERBY, String.class).build());
        newParameterMappings.add(new ParameterMapping.Builder(configuration, PAGEPARAMETER_ORDERBYTYPE, String.class).build());
    }
    newParameterMappings.add(new ParameterMapping.Builder(configuration,PAGEPARAMETER_FIRST,Integer.class).build());
    newParameterMappings.add(new ParameterMapping.Builder(configuration,PAGEPARAMETER_SECOND,Integer.class).build());
    return newParameterMappings;
}

@Override
public Map<String, Object> setParameterValues(Map<String, Object> parameterMappings, Page page) {
    String orderby=page.getOrderby();
    Map<String, Object> newMap = parameterMappings;
    if(orderby != null && !orderby.equals("")){
        newMap.put(PAGEPARAMETER_ORDERBY, page.getOrderby());
        newMap.put(PAGEPARAMETER_ORDERBYTYPE,page.getOrderByType());
    }
    newMap.put(PAGEPARAMETER_FIRST, page.getStartRow());
    newMap.put(PAGEPARAMETER_SECOND,page.getPageSize());
    return newMap;
}

@Override
public String getPageSql(String sql,Page page) {
    StringBuilder sqlBuilder = new StringBuilder(sql.length() + 14);
    sqlBuilder.append(sql);
    String orderby=page.getOrderby();
    if(orderby != null && !orderby.equals(""))
        sqlBuilder.append(" order by ? ?");
    sqlBuilder.append(" limit ?,?");
    return sqlBuilder.toString();
}

@Override
public String getCountSql(String sql) {
    return "select count(0) from (" + sql + ") as " + SUFFIX_COUNT;
}

}




**

=========================
--------------

**MyBatis 拦截器**
**

package isxiatian.mybatis.plugin;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.apache.ibatis.builder.StaticSqlSource;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.mapping.SqlSource;
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 org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.log4j.Logger;

import isxiatian.mybatis.plugin.parser.MySqlParser;
import isxiatian.mybatis.plugin.parser.Parser;

/**
* Mybatis - 通用分页拦截器
* @author xia
*
*/
@Intercepts(@Signature(type = Executor.class, method = “query”, args = { MappedStatement.class, Object.class,
RowBounds.class, ResultHandler.class }))
public class PageHelper implements Interceptor,ParserData {

private static final Logger LOGGER = Logger.getLogger(PageHelper.class);

@SuppressWarnings("rawtypes")
private static final ThreadLocal<Page> localPage = new ThreadLocal<Page>();
private static Parser parser = null;


/**
 * 开始分页
 * 
 * @param pageNum
 * @param pageSize
 */
public static <E> Page<E> startPage(int pageNum, int pageSize,Class<E> resultType) {
    Page<E> page=new Page<E>(pageNum, pageSize);
    localPage.set(page);
    return page;
}

public static <E> Page<E> startPage(int pageNum, int pageSize,String orderby,Class<E> resultType) {
    Page<E> page=new Page<E>(pageNum, pageSize,orderby);
    localPage.set(page);
    return page;
}

public static <E> Page<E> startPage(int pageNum, int pageSize,String orderby,OrderByType orderByType,Class<E> resultType) {
    Page<E> page =new Page<E>(pageNum, pageSize,orderby,orderByType);
    localPage.set(page);
    return page;
}


@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public Object intercept(Invocation invocation) throws Throwable {
     //获取Page
    Page page=localPage.get();
    if ( page == null || page.getPageSize() <= 0) {
        return invocation.proceed();
    }
    //忽略Mybatis自带的内存分页
    RowBounds rowBounds=(RowBounds)invocation.getArgs()[2];
    invocation.getArgs()[2] = RowBounds.DEFAULT;

    MappedStatement mappedStatement = (MappedStatement)invocation.getArgs()[0];
    Object parameter = invocation.getArgs()[1];
    //不是查询跳过
    if(mappedStatement.getSqlCommandType() != SqlCommandType.SELECT)
        return invocation.proceed();

    Configuration configuration = mappedStatement.getConfiguration();
    BoundSql boundSql = mappedStatement.getBoundSql(parameter);

    //获取连接
    Connection connection=mappedStatement.getConfiguration().getEnvironment().getDataSource().getConnection();
    //重设分页参数里的总页数等
    setPageParameter(boundSql.getSql(), connection, mappedStatement, boundSql, page);

    //越界则取最后一页
    if(page.getEndRow()>page.getPages()*page.getPageSize())
    {
        page.setPageNum(page.getPages());
        page.setStartRow((page.getPageNum()-1)*page.getPageSize());
        page.setEndRow(page.getPageNum()*page.getPageSize());
    }

    //获取参数 列表
    List<ParameterMapping> newParameterMappings =parser.setParameterKeys(configuration, boundSql.getParameterMappings(), page);
    //获取 分页sql
    String newSql=parser.getPageSql(boundSql.getSql(),page);
    StaticSqlSource sqlsource = new StaticSqlSource(configuration,newSql,newParameterMappings);
    //替换ms
    invocation.getArgs()[0]=newMappedStatement(mappedStatement,sqlsource,SUFFIX_PAGE);

    //获取参数 数值
    Map<String, Object> map = setPageParameter(mappedStatement,parameter,mappedStatement.getBoundSql(parameter));
    Map<String, Object> newMap=parser.setParameterValues(map, page);
    int i=1;
    //防止使用 sql 使用 下标作为参数 报错
    for (ParameterMapping parameterMapping : newParameterMappings) {
        newMap.put("param"+i++, newMap.get(parameterMapping.getProperty()));
    }
    //替换参数
    invocation.getArgs()[1]=newMap;
    Object result = invocation.proceed();

    page.setResult((List)result);
    localPage.remove();

    //还原
    invocation.getArgs()[0]=mappedStatement;
    invocation.getArgs()[1]=parameter;
    invocation.getArgs()[2]=rowBounds;

    return result;
}







/**
 * 获取总记录数
 * 
 * @param sql
 * @param connection
 * @param mappedStatement
 * @param boundSql
 * @param page
 */
@SuppressWarnings("rawtypes")
private void setPageParameter(String sql, Connection connection, MappedStatement mappedStatement, BoundSql boundSql,
        Page page) {
    // 记录总记录数
    String countSql = parser.getCountSql(sql);
    PreparedStatement countStmt = null;
    ResultSet rs = null;
    try {
        countStmt = connection.prepareStatement(countSql);
        BoundSql countBS = new BoundSql(mappedStatement.getConfiguration(), countSql,
                boundSql.getParameterMappings(), boundSql.getParameterObject());
        //设置原来的动态参数 比如循环之类的参数
        for(ParameterMapping parameterMapping:boundSql.getParameterMappings()){
            if(boundSql.hasAdditionalParameter(parameterMapping.getProperty()))
                countBS.setAdditionalParameter(parameterMapping.getProperty(), boundSql.getAdditionalParameter(parameterMapping.getProperty()));
        }
        setParameters(countStmt, mappedStatement, countBS, boundSql.getParameterObject());
        rs = countStmt.executeQuery();
        int totalCount = 0;
        if (rs.next()) {
            totalCount = rs.getInt(1);
        }
        page.setTotal(totalCount);
        int totalPage = totalCount / page.getPageSize() + ((totalCount % page.getPageSize() == 0) ? 0 : 1);
        page.setPages(totalPage);
    } catch (SQLException e) {
        LOGGER.error("Ignore this exception", e);
    } finally {
        try {
            rs.close();
        } catch (SQLException e) {
            LOGGER.error("Ignore this exception", e);
        }
        try {
            countStmt.close();
        } catch (SQLException e) {
            LOGGER.error("Ignore this exception", e);
        }
    }
}






/**
 * 代入参数值
 * 
 * @param ps
 * @param mappedStatement
 * @param boundSql
 * @param parameterObject
 * @throws SQLException
 */
private void setParameters(PreparedStatement ps, MappedStatement mappedStatement, BoundSql boundSql,
        Object parameterObject) throws SQLException {
    ParameterHandler parameterHandler = new DefaultParameterHandler(mappedStatement, parameterObject, boundSql);
    parameterHandler.setParameters(ps);
}





/**
 * 创建 MappedStatement
 * @param ms
 * @param sqlSource
 * @param suffix MappedStatement id
 * @return MappedStatement
 */
private MappedStatement newMappedStatement(MappedStatement ms, SqlSource sqlSource,String suffix) {
    String id = ms.getId() + suffix;
    MappedStatement.Builder builder = new MappedStatement.Builder(ms.getConfiguration(), id, sqlSource, ms.getSqlCommandType());
    builder.resource(ms.getResource());
    builder.fetchSize(ms.getFetchSize());
    builder.statementType(ms.getStatementType());
    builder.keyGenerator(ms.getKeyGenerator());
    if (ms.getKeyProperties() != null && ms.getKeyProperties().length != 0) {
        StringBuilder keyProperties = new StringBuilder();
        for (String keyProperty : ms.getKeyProperties()) {
            keyProperties.append(keyProperty).append(",");
        }
        keyProperties.delete(keyProperties.length() - 1, keyProperties.length());
        builder.keyProperty(keyProperties.toString());
    }
    builder.timeout(ms.getTimeout());
    builder.parameterMap(ms.getParameterMap());
    builder.resultMaps(ms.getResultMaps());
    builder.resultSetType(ms.getResultSetType());
    builder.cache(ms.getCache());
    builder.flushCacheRequired(ms.isFlushCacheRequired());
    builder.useCache(ms.isUseCache());

    return builder.build();
}




/**
 * 获取参数
 * @param ms
 * @param parameterObject
 * @param boundSql
 * @return
 */
@SuppressWarnings({ "rawtypes", "unchecked" })
public Map<String, Object> setPageParameter(MappedStatement ms, Object parameterObject, BoundSql boundSql) {
    Map<String, Object> paramMap = null;
    if (parameterObject == null) {
        paramMap = new HashMap<String, Object>();
    } else if (parameterObject instanceof Map) {
        //解决不可变Map的情况
        paramMap = new HashMap<String, Object>();
        paramMap.putAll((Map) parameterObject);
    } else {
        paramMap = new HashMap<String, Object>();
        //动态sql时的判断条件不会出现在ParameterMapping中,但是必须有,所以这里需要收集所有的getter属性
        //TypeHandlerRegistry可以直接处理的会作为一个直接使用的对象进行处理
        boolean hasTypeHandler = ms.getConfiguration().getTypeHandlerRegistry().hasTypeHandler(parameterObject.getClass());

        if (!hasTypeHandler) {
            MetaObject metaObject = SystemMetaObject.forObject(parameterObject);
            for (String name : metaObject.getGetterNames()) {
                paramMap.put(name, metaObject.getValue(name));
            }
        }
        //下面这段方法,主要解决一个常见类型的参数时的问题
        if (boundSql.getParameterMappings() != null && boundSql.getParameterMappings().size() > 0) {
            for (ParameterMapping parameterMapping : boundSql.getParameterMappings()) {
                String name = parameterMapping.getProperty();
                if (!name.equals(PAGEPARAMETER_FIRST)
                        && !name.equals(PAGEPARAMETER_SECOND)
                        && paramMap.get(name) == null) {
                    if (hasTypeHandler
                            || parameterMapping.getJavaType().equals(parameterObject.getClass())) {
                        paramMap.put(name, parameterObject);
                        break;
                    }
                }
            }
        }
    }
    //设置原来的动态参数 比如循环之类的参数
    for(ParameterMapping parameterMapping:boundSql.getParameterMappings()){
        if(boundSql.hasAdditionalParameter(parameterMapping.getProperty()))
            paramMap.put(parameterMapping.getProperty(), boundSql.getAdditionalParameter(parameterMapping.getProperty()));
    }
    return paramMap;
}








@Override
public Object plugin(Object target) {
    if (target instanceof Executor)
        return Plugin.wrap(target, this);
    return target;
}

@Override
public void setProperties(Properties properties) {
    //获取 分页插件实现 默认Mysql
    String sqlparser=properties.getProperty("sqlParser");
    if(sqlparser != null && !"".equals(sqlparser))
    {
        Exception exception=null;
        //创建分页插件对象
        try {
            Class<?> parserClass = Class.forName(sqlparser);
            if(Parser.class.isAssignableFrom(parserClass))
                parser=(Parser)parserClass.newInstance();
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
            exception=e;
        }
        if(parser == null && exception != null)
            throw new RuntimeException(exception);
    }
    else
    {
        parser=new MySqlParser();
    }
}

}



使用方式
----
**1.让拦截器生效**

我这里没有 吧MyBatis 配置文件单独分出来,而是和spring 配置文件结合了










sqlParser=isxiatian.mybatis.plugin.parser.MySqlParser










    <!-- 自动扫描mapping.xml文件 -->
    <property name="mapperLocations" value="classpath:dao/mapper/*.xml" />
</bean>

**如果是单独的 MyBatis 配置文件 参考看下面,这一种我没用过,不行的话,自行脑补**








<plugins>
    <plugin interceptor="isxiatian.mybatis.plugin.PageHelper">
        <property name="sqlParser" value="isxiatian.mybatis.plugin.parser.MySqlParser" />
    </plugin>
</plugins>


**2.代码上的使用**
注意 PageHelper.startPage 下面 的第一个查询 会进行分页
后面分页 需要继续 调用 PageHelper.startPage

PageHelper.startPage 下面第一个一定要进行分页的查询,不要把不需要分页的查询放在 PageHelper.startPage 下面的第一个

public Page getBySoftware(int softwareId,int pageNum,int pageSize,int oprId) {
Page page=PageHelper.startPage(pageNum, pageSize, SoftwareUser.class);
dao.selectBySoftware(softwareId);//这里也会返回分页后的 数据 page中的result 中也有保存
return page;
}

或者

Page page=PageHelper.startPage(1, 10, User.class);
List list = dao.selectList();
page.setResult(list);
return page;

Page page=PageHelper.startPage(1, 10, User.class);
dao.selectList();
return page;

Page page=PageHelper.startPage(1, 10,”user_name”,OrderByType.DESC User.class);
dao.selectList();
return page;


利用Jackson 返回JSON数据  

Page page=PageHelper.startPage(1, 10, User.class);
dao.selectList();
return Json.getJson(page);


以上都是正确的使用方式

**下面这个是错误的**

Page page=PageHelper.startPage(1, 10, User.class);
User user=dao.selectId(1);//这里这样写的话,会把 selectId 变成分页语句,后面真正需要分页的没有进行分页
dao.selectList();
return page;
“`

代码

链接
http://download.csdn.net/download/carlyle123/9900826

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值