1. 程式人生 > >easyui中的分頁實現(支援MySQL,SQLServer,Oracle)

easyui中的分頁實現(支援MySQL,SQLServer,Oracle)

package com.dxwind.common.bean;

import java.sql.CallableStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Types;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.CallableStatementCallback;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;

import com.dxwind.common.support.DAORowMapper;

/**
 * 分頁函式
 */
public class Pagination<T> {
	private static Log logger = LogFactory.getLog(Pagination.class);
	
	private int dbType = 1;//1:mssql;2:mysql;3:oracle
	/** 一頁顯示的記錄數 */
	private int numPerPage = 0;
	/** 記錄總數 */
	private int totalRows = 0;
	/** 總頁數 */
	private int totalPages = 0;
	/** 當前頁碼 */
	private int currentPage = 1;
	/** 起始行數 */
	private int startIndex = 0;
	/** 結束行數 */
	private int lastIndex = 0;
	/** 指定型別結果列表 */
	private List<T> resultList = null;
	/** 未指定型別結果列表 */
	private List<Map<String, Object>> resultMapList = null;
	/** JdbcTemplate jTemplate */
	private JdbcTemplate jdbcTemplate = null;
	/** 查詢sql語句 */
	private String querySql = null;
	/** 計數sql語句 */
	private String countSql = null;
	/** 是否優化 (sql中有多個from或多個order by時置為false) */
	private boolean optimizeCountSql = true;
	/** RowMapper */
	private DAORowMapper<T> rowMapper = null;
	/** SQL 繫結引數 */
	private Object[] objs = null;
	
	/**
	 * 預設建構函式
	 */
	public Pagination() {}
	
	public Pagination(String sql, int currentPage, int numPerPage, JdbcTemplate jdbcTemplate) {
		setQuerySql(sql);
		setNumPerPage(numPerPage);
		setCurrentPage(currentPage);
		this.jdbcTemplate = jdbcTemplate;
	}

	public Pagination(String sql, int currentPage, int numPerPage, JdbcTemplate jdbcTemplate, Object[] objs) {
		setQuerySql(sql);
		setNumPerPage(numPerPage);
		setCurrentPage(currentPage);
		this.jdbcTemplate = jdbcTemplate;
		this.objs = objs;
	}

	public Pagination(String sql, int currentPage, int numPerPage, JdbcTemplate jdbcTemplate, DAORowMapper<T> rowMapper) {
		setQuerySql(sql);
		setNumPerPage(numPerPage);
		setCurrentPage(currentPage);
		this.jdbcTemplate = jdbcTemplate;
		this.setRowMapper(rowMapper);
	}
	
	public Pagination(String sql, int currentPage, int numPerPage, JdbcTemplate jdbcTemplate, DAORowMapper<T> rowMapper, Object[] objs) {
		setQuerySql(sql);
		setNumPerPage(numPerPage);
		setCurrentPage(currentPage);
		this.jdbcTemplate = jdbcTemplate;
		this.objs = objs;
		this.setRowMapper(rowMapper);
	}

	public Pagination(int currentPage, int numPerPage, int totalRows, List<T> list){
		setTotalRows(totalRows);
		setNumPerPage(numPerPage);
		setCurrentPage(currentPage);
		setResultList(list);
		setTotalPages();
	}

	public String getCountSql(String querySql){
		StringBuffer sb = new StringBuffer("select count(*) from (");
		sb.append(querySql);
		sb.append(") z");
		return sb.toString();
	}
	
	public String getCountFastSql(String querySql){
		String sql = querySql.toLowerCase(); 
		StringBuffer sb = new StringBuffer("select count(*) ");
			int orderPos = sql.lastIndexOf("order by");
			int fromPos = sql.indexOf("from");
			if(orderPos > 0)
				sb.append(sql.substring(fromPos, orderPos));
			else
				sb.append(sql.substring(fromPos));
		return sb.toString();
	}
	
	/**
	 * 初始化 
	 * @param sql 根據傳入的sql語句得到一些基本分頁資訊
	 * @param currentPage 當前頁
	 * @param numPerPage 每頁記錄數
	 * @param jdbcTemplate JdbcTemplate例項
	 */
	public void query() {
		if (this.jdbcTemplate == null) {
			throw new IllegalArgumentException(
					"com.dxwind.common.bean.Pagination.jdbcTemplate is null,please initial it first. ");
		} else if (querySql == null || querySql.equals("")) {
			throw new IllegalArgumentException(
					"com.dxwind.common.bean.Pagination.querySql is empty,please initial it first. ");
		}

		String totalSQL = countSql == null?(isOptimizeCountSql()?getCountFastSql(querySql):getCountSql(querySql)): countSql;
		// 總記錄數
		try{
			if(objs == null){
				setTotalRows(jdbcTemplate.queryForInt(totalSQL));
			}else{
				setTotalRows(jdbcTemplate.queryForInt(totalSQL,objs));
			}
		}catch(Exception e){
			logger.error(e.getMessage(),e);
		}
		// 計算總頁數
		setTotalPages();
		// 計算起始行數
		setStartIndex();
		// 計算結束行數
		setLastIndex();
		
		if(this.dbType == 1){
			// 處理mssql資料庫的分頁儲存過程
			CallableStatementCallback<Integer> cb = new CallableStatementCallback<Integer>() {
				@Override
				public Integer doInCallableStatement(CallableStatement cs)
						throws SQLException, DataAccessException {
					cs.setString(1, querySql);
					cs.setInt(2, currentPage);
					cs.setInt(3, numPerPage);
					cs.registerOutParameter(4, Types.INTEGER);
					cs.execute();
					cs.getMoreResults();
					ResultSet rs = cs.getResultSet();
					if(rowMapper != null){
						List<T> list = new ArrayList<T>();
						while (rs.next()) {
							list.add(rowMapper.mapRow(rs, 0));
						}
						setResultList(list);
						rs.close();
					}else{
						List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
						ResultSetMetaData rsMeta = rs.getMetaData();
		                while (rs.next()) {  
		                	Map<String, Object> rowMap = new HashMap<String, Object>(); 
		                	for(int i = 1; i <= rsMeta.getColumnCount(); i++){
		                		rowMap.put(rsMeta.getColumnName(i), rs.getObject(i));
		                	}
		                	list.add(rowMap);
		                }     
		                setResultMapList(list);
		                rs.close();
					}
					return cs.getInt(4);
				}
			};
			try {
				this.jdbcTemplate.execute("{call sp_pagination(?,?,?,?)}", cb);
			} catch (Exception e) {
				logger.error(e.getMessage(),e);
			}
		}else{
			StringBuffer paginationSQL = new StringBuffer();
			if(this.dbType == 2){
				// 構造mysql資料庫的分頁語句
				paginationSQL.append("select * from ( ");
				paginationSQL.append(querySql);
				paginationSQL.append(" limit " + startIndex + "," + numPerPage);
				paginationSQL.append(") z");
			}else{
				// 構造oracle資料庫的分頁語句
				paginationSQL.append("SELECT * FROM ( ");
				paginationSQL.append("SELECT temp.* ,ROWNUM num FROM ( ");
				paginationSQL.append(querySql);
				paginationSQL.append(" ) temp where ROWNUM <= " + lastIndex);
				paginationSQL.append(" ) WHERE num > " + startIndex);
			}
			// 裝入結果集List
			String paginationQuerySQL = paginationSQL.toString();
			try{
				if(this.rowMapper != null){
					if(this.objs == null){
						setResultList(this.jdbcTemplate.query(paginationQuerySQL, this.rowMapper));
					}else{
						setResultList(this.jdbcTemplate.query(paginationQuerySQL, this.rowMapper, objs));
					}
				}else{
					if(this.objs == null){
						setResultMapList(this.jdbcTemplate.queryForList(paginationQuerySQL));
					}else{
						setResultMapList(this.jdbcTemplate.queryForList(paginationQuerySQL, objs));
					}
				}
			}catch(Exception e){
				logger.error(e.getMessage(),e);
			}
		}
	}

	/**
	 * 獲取分頁資訊
	 * @return
	 */
	public PageInfo getPageInfo(){
		if(this.getResultList() != null){
			return new PageInfo(this.getTotalPages(), currentPage, this.getTotalRows(),
					this.getResultList().size(), this.getNumPerPage());
		}
		if(this.getResultMapList() != null){
			return new PageInfo(this.getTotalPages(), currentPage, this.getTotalRows(),
					this.getResultMapList().size(), this.getNumPerPage());
		}
		return new PageInfo(this.getTotalPages(), currentPage, this.getTotalRows(), 0, this.getNumPerPage());
	}

