在做項目時,好多地方都會用到分頁,以前只是把別人封裝號的分頁拿過來用,從來沒有自己認真研究過,今天我在項目裏要自己開始寫了分頁了,在網上查了一下資料,再結合自己的項目,謝了一個簡單的分頁,主要有三塊核心內容,page實體類,mybatis攔截器,前臺實現分頁:
Page實體類代碼如下:
package com.hrtel.framework.util;
import java.util.List;
import java.util.Map;
import org.apache.log4j.Logger;
import org.codehaus.jackson.map.ObjectMapper;
import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
public class Page {
private static final Logger logger = Logger.getLogger(Page.class);
private static ObjectMapper mapper = new ObjectMapper();
private static String DEFAULT_PAGESIZE = "10";
private int pageNo; // 當前頁碼
private int pageSize; // 每頁行數
private int totalRecord; // 總記錄數
private int totalPage; // 總頁數
private Map<String, String> params; // 查詢條件
private Map<String, List<String>> paramLists; // 數組查詢條件
private String searchUrl; // Url地址
public Page() {
pageNo = 1;
pageSize = Integer.valueOf(DEFAULT_PAGESIZE);
totalRecord = 0;
totalPage = 0;
params = Maps.newHashMap();
paramLists = Maps.newHashMap();
searchUrl = "";
}
public static Page newBuilder(int pageNo, int pageSize, String url) {
Page page = new Page();
page.setPageNo(pageNo);
page.setPageSize(pageSize);
page.setSearchUrl(url);
return page;
}
/**
* 查詢條件轉json
*
* @return
*/
public String getParaJson() {
Map<String, Object> map = Maps.newHashMap();
for (String key : params.keySet()) {
if (params.get(key) != null) {
map.put(key, params.get(key));
}
}
String json = "";
try {
json = mapper.writeValueAsString(map);
} catch (Exception e) {
logger.error("轉換JSON失敗", e);
}
return json;
}
/**
* 數組查詢條件轉JSON
*/
public String getParaListJson() {
Map<String, Object> map = Maps.newHashMap();
for (String key : paramLists.keySet()) {
List<String> lists = paramLists.get(key);
if (lists != null && lists.size() > 0) {
map.put(key, lists);
}
}
String json = "";
try {
json = mapper.writeValueAsString(map);
} catch (Exception e) {
logger.error("轉換JSON失敗", e);
}
return json;
}
/**
* 總件數變化時,更新總頁數並計算顯示樣式
*/
public void refreshPage() {
// 總頁數計算
totalPage = totalRecord % pageSize == 0 ? totalRecord / pageSize : (totalRecord / pageSize + 1);
// 防止超出最末頁(瀏覽途中數據被刪除的情況)
if (pageNo > totalPage && totalPage != 0) {
pageNo = totalPage;
}
}
public int getPageNo() {
return pageNo;
}
public void setPageNo(int pageNo) {
this.pageNo = pageNo;
}
public int getPageSize() {
return pageSize;
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
public int getTotalRecord() {
return totalRecord;
}
public void setTotalRecord(int totalRecord) {
this.totalRecord = totalRecord;
}
public int getTotalPage() {
return totalPage;
}
public void setTotalPage(int totalPage) {
this.totalPage = totalPage;
}
public Map<String, String> getParams() {
return params;
}
public void setParams(Map<String, String> params) {
this.params = params;
}
public Map<String, List<String>> getParamLists() {
return paramLists;
}
public void setParamLists(Map<String, List<String>> paramLists) {
this.paramLists = paramLists;
}
public String getSearchUrl() {
return searchUrl;
}
public void setSearchUrl(String searchUrl) {
this.searchUrl = searchUrl;
}
}
哪個類需要用到分頁,就要在它的實體類裏面加上Page屬性:
private Page page; //分頁
接下來是mybatis的攔截器:
package com.hrtel.framework.util;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Properties;
import org.apache.commons.jxpath.JXPathContext;
import org.apache.commons.jxpath.JXPathNotFoundException;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.MappedStatement.Builder;
import org.apache.ibatis.mapping.ParameterMapping;
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.scripting.defaults.DefaultParameterHandler;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.log4j.Logger;
@Intercepts({@Signature(type=Executor.class,method="query",args={ MappedStatement.class,
Object.class, RowBounds.class, ResultHandler.class })})
public class PageInterceptor implements Interceptor{
private static final Logger logger = Logger.getLogger(PageInterceptor.class);
@Override
public Object intercept(Invocation invocation) throws Throwable {
logger.info("*****into method intercept for mybatis plugin*****");
//當前環境 MappedStatement,BoundSql,及sql取得
MappedStatement mappedStatement=(MappedStatement)invocation.getArgs()[0];
Object parameter = invocation.getArgs()[1];
BoundSql boundSql = mappedStatement.getBoundSql(parameter);
String originalSql = boundSql.getSql().trim();
Object parameterObject = boundSql.getParameterObject();
//Page對象獲取,“信使”到達攔截器!
Page page = searchPageWithXpath(boundSql.getParameterObject(),".","page","*/page");
if (null != page){
//Page對象存在的場合,開始分頁處理
String countSql = getCountSql(originalSql);
Connection connection=mappedStatement.getConfiguration().getEnvironment().getDataSource().getConnection();
PreparedStatement countStmt = connection.prepareStatement(countSql);
BoundSql countBS = copyFromBoundSql(mappedStatement, boundSql, countSql);
DefaultParameterHandler parameterHandler = new DefaultParameterHandler(mappedStatement, parameterObject, countBS);
parameterHandler.setParameters(countStmt);
ResultSet rs = countStmt.executeQuery();
int totpage=0;
if (rs.next()) {
totpage = rs.getInt(1);
}
rs.close();
countStmt.close();
connection.close();
//分頁計算
page.setTotalRecord(totpage);
page.refreshPage();
//對原始Sql追加limit
int offset = (page.getPageNo() - 1) * page.getPageSize();
StringBuffer sb = new StringBuffer();
sb.append(originalSql).append(" limit ").append(offset).append(",").append(page.getPageSize());
BoundSql newBoundSql = copyFromBoundSql(mappedStatement, boundSql, sb.toString());
MappedStatement newMs = copyFromMappedStatement(mappedStatement,new BoundSqlSqlSource(newBoundSql));
invocation.getArgs()[0]= newMs;
}
logger.info("*******method intercept end**********");
return invocation.proceed();
}
@Override
public Object plugin(Object arg0) {
return Plugin.wrap(arg0, this);
}
@Override
public void setProperties(Properties arg0) {
}
/**
* 根據給定的xpath查詢Page對象
*/
private Page searchPageWithXpath(Object o,String... xpaths) {
JXPathContext context = JXPathContext.newContext(o);
Object result;
for(String xpath : xpaths){
try {
result = context.selectSingleNode(xpath);
} catch (JXPathNotFoundException e) {
continue;
}
if ( result instanceof Page ){
return (Page)result;
}
}
return null;
}
/**
* 根據原Sql語句獲取對應的查詢總記錄數的Sql語句
*/
private String getCountSql(String sql) {
return "SELECT COUNT(*) FROM (" + sql + ") aliasForPage";
}
/**
* 複製BoundSql對象
*/
private BoundSql copyFromBoundSql(MappedStatement ms, BoundSql boundSql, String sql) {
BoundSql newBoundSql = new BoundSql(ms.getConfiguration(),sql, boundSql.getParameterMappings(), boundSql.getParameterObject());
for (ParameterMapping mapping : boundSql.getParameterMappings()) {
String prop = mapping.getProperty();
if (boundSql.hasAdditionalParameter(prop)) {
newBoundSql.setAdditionalParameter(prop, boundSql.getAdditionalParameter(prop));
}
}
return newBoundSql;
}
public class BoundSqlSqlSource implements SqlSource {
BoundSql boundSql;
public BoundSqlSqlSource(BoundSql boundSql) {
this.boundSql = boundSql;
}
public BoundSql getBoundSql(Object parameterObject) {
return boundSql;
}
}
/**
* 複製MappedStatement對象
*/
private MappedStatement copyFromMappedStatement(MappedStatement ms,SqlSource newSqlSource) {
Builder builder = new Builder(ms.getConfiguration(),ms.getId(),newSqlSource,ms.getSqlCommandType());
builder.resource(ms.getResource());
builder.fetchSize(ms.getFetchSize());
builder.statementType(ms.getStatementType());
builder.keyGenerator(ms.getKeyGenerator());
String [] s = ms.getKeyProperties();
if (null == s){
builder.keyProperty(null);
}else{
builder.keyProperty(s[0]);
}
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();
}
}
寫了攔截器之後,需要在xml裏面註冊攔截器,我用的框架是springMVC+mybatis結合的,所以我就在spring-mybatis.xml中註冊自己的攔截器:
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!-- 自動掃描mapping.xml文件 -->
<property name="configLocation" value="classpath:sqlMapConfig.xml"/>
<!-- 配置Mybatis的插件plugin -->
<property name="plugins">
<array>
<bean class="com.hrtel.framework.util.PageInterceptor">
<property name="properties">
<value>
property-key=property-value
</value>
</property>
</bean>
</array>
</property>
</bean>
寫完上面的之後,就需要寫前臺的js接收了:
function initPage(){
var pageHtml = "";
var pageNo = page.pageNo;
var pageSize = page.pageSize;
var totalPage = page.totalPage;
var totalRecord = page.totalRecord;
if (pageNo != 1){
pageHtml += "<a href='#' οnclick='onclickMenu(1)' style='text-decoration: none'><b style='font-size: 12'>第一頁</b></a> ";
pageHtml += "<a href='#' οnclick='onclickMenu("+(pageNo-1)+")' style='text-decoration: none'><b style='font-size: 12'>上一頁</b></a> ";
}
if (pageNo != totalPage){
pageHtml += "<a href='#' οnclick='onclickMenu("+(parseInt(pageNo)+1)+")' style='text-decoration: none'><b style='font-size: 12'>下一頁</b></a> ";
pageHtml += "<a href='#' οnclick='onclickMenu("+(parseInt(totalPage))+")' style='text-decoration: none'><b style='font-size: 12'>最後一頁</b></a> ";
}
pageHtml += "頁數:<label id='curpage' style='color: red; font-size: 13'>"+pageNo+"</label>/<label id='wholepages' style='color: red; font-size: 13'>"+totalPage+"</label> ";
pageHtml += "<input id='ppage' type='text' size='5'/><a οnclick='gotoPage()'>跳轉</a> ";
pageHtml += "<label>總條數:"+totalRecord+"</label>";
$('#datePage').html("<tr><td>"+pageHtml+"</td></tr>");
}
每次點擊分頁裏面的按鈕時,都會調用onclickMenu()方法,這個方法主要封裝的是一個ajax,前臺向後臺發送請求:
function onclickMenu(pageNo){
var startTime = $('#startTime').datebox('getValue');
var endTime = $('#endTime').datebox('getValue');
var citys_name = $('#citys_name').val();
var ci = $('#ci').val();
var consumptionFlow_size = $('#consumptionFlow_size').val();
var IMSI = $('IMSI').val();
var MSISDN = $('MSISDN').val();
var resultConlection = $('#resultConlection').val();
var datas = {"pageNo":pageNo, "treeId":nodeId, "startTime":startTime, "endTime":endTime,
"citys_name":citys_name, "ci":ci, "consumptionFlow_size":consumptionFlow_size,
"resultConlection":resultConlection, "IMSI":IMSI, "MSISDN":MSISDN};
$.ajax({
type:'post',
url:path+'/multipleAnalyseController/selectTempManager.do',
dataType:'json',
async: false,
data: datas,
success:function(result){
myStore.removeAll();
dataSource = result.multipleAnalyseList;
myStore.add(dataSource);
page = result.page;
initPage();
}
});
}
後臺controller裏面接收參數以及封裝參數的方法:
@RequestMapping("selectTempManager")
public ModelAndView selectTempManager(HttpServletRequest request, HttpServletResponse response,
@RequestParam(required = false, defaultValue = "1") int pageNo,
@RequestParam(required = false, defaultValue = "10") int pageSize) throws ParseException{
logger.info("************************Thread into method selectTempManager*********************");
String treeId = request.getParameter("treeId");
Page page = Page.newBuilder(pageNo, pageSize, "selectTempManager");
MultipleAnalyse multipleAnalyse = new MultipleAnalyse();
multipleAnalyse.setNum1(treeId );
multipleAnalyse.setPage(page);
multipleAnalyseList = multipleAnalyseService.selectMultipleAnalyse(multipleAnalyse);
Map<String,Object> attributes = new HashMap<String,Object>();
attributes.put("multipleAnalyseList", multipleAnalyseList);
attributes.put("page", page);
MappingJacksonJsonView view = new MappingJacksonJsonView();
view.setAttributesMap(attributes);
ModelAndView mode = new ModelAndView();
logger.info("************************select Flow analyse:"+multipleAnalyseList+"*********************");
mode.setView(view);
return mode;
}