分页是系统中常用到的功能,只要涉及到查询必定伴随而来的就是分页,之前也学习过关于分页的内容,例如在牛腩的新闻发布系统,之前学习的大部分都是使用了假分页,这次学习java,使用Oracle数据库来实现一下真分页。
首先来说一下实现这个分页查询的流程:
需要分页的部分我们首先要做的是为分页封装一个分页实体,方便返回查询信息,封装如下:
/** *封装分页信息 * @author YoungJong * */ public class PageModel<E> { //结果集 private List<E> list; //查询记录数 private int totalRecords; //每页多少条记录 private int pageSize; //第几页 private int pageNo; public List<E> getList() { return list; } public void setList(List<E> list) { this.list = list; } public int getTotalRecords() { return totalRecords; } public void setTotalRecords(int totalRecords) { this.totalRecords = totalRecords; } public int getPageSize() { return pageSize; } public void setPageSize(int pageSize) { this.pageSize = pageSize; } public int getPageNo() { return pageNo; } public void setPageNo(int pageNo) { this.pageNo = pageNo; } /** * 总页数 * @return */ public int getTotalPages(){ return(totalRecords+pageSize-1)/pageSize; } /** * 取得首页 * @return */ public int getTopPageNo(){ return 1; } /** * 上一页 * @return */ public int getPreviousPageNo(){ if(pageNo<=1){ return 1; } return pageNo-1; } /** * 下一页 * @return */ public int getNextPageNo() { if (pageNo >= getBottomPageNo()) { return getBottomPageNo(); } return pageNo + 1; } /** * 取得尾页 * @return */ public int getBottomPageNo(){ return getTotalPages(); } }
这里的重点是这个实体使用了泛型,使用分页显示的数据并不全是同一种实体数据,为了更好的复用分页查询,将结果集定义成泛型,则便于众多信息的查询:
页面加载时调用一个Servlet,通过Servelt来调用分页查询并将查询结果返回到页面:我们先来看Servlet的代码实现:
public class SearchItemServlet extends AbstractItemServlet { /** * 覆盖servlet的doGet方法 */ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 定义显示第几页的变量 int pageNo=0; //int pageSize=2; //从配置文件读取每页设置的显示数据数量 int pageSize=Integer.parseInt(this.getServletContext().getInitParameter("page-size")); //获取jsp传递过来的显示第几页 String pageNoString=req.getParameter("pageNo"); //如果为空则显示第一页 if(pageNoString==null){ pageNo=1; }else{ pageNo=Integer.parseInt(pageNoString); } //取得查询条件条件,条件为空则查询全部 String condation=req.getParameter("clientIdOrName"); //调用分页查询方法,返回查询数据 PageModel pageModel=itemManager.findItemList(pageNo, pageSize, condation); ///取得查询页面传递过来的分页实体 req.setAttribute("pageModel", pageModel); //将查询数据在页面显示 req.getRequestDispatcher("/basedata/item_maint.jsp").forward(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // TODO Auto-generated method stub //super.doPost(req, resp); doGet(req,resp); } }
其中值得注意的是,关于每页显示数据条数的问题,这一部分可以自己写在代码里,也可以将显示的数目写在配置文件中,只需要读取配置文件即可,方便配置:
其中配置文件可以这样写:在WEB-INF下的web.xml中:
<context-param> <param-name>page-size</param-name> <param-value>3</param-value> </context-param>
这种写法是可以适用于系统中所有的Servlet的,每一个想读取页面显示数量的都可以进行读取。
Servlet调用查询方法是通过一个Manager的接口,类似于三层中B层的作用,由于没有复杂的逻辑,所以这里的代码很简单:
/**
* 查询物料信息,参数分别为:页码,每页显示数据,查询条件 */ public PageModel findItemList(int pageNo, int pageSize, String condation) { Connection conn=null; try{ conn=DbUtil.getConnection(); //调用Dao层的分页查询 return itemDao.findItemList(conn, pageNo, pageSize, condation); }finally{ DbUtil.close(conn); } }
真分页查询的重点在于DAO层的实现,下面我们来看一下代码:
/**
* 分页查询 */ public PageModel findItemList(Connection conn,int pageNo, int pageSize, String condation) { StringBuffer sbSql=new StringBuffer(); sbSql.append("select * ") .append("from (") .append("select i.*, rownum rn from (") .append("select a.item_no, a.item_name, a.spec, a.pattern, a.item_category_id, ") .append("b.name as item_category_name, a.item_unit_id, c.name as item_unit_name, a.file_name ") .append("from t_items a, t_data_dict b, t_data_dict c ") .append("where a.item_category_id=b.id and a.item_unit_id=c.id "); if (condation != null && !"".equals(condation)) { sbSql.append(" and (a.item_no like '" + condation + "%' or a.item_name like '" + condation + "%') "); } sbSql.append(" order by a.item_no") .append(") i where rownum<=? ") .append(") ") .append("where rn >? "); System.out.println("sql=" + sbSql.toString()); //通常采用日志组件记录,如log4j, 级别:info,debug,error... PreparedStatement pstmt = null; ResultSet rs = null; PageModel pageModel = null; try { //为查询条件参数赋值 pstmt = conn.prepareStatement(sbSql.toString()); //查询数据库中列在如何条件之间的数据 pstmt.setInt(1, pageNo * pageSize); pstmt.setInt(2, (pageNo - 1) * pageSize); int i=pageNo*pageSize; int j=(pageNo - 1) * pageSize; rs = pstmt.executeQuery(); //获得符合条件的信息结婚 List itemList = new ArrayList(); while (rs.next()) { Item item = new Item(); item.setItemNo(rs.getString("item_no")); item.setItemName(rs.getString("item_name")); item.setSpec(rs.getString("spec")); item.setPattern(rs.getString("pattern")); //构造ItemCategory ItemCategory ic = new ItemCategory(); ic.setId(rs.getString("item_category_id")); ic.setName(rs.getString("item_category_name")); item.setItemCategory(ic); //构造ItemUnit ItemUnit iu = new ItemUnit(); iu.setId(rs.getString("item_unit_id")); iu.setName(rs.getString("item_unit_name")); item.setItemUnit(iu); item.setFileName(rs.getString("file_name")); itemList.add(item); } //为分页实体赋值 pageModel = new PageModel(); pageModel.setPageNo(pageNo); pageModel.setPageSize(pageSize); pageModel.setList(itemList); //根据条件取得记录数 int totalRecords = getTotalRecords(conn, condation); pageModel.setTotalRecords(totalRecords); }catch(SQLException e) { e.printStackTrace(); //记录到日志文件 error throw new ApplicationException("分页查询失败"); }finally { DbUtil.close(rs); DbUtil.close(pstmt); } return pageModel; }
其实看起来复杂,做起来逻辑并不复杂,很容易实现
后台获得了数据,传递到页面,页面接收后就可以在页面上进行显示了,其实获得数据的代码一句话就可以搞定:更Servlet的代码是对应的,因为在Servlet中我们已经使用了setAttribute,所以jsp中的代码如下:
PageModel pageModel= (PageModel) request.getAttribute("pageModel");
点击跳到首页的方法如下(其他跳转类似不一一列出):
//跳转到首页 function topPage() { window.self.location="<%=basePath%>servlet/item/SearchItemServlet?pageNo=<%=pageModel.getTopPageNo()%>&clientIdOrName=<%=clientIdOrName%>"; }