	private void setRowMapper(DAORowMapper<T> rowMapper) {
		this.rowMapper = rowMapper;
	}

	public RowMapper<T> getRowMapper() {
		return rowMapper;
	}

	public void setQuerySql(String querySql) {
		this.querySql = querySql;
	}

	public String getQuerySql() {
		return querySql;
	}

	public int getCurrentPage() {
		return currentPage;
	}

	public void setCurrentPage(int currentPage) {
		if(currentPage > 0){
			this.currentPage = currentPage;
		}else{
			this.currentPage = 1;
		}
	}

	public int getNumPerPage() {
		return numPerPage;
	}

	public void setNumPerPage(int numPerPage) {
		this.numPerPage = numPerPage;
	}

	public List<T> getResultList() {
		return this.resultList;
	}
	public void setResultList(List<T> resultList) {
		this.resultList = resultList;
	}
	public List<Map<String, Object>> getResultMapList() {
		return this.resultMapList;
	}
	public void setResultMapList(List<Map<String, Object>> resultMapList) {
		this.resultMapList = resultMapList;
	}

	public int getTotalPages() {
		return this.totalPages;
	}

	// 計算總頁數
	public void setTotalPages() {
		if (totalRows % numPerPage == 0) {
			this.totalPages = totalRows / numPerPage;
		} else {
			this.totalPages = (totalRows / numPerPage) + 1;
		}
		if(this.currentPage > this.totalPages) this.currentPage = this.totalPages;
		if(this.currentPage < 1) this.currentPage = 1;
	}

	public int getTotalRows() {
		return totalRows;
	}

	public void setTotalRows(int totalRows) {
		this.totalRows = totalRows;
	}

	public int getStartIndex() {
		return startIndex;
	}

	public void setStartIndex() {
		this.startIndex = (currentPage - 1) * numPerPage;
	}

	public int getLastIndex() {
		return lastIndex;
	}

	public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}

	// 計算結束時候的索引
	public void setLastIndex() {
		/*if(currentPage==-1){//如果當前頁為-1,則認為需要顯示全部
			this.lastIndex = totalRows;
			return;
		}*/
		if (totalRows < numPerPage) {
			this.lastIndex = totalRows;
		} else if ((totalRows % numPerPage == 0)
				|| (totalRows % numPerPage != 0 && currentPage < totalPages)) {
			this.lastIndex = currentPage * numPerPage;
		} else if (totalRows % numPerPage != 0 && currentPage == totalPages) {// 最後一頁
			this.lastIndex = totalRows;
		}
	}

	public Object[] getObjs() {
		return objs;
	}

	public void setObjs(Object[] objs) {
		this.objs = objs;
	}

	public String getCountSql() {
		return countSql;
	}

	public void setCountSql(String countSql) {
		this.countSql = countSql;
	}

	public boolean isOptimizeCountSql() {
		return optimizeCountSql;
	}

	public void setOptimizeCountSql(boolean optimizeCountSql) {
		this.optimizeCountSql = optimizeCountSql;
	}

}

DAORowMapper.java

package com.dxwind.common.support;

import java.lang.reflect.Method;
import java.sql.ResultSet;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;

import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.support.rowset.ResultSetWrappingSqlRowSetMetaData;

public class DAORowMapper<T> implements RowMapper<T> {
	
	static protected enum ClassType {
		STRING, INT, LONG, BOOLEAN, DOUBLE, UTILDATE, CALENDAR, SQLTIMESTAMP, SQLDATE, SQLTIME;
	}
	
	private Class<? extends T> rowObjClass;
	private boolean direct;
	static protected Map<String, String> classNameCastMap = new HashMap<String, String>();
	static protected Map<String, DAORowMapper.ClassType> classNameMap = new HashMap<String, DAORowMapper.ClassType>();
	
