网上找一下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);
}
}