网上有很多封装的mybatis 分页拦截器,但是看起来都比较乱,不能直接套用,在这里贴出项目中的分页源码出来供大家参考。
Controller 层:
@RequestMapping("/channelList") public String channelList(HttpServletRequest request,AppMarket appMarket,Model model){ String pageNo = request.getParameter("pageNo"); Page page = new Page(); if (StringUtils.isNotBlank(pageNo)) { page.setPageNo(Integer.parseInt(pageNo)); } RowBounds rowBounds = PageTools.getRowBounds(page); appMarket = (AppMarket) StringTools.spacialCharForHtml(appMarket); List<AppMarket> marketList = appMarketService.selectMarkets(appMarket, rowBounds); for (int i = 0; i < marketList.size(); i++) { marketList.set(i, (AppMarket) StringTools.spacialCharForHtml(marketList.get(i))); } model.addAttribute("marketName",appMarket.getMarketName()); model.addAttribute("marketList",marketList); long totalCount = appMarketService.selectTotalCount(); page.setTotalRecordNum(totalCount); model.addAttribute("page",page); return "channel/channel_list"; }
先定义好page的属性,再用RowsBounds 类进行数据封装。
Page 类:
public class Page implements Serializable{ private static final long serialVersionUID = 5953682584953355175L; private Integer pageSize=10; private Integer pageNo=1; private long totalPageNum; private long totalRecordNum; public Integer getPageSize() { return pageSize; } public void setPageSize(Integer pageSize) { this.pageSize = pageSize; } public Integer getPageNo() { return pageNo; } public void setPageNo(Integer pageNo) { this.pageNo = pageNo; } public Long getTotalPageNum() { return (totalRecordNum -1)/pageSize +1; } public Long getTotalRecordNum() { return totalRecordNum; } public void setTotalRecordNum(Long totalRecordNum) { this.totalRecordNum = totalRecordNum; } }
PageTools.getRowBounds(page) 方法:
package com.ijiami.appdata.common.page; import org.apache.ibatis.session.RowBounds; public class PageTools{ public static RowBounds getRowBounds(Page page) { if(page.getPageNo()==null||page.getPageSize()==null||page.getPageNo()==0||page.getPageSize()==0){ page.setPageNo(1); page.setPageSize(10); } return new RowBounds((page.getPageNo()-1)*page.getPageSize(), page.getPageSize()); } }
Service 层很简单,直接调用Maper:
@Override public List<AppMarket> selectMarkets(AppMarket record, RowBounds r) { return appMarketMapper.selectMarkets(record, r); }
Maper 对应mybatis 配置:
<select id="selectMarkets" parameterType="com.ijiami.appdata.model.AppMarket" resultMap="BaseResultMap"> select <include refid="Part_Column_List" /> from app_market where 1 = 1 <if test="marketName != null"> and market_name LIKE '%${marketName}%' </if> </select>
最重要的就是接下来的拦截器,将mybatis 将要执行的sql进行拦截封装:
package com.ijiami.appdata.common.page.interceptor; import java.sql.Connection; import java.util.Properties; import org.apache.ibatis.executor.statement.StatementHandler; import org.apache.ibatis.mapping.BoundSql; 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.DefaultReflectorFactory; import org.apache.ibatis.reflection.MetaObject; import org.apache.ibatis.reflection.ReflectorFactory; import org.apache.ibatis.reflection.factory.DefaultObjectFactory; import org.apache.ibatis.reflection.factory.ObjectFactory; import org.apache.ibatis.reflection.wrapper.DefaultObjectWrapperFactory; import org.apache.ibatis.reflection.wrapper.ObjectWrapperFactory; import org.apache.ibatis.session.Configuration; import org.apache.ibatis.session.RowBounds; import com.ijiami.appdata.common.page.dialect.Dialect; import com.ijiami.appdata.common.page.dialect.MySqlDialect; import com.ijiami.appdata.common.page.dialect.OracleDialect; @Intercepts({@Signature(type=StatementHandler.class,method="prepare",args={Connection.class})}) public class PaginationInterceptor implements Interceptor{ private static final ObjectFactory DEFAULT_OBJECT_FACTORY = new DefaultObjectFactory(); private static final ObjectWrapperFactory DEFAULT_OBJECT_WRAPPER_FACTORY = new DefaultObjectWrapperFactory(); private static final ReflectorFactory DEFAULT_REFLECTOR_FACTORY = new DefaultReflectorFactory(); @Override public Object intercept(Invocation invocation) throws Throwable { StatementHandler statementHandler = (StatementHandler)invocation.getTarget(); BoundSql boundSql = statementHandler.getBoundSql(); MetaObject metaStatementHandler = MetaObject.forObject(statementHandler,DEFAULT_OBJECT_FACTORY,DEFAULT_OBJECT_WRAPPER_FACTORY, DEFAULT_REFLECTOR_FACTORY); RowBounds rowBounds = (RowBounds)metaStatementHandler.getValue("delegate.rowBounds"); if(rowBounds == null || rowBounds == RowBounds.DEFAULT){ return invocation.proceed(); } Configuration configuration = (Configuration)metaStatementHandler.getValue("delegate.configuration"); Dialect.Type databaseType = null; try{ databaseType = Dialect.Type.valueOf(configuration.getVariables().getProperty("dialect").toUpperCase()); } catch(Exception e){ //ignore } if(databaseType == null){ throw new RuntimeException("the value of the dialect property in configuration.xml is not defined : " + configuration.getVariables().getProperty("dialect")); } Dialect dialect = null; switch(databaseType){ case MYSQL: dialect = new MySqlDialect(); break; case ORACLE: dialect = new OracleDialect(); break; default: dialect = new MySqlDialect(); } String originalSql = (String)metaStatementHandler.getValue("delegate.boundSql.sql"); metaStatementHandler.setValue("delegate.boundSql.sql", dialect.getLimitString(originalSql, rowBounds.getOffset(), rowBounds.getLimit()) ); metaStatementHandler.setValue("delegate.rowBounds.offset", RowBounds.NO_ROW_OFFSET ); metaStatementHandler.setValue("delegate.rowBounds.limit", RowBounds.NO_ROW_LIMIT ); System.out.println("key="+boundSql.getSql()); return invocation.proceed(); } @Override public Object plugin(Object target) { return Plugin.wrap(target, this); } @Override public void setProperties(Properties properties) { } }