	static {
		DAORowMapper.classNameCastMap.put("java.lang.String", ",java.lang.String,");
		DAORowMapper.classNameCastMap.put("java.lang.Integer", ",int,java.lang.Integer,boolean,java.lang.Boolean,");
		DAORowMapper.classNameCastMap.put("java.math.BigInteger", ",int,java.lang.Integer,boolean,java.lang.Boolean,");
		DAORowMapper.classNameCastMap.put("java.lang.Long", ",long,java.lang.Long,int,java.lang.Integer,boolean,java.lang.Boolean,");
		DAORowMapper.classNameCastMap.put("java.lang.Boolean", ",boolean,java.lang.Boolean,");
		DAORowMapper.classNameCastMap.put("java.math.BigDecimal", ",double,java.lang.Double,long,java.lang.Long,int,java.lang.Integer,boolean,java.lang.Boolean,");
		DAORowMapper.classNameCastMap.put("java.lang.Double", ",double,java.lang.Double,long,java.lang.Long,int,java.lang.Integer,boolean,java.lang.Boolean,");
		DAORowMapper.classNameCastMap.put("java.lang.Float", ",double,java.lang.Double,long,java.lang.Long,int,java.lang.Integer,boolean,java.lang.Boolean,");
		DAORowMapper.classNameCastMap.put("java.sql.Timestamp", ",java.sql.Timestamp,java.sql.Date,java.util.Calendar,java.util.Date,java.lang.String,");
		DAORowMapper.classNameCastMap.put("java.sql.Date", ",java.sql.Timestamp,java.sql.Date,java.util.Calendar,java.util.Date,java.lang.String,");
		DAORowMapper.classNameCastMap.put("java.sql.Time", ",java.sql.Time,java.util.Calendar,java.util.Date,java.lang.String,");
		
		DAORowMapper.classNameMap.put("java.lang.String", ClassType.STRING);
		DAORowMapper.classNameMap.put("int", ClassType.INT);
		DAORowMapper.classNameMap.put("java.lang.Integer", ClassType.INT);
		DAORowMapper.classNameMap.put("long", ClassType.LONG);
		DAORowMapper.classNameMap.put("java.lang.Long", ClassType.LONG);
		DAORowMapper.classNameMap.put("boolean", ClassType.BOOLEAN);
		DAORowMapper.classNameMap.put("java.lang.Boolean", ClassType.BOOLEAN);
		DAORowMapper.classNameMap.put("double", ClassType.DOUBLE);
		DAORowMapper.classNameMap.put("java.lang.Double", ClassType.DOUBLE);
		DAORowMapper.classNameMap.put("java.util.Date", ClassType.UTILDATE);
		DAORowMapper.classNameMap.put("java.util.Calendar", ClassType.CALENDAR);
		DAORowMapper.classNameMap.put("java.sql.Timestamp", ClassType.SQLTIMESTAMP);
		DAORowMapper.classNameMap.put("java.sql.Date", ClassType.SQLDATE);
		DAORowMapper.classNameMap.put("java.sql.Time", ClassType.SQLTIME);
	}
	
	public DAORowMapper(Class<? extends T> rowObjClass) {
		super();
		this.rowObjClass = rowObjClass;
		this.direct = this.isDirectClass();
	}

	public DAORowMapper(Class<? extends T> rowObjClass, boolean direct) {
		super();
		this.rowObjClass = rowObjClass;
		boolean directClass = this.isDirectClass();
		this.direct = directClass ? true : direct;
	}
	
	private final boolean isDirectClass() {
		if (this.rowObjClass == null) return false;
		return DAORowMapper.classNameMap.get(this.rowObjClass.getName()) != null;
	}

