網上找一下spring jdbc的分頁,基本都是一個類型,不知道爲啥,都是在Page對象中再進行查詢,這樣Page對象不就和數據庫操作混一起了嘛?看過其他的項目,有的是隻在Dao層查出個list(分頁結果集),其他的Page屬性在action中再封裝,我覺得每次都這樣,用着不方便,就自己再搞個輪子吧。下面開整。
1、先上Page對象吧
這裏有兩個構造方法,看需不需要總計錄數,如果不需要的話,後面查詢會少查一次,更方便,但是以防萬一,再給出一個有總記錄數的構造方法
package com.mos.base.sql;
import org.springframework.jdbc.core.JdbcTemplate;
import java.util.List;
/**
* Package Name: com.mos.base.sql
* User: grq
* Date: 2016/3/25
* Time: 9:08
* Description:some des here!
*/
public class Page<T> {
//一頁顯示的記錄數
private int numPerPage;
//記錄總數
private int totalRows;
//總頁數
private int totalPages;
//當前頁碼
private int currentPage;
//起始行數
private int startIndex;
//結束行數
private int lastIndex;
//結果集存放List
private List<T> resultList;
public Page(int currentPage,int numPerPage,List<T> list){
//設置每頁顯示記錄數
setNumPerPage(numPerPage);
//設置要顯示的頁數
setCurrentPage(currentPage);
//總記錄數
// setTotalRows(list.isEmpty() ? 0 : list.size());
//計算總頁數
setTotalPages();
//計算起始行數
setStartIndex();
//計算結束行數
setLastIndex();
System.out.println("lastIndex="+lastIndex);
//裝入結果集
setResultList(list);
}
public Page(int currentPage,int numPerPage,int totalRows,List<T> list){
//設置每頁顯示記錄數
setNumPerPage(numPerPage);
//設置要顯示的頁數
setCurrentPage(currentPage);
//總記錄數
setTotalRows(totalRows);
//計算總頁數
setTotalPages();
//計算起始行數
setStartIndex();
//計算結束行數
setLastIndex();
System.out.println("lastIndex="+lastIndex);
//裝入結果集
setResultList(list);
}
public int getNumPerPage() {
return numPerPage;
}
public void setNumPerPage(int numPerPage) {
this.numPerPage = numPerPage;
}
public int getTotalRows() {
return totalRows;
}
public void setTotalRows(int totalRows) {
this.totalRows = totalRows;
}
public int getTotalPages() {
return totalPages;
}
public void setTotalPages() {
if(totalRows % numPerPage == 0){
this.totalPages = totalRows / numPerPage;
}else{
this.totalPages = (totalRows / numPerPage) + 1;
}
}
public int getCurrentPage() {
return currentPage;
}
public void setCurrentPage(int currentPage) {
this.currentPage = currentPage;
}
public int getStartIndex() {
return startIndex;
}
public void setStartIndex() {
this.startIndex = (currentPage - 1) * numPerPage;
}
public int getLastIndex() {
return lastIndex;
}
public void setLastIndex() {
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 List<T> getResultList() {
return resultList;
}
public void setResultList(List<T> resultList) {
this.resultList = resultList;
}
}
2、SQLPageHandle
這個的作用是處理分頁的,比如mysql和oracle的不同,分別做一個實現就好了,細心的童鞋可能會發現上一篇的applicationContext.xml中注入了一個sQLPageHandle,其實就是這個,需要同時支持mysql和oracle的時候,用工廠注入就行了。
package com.mos.base.sql;
/**
* 分頁處理接口
* */
public interface SQLPageHandle {
/**
* 將傳入的SQL做分頁處理
*
* @param String
* oldSql 原SQL
* @param int pageNo 第幾頁,用來計算first 這個值由(pageNo-1)*pageSize
* @param int pageSize 每頁數量
* */
public String handlerPagingSQL(String oldSql, int pageNo, int pageSize);
}
3、MysqlSQLPageHandleImpl
其實就是對sql進行重新拼接處理。
package com.mos.base.sql;
import org.apache.log4j.Logger;
/**
* mysql數據庫的分頁實現
*
* */
public class MysqlSQLPageHandleImpl implements SQLPageHandle {
private Logger logger=Logger.getLogger(MysqlSQLPageHandleImpl.class);
public String handlerPagingSQL(String oldSQL, int pageNo, int pageSize) {
StringBuffer sql = new StringBuffer(oldSQL);
if (pageSize > 0) {
int firstResult = (pageNo - 1)*pageSize;
if (firstResult <= 0) {
sql.append(" limit ").append(pageSize);
} else {
sql.append(" limit ").append(firstResult).append(",")
.append(pageSize);
}
}
return sql.toString();
}
}
4、BaseDao
個人覺得這幾個最常用的就可以了,其他的可以再擴展,比如批量操作,我一直的想法就是先會走再會跑,單個的搞定了,批量的還遠嗎?
package com.mos.base.sql;
import java.util.List;
import java.util.Map;
/**
* Package Name: com.mos.base
* User: grq
* Date: 2016/3/24
* Time: 16:02
* Description:some des here!
*/
public interface BaseDao {
public <T> List<T> find(String sql, Object[] params, Class<T> tClass);
public <T> int addOrUpdateOrDelete(String sql, Object[] params, Class<T> tClass);
public <T> Page<T> queryPagination(String sql, Object[] parameters,int pageNo, int pageSize, Class<T> entity);
public <T> T findForObject(String sql, Object[] args, Class<T> classT);
public Map<String,Object> find(String sql,Object[] params);
public List<Map<String,Object>> queryList(String sql,Object[] params);
}
5、BaseDaoImpl
這個裏面好多坑。
- queryPagination(…….)方法中有個totalList,這個就是對應前面Page對象的totalRows,如果不需要,那就不用查詢了。
- 傳入參數提示Class< T>,我以爲比如User對象,傳入User.class就行了,然並卵,spring jdbc不支持自定義複雜對象,需要轉換,參考代碼。
- 查詢的時候如果沒有查詢條件,必須用沒條件的方法查詢,如果條件傳個null,sorry,等着catch exception吧。
package com.mos.base.sql;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementSetter;
import org.springframework.stereotype.Repository;
import javax.annotation.Resource;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
/**
* Package Name: com.mos.base
* User: grq
* Date: 2016/3/24
* Time: 16:06
* Description:some des here!
*/
@Repository
public class BaseDaoImpl implements BaseDao {
@Autowired
private JdbcTemplate jdbcTemplate;
@Resource
protected SQLPageHandle sQLPageHandle;
public <T> List<T> find(String sql, Object[] params, Class<T> tClass) {
List<T> resultList = null;
try {
if (params != null && params.length > 0)
resultList = jdbcTemplate.query(sql, params, new BeanPropertyRowMapper<T>(tClass));
else
// BeanPropertyRowMapper是自動映射實體類的
resultList = jdbcTemplate.query(sql, new BeanPropertyRowMapper<T>(tClass));
} catch (Exception e) {
e.printStackTrace();
}
return resultList;
}
public <T> int addOrUpdateOrDelete(String sql, final Object[] params, Class<T> tClass) {
int num = 0;
try {
if (params == null || params.length == 0)
num = jdbcTemplate.update(sql);
else
num = jdbcTemplate.update(sql, new PreparedStatementSetter() {
public void setValues(PreparedStatement ps) throws SQLException {
for (int i = 0; i < params.length; i++)
ps.setObject(i + 1, params[i]);
}
});
} catch (Exception e) {
e.printStackTrace();
num = -1;
}
return num;
}
/**
* @param sql
* @param parameters
* @param pageNo
* @param pageSize
* @param entity jdbcTemplate.query由於需要返回自定義對象,調用此方法時候需要傳入new BeanPropertyRowMapper<T>(entity)
* @param <T>
* @return
*/
public <T> Page<T> queryPagination(String sql, Object[] parameters, int pageNo, int pageSize, Class<T> entity) {
// 將SQL語句進行分頁處理
String newSql = sQLPageHandle.handlerPagingSQL(sql, pageNo, pageSize);
List<T> list = null;
List<T> totalList = null;
if (parameters == null || parameters.length <= 0) {
totalList = jdbcTemplate.query(sql, new BeanPropertyRowMapper<T>(entity));
list = jdbcTemplate.query(newSql, new BeanPropertyRowMapper<T>(entity));
} else {
totalList = jdbcTemplate.query(sql, parameters, new BeanPropertyRowMapper<T>(entity));
list = jdbcTemplate.query(newSql, parameters, new BeanPropertyRowMapper<T>(entity));
}
// 根據參數的個數進行差別查詢
Page<T> page = new Page<T>(pageNo, pageSize, totalList.isEmpty() ? 0 : totalList.size(), list);
return page;
}
/**
* @param sql
* @param args
* @param classT 注意該參數,jdbcTemplate.queryForObject傳入的不能是自定義的classType,
* 如果是自定義的,需要經過new BeanPropertyRowMapper<T>(classT)轉換,默認支持的只有比如String,int等類型
* @param <T>
* @return
*/
public <T> T findForObject(String sql, Object[] args, Class<T> classT) {
if (sql == null || sql.length() <= 0) {
return null;
}
if (args == null || args.length <= 0) {
return jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<T>(classT));
}
return jdbcTemplate.queryForObject(sql, args, new BeanPropertyRowMapper<T>(classT));
}
public Map<String, Object> find(String sql, Object[] params) {
return jdbcTemplate.queryForMap(sql,params);
}
public List<Map<String, Object>> queryList(String sql, Object[] params) {
return jdbcTemplate.queryForList(sql,params);
}
}