	@SuppressWarnings(value = "unchecked")
	public T mapRow(ResultSet rs, int index){
		T object = null;
		try {
			Method[] methods = null;
			//獲取列資料	
			ResultSetWrappingSqlRowSetMetaData wapping = new ResultSetWrappingSqlRowSetMetaData(rs.getMetaData());
			int columnCount = wapping.getColumnCount();
			if (this.direct){
				Object value = null;
				int columnIndex = 1;
				if(columnCount == 1){
					String columnClassName = wapping.getColumnClassName(columnIndex);//列被封裝的java型別名稱
					if (DAORowMapper.classNameCastMap.get(columnClassName).indexOf(this.rowObjClass.getName()) != -1 || this.rowObjClass.getName().equals("java.lang.Object")) {
						DAORowMapper.ClassType classType = DAORowMapper.classNameMap.get(this.rowObjClass.getName());
						if (classType != null){
							if(rs.getObject(columnIndex) != null || classType == DAORowMapper.ClassType.STRING){
								switch (classType) {
								case STRING:
									value = rs.getString(columnIndex);
									if(value == null){
										value = "";
									}else{
										value = rs.getString(columnIndex);
									}
									break;
								case INT:	
									value = rs.getInt(columnIndex);
									break;
								case LONG:
									value = rs.getLong(columnIndex);
									break;
								case BOOLEAN:
									value = rs.getBoolean(columnIndex);
									break;
								case DOUBLE:
									value = rs.getDouble(columnIndex);
									break;
								case UTILDATE:
									value = new java.util.Date(rs.getTimestamp(columnIndex).getTime());
									break;
								case CALENDAR:
									Calendar targetValue = Calendar.getInstance();
									targetValue.setTimeInMillis(rs.getTimestamp(columnIndex).getTime());
									value = targetValue;
									break;
								case SQLTIMESTAMP:
									value = rs.getTimestamp(columnIndex);
									break;
								case SQLDATE:
									value = rs.getDate(columnIndex);
									break;
								case SQLTIME:
									value = rs.getTime(columnIndex);
									break;
								}
							}
						}
					}
				}
				return (T)value;
			}else{
				object = this.rowObjClass.newInstance();
				methods = this.rowObjClass.getMethods(); //獲取資料儲存物件所有的公開方法,包括繼承的方法
				for (int columnIndex = 0; columnIndex++ != columnCount;){
					String columnClassName = wapping.getColumnClassName(columnIndex);//列被封裝的java型別名稱
					//找到和當前欄位名稱一致的物件屬性設定方法,然後賦值
					String columnName = wapping.getColumnLabel(columnIndex);
					for (Method method : methods) {
						Object value = null;
						//通過方法名以及引數型別來過濾掉不匹配的方法,過濾之後剩下的就是對應的 setter
						String methodName = method.getName();
						if (methodName != null && methodName.equalsIgnoreCase("set".concat(columnName))){
							//獲取引數型別
							Class<?>[] params = method.getParameterTypes();
							if (params.length == 1) {
								if (DAORowMapper.classNameCastMap.get(columnClassName).indexOf("," + params[0].getName() + ",") != -1 || params[0].getName().equals("java.lang.Object")) {
									DAORowMapper.ClassType classType = DAORowMapper.classNameMap.get(params[0].getName());
									if (classType != null){
										if(rs.getObject(columnIndex) != null || classType == DAORowMapper.ClassType.STRING){
											switch (classType) {
											case STRING:
												value = rs.getString(columnIndex);
												if(value == null){
													value = "";
												}else{
													if(columnClassName.equals("java.sql.Timestamp")){
														SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 
														value = sdf.format(rs.getTimestamp(columnIndex));
													}else{
														value = rs.getString(columnIndex);
													}
												}
												break;
											case INT:	
												value = rs.getInt(columnIndex);
												break;
											case LONG:
												value = rs.getLong(columnIndex);
												break;
											case BOOLEAN:
												value = rs.getBoolean(columnIndex);
												break;
											case DOUBLE:
												value = rs.getDouble(columnIndex);
												break;
											case UTILDATE:
												value = new java.util.Date(rs.getTimestamp(columnIndex).getTime());
												break;
											case CALENDAR:
												Calendar targetValue = Calendar.getInstance();
												targetValue.setTimeInMillis(rs.getTimestamp(columnIndex).getTime());
												value = targetValue;
												break;
											case SQLTIMESTAMP:
												value = rs.getTimestamp(columnIndex);
												break;
											case SQLDATE:
												value = rs.getDate(columnIndex);
												break;
											case SQLTIME:
												value = rs.getTime(columnIndex);
												break;
											}
										}else{
											break;
										}
									}
								}
							}
						}
						//執行 setter
						if(value != null){
							method.invoke(object, value);
							break;
						}
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
			object = null;
		}
		return object;
	}

}

SQLSERVER實現分頁的儲存過程:

ALTER PROCEDURE [dbo].[sp_pagination]
@sqlstr varchar(4000), --查詢字串
@currentpage int, --第N頁
@pagesize int, --每頁行數
@recordCount int output
as
set nocount on
declare @P1 int --P1是遊標的id
exec sp_cursoropen @P1 output,@sqlstr,@scrollopt=1,@ccopt=1,@[email protected] output
set @currentpage=(@currentpage-1)*@pagesize+1
exec sp_cursorfetch @P1,16,@currentpage,@pagesize 
exec sp_cursorclose @P1
set nocount off