分页技术原理与实现之Java+Oracle代码实现分页(二)
紧接着上篇—分页技术原理与实现之分页的意义及方法(一),本篇继续分析分页技术。上篇讲的是分页技术的简单原理与介绍,这篇深入分析一下分页技术的代码实现。
上篇最后讲到了分页的最佳实现是在数据库层进行分页,而且不同的数据库有不同的分页实现,比如Oracle是用三层sql嵌套实现分页的、MySQL是用limit关键字实现的(上篇已讲到)。
这篇以Java+Oracle为基础,讲解代码层的实现。
就如平时我们很在分页中看到的,分页的时候返回的不仅包括查询的结果集(List),而且还包括总的页数(pageNum)、当前第几页(pageNo)等等信息,所以我们封装一个查询结果PageModel类,代码如下:
packagekane; importjava.util.List; publicclassPageModel<E>{ privateList<E>list; privateintpageNo; privateintpageSize; privateinttotalNum; privateinttotalPage; publicList<E>getList(){ returnlist; } publicvoidsetList(List<E>list){ this.list=list; } publicintgetPageNo(){ returnpageNo; } publicvoidsetPageNo(intpageNo){ this.pageNo=pageNo; } publicintgetPageSize(){ returnpageSize; } publicvoidsetPageSize(intpageSize){ this.pageSize=pageSize; } publicintgetTotalNum(){ returntotalNum; } publicvoidsetTotalNum(inttotalNum){ this.totalNum=totalNum; setTotalPage((getTotalNum()%pageSize)==0?(getTotalNum()/pageSize) :(getTotalNum()/pageSize+1)); } publicintgetTotalPage(){ returntotalPage; } publicvoidsetTotalPage(inttotalPage){ this.totalPage=totalPage; } //获取第一页 publicintgetFirstPage(){ return1; } //获取最后页 publicintgetLastPage(){ returntotalPage; } //获取前页 publicintgetPrePage(){ if(pageNo>1) returnpageNo-1; return1; } //获取后页 publicintgetBackPage(){ if(pageNo<totalPage) returnpageNo+1; returntotalPage; } //判断'首页'及‘前页'是否可用 publicStringisPreable(){ if(pageNo==1) return"disabled"; return""; } //判断'尾页'及‘下页'是否可用 publicStringisBackable(){ if(pageNo==totalPage) return"disabled"; return""; } }
其中使用泛型是为了能使的该分页类能进行重用,比如在查询用户时可以封装User对象、在查询财务中的流向单时可以封装流向单FlowCard类。
我们以查询用户为例,用户选择查询条件,首先调用Servlet获取查询参数,然后请求业务逻辑层取得分页封装结果类。业务逻辑调用Dao层取得结果集、取得中记录数封装成分页类。最后Servlet将结果设置到jsp页面显示。
首先来讲解Servlet,代码如下:
packagekane; importjava.io.*; importjava.util.*; importjavax.servlet.ServletConfig; importjavax.servlet.ServletException; importjavax.servlet.http.HttpServlet; importjavax.servlet.http.HttpServletRequest; importjavax.servlet.http.HttpServletResponse; importkane.UserInfo; importkane.UserInfoManage; importkane.PageModel; publicclassUserBasicSearchServletextendsHttpServlet{ privatestaticfinallongserialVersionUID=1L; privateintpageSize=0; @Override publicvoidinit(ServletConfigconfig)throwsServletException{ pageSize=Integer.parseInt(config.getInitParameter("pageSize")); } @Override protectedvoiddoGet(HttpServletRequestreq,HttpServletResponseresp) throwsServletException,IOException{ doPost(req,resp); } @Override protectedvoiddoPost(HttpServletRequestreq,HttpServletResponseresp) throwsServletException,IOException{ //1.取得页面参数并构造参数对象 intpageNo=Integer.parseInt(req.getParameter("pageNo")); Stringsex=req.getParameter("gender"); Stringhome=req.getParameter("newlocation"); Stringcolleage=req.getParameter("colleage"); Stringcomingyear=req.getParameter("ComingYear"); UserInfou=newUserInfo(); u.setSex(sex); u.setHome(home); u.setColleage(colleage); u.setCy(comingyear); //2.调用业务逻辑取得结果集 UserInfoManageuserInfoManage=newUserInfoManage(); PageModel<UserInfo>pagination=userInfoManage.userBasicSearch(u, pageNo,pageSize); List<UserInfo>userList=pagination.getList(); //3.封装返回结果 StringBufferresultXML=newStringBuffer(); try{ resultXML.append("<?xmlversion='1.0'encoding='gb18030'?>/n"); resultXML.append("<root>/n"); for(Iterator<UserInfo>iterator=userList.iterator();iterator .hasNext();){ UserInfouserInfo=iterator.next(); resultXML.append("<data>/n"); resultXML.append("/t<id>"+userInfo.getId()+"</id>/n"); resultXML.append("/t<truename>"+userInfo.getTruename() +"</truename>/n"); resultXML.append("/t<sex>"+userInfo.getSex()+"</sex>/n"); resultXML.append("/t<home>"+userInfo.getHome()+"</home>/n"); resultXML.append("</data>/n"); } resultXML.append("<pagination>/n"); resultXML.append("/t<total>"+pagination.getTotalPage() +"</total>/n"); resultXML.append("/t<start>"+pagination.getFirstPage() +"</start>/n"); resultXML.append("/t<end>"+pagination.getLastPage()+"</end>/n"); resultXML.append("/t<pageno>"+pagination.getPageNo() +"</pageno>/n"); resultXML.append("</pagination>/n"); resultXML.append("</root>/n"); }catch(Exceptione){ e.printStackTrace(); } writeResponse(req,resp,resultXML.toString()); } publicvoidwriteResponse(HttpServletRequestrequest, HttpServletResponseresponse,Stringresult)throwsIOException{ response.setContentType("text/xml"); response.setHeader("Cache-Control","no-cache"); response.setHeader("Content-Type","text/xml;charset=gb18030"); PrintWriterpw=response.getWriter(); pw.write(result); pw.close(); } }
其中User对象代码如下:
packagekane; importjava.util.Date; publicclassUserInfo{ privateintid; privateStringusername; privateStringpassword; privateStringtruename; privateStringsex; privateDatebirthday; privateStringhome; privateStringcolleage; privateStringcomingYear; publicintgetId(){ returnid; } publicvoidsetId(intid){ this.id=id; } publicStringgetUsername(){ returnusername; } publicvoidsetUsername(Stringusername){ this.username=username; } publicStringgetPassword(){ returnpassword; } publicvoidsetPassword(Stringpassword){ this.password=password; } publicStringgetTruename(){ returntruename; } publicvoidsetTruename(Stringtruename){ this.truename=truename; } publicStringgetSex(){ returnsex; } publicvoidsetSex(Stringsex){ this.sex=sex; } publicDategetBirthday(){ returnbirthday; } publicvoidsetBirthday(Datebirthday){ this.birthday=birthday; } publicStringgetHome(){ returnhome; } publicvoidsetHome(Stringhome){ this.home=home; } publicStringgetColleage(){ returncolleage; } publicvoidsetColleage(Stringcolleage){ this.colleage=colleage; } publicStringgetCy(){ returncomingYear; } publicvoidsetCy(Stringcy){ this.comingYear=cy; } }
接着是业务逻辑层代码,代码如下:
packagekane; importjava.sql.Connection; importkane.DBUtility; importkane.PageModel; publicclassUserInfoManage{ privateUserInfoDaouserInfoDao=null; publicUserInfoManage(){ userInfoDao=newUserInfoDao(); } publicPageModel<UserInfo>userBasicSearch(UserInfou,intpageNo, intpageSize)throwsException{ Connectionconnection=null; PageModel<UserInfo>pagination=newPageModel<UserInfo>(); try{ connection=DBUtility.getConnection(); DBUtility.setAutoCommit(connection,false); pagination.setList(userInfoDao.getUserList(u,pageNo,pageSize)); pagination.setPageNo(pageNo); pagination.setPageSize(pageSize); pagination.setTotalNum(userInfoDao.getTotalNum(u)); DBUtility.commit(connection); }catch(Exceptione){ DBUtility.rollBack(connection); e.printStackTrace(); thrownewException(); }finally{ DBUtility.closeConnection(); } returnpagination; } }
其中DBUtility为数据库的连接封装类。
最后是Dao层代码实现,代码如下:
packagekane; importjava.sql.Connection; importjava.sql.PreparedStatement; importjava.sql.ResultSet; importjava.sql.SQLException; importjava.util.ArrayList; importjava.util.List; importkane.UserInfo; importkane.DBUtility; publicclassUserInfoDao{ publicList<UserInfo>getUserList(UserInfouserInfo,intpageNo, intpageSize)throwsException{ PreparedStatementpstmt=null; ResultSetrs=null; List<UserInfo>userList=null; try{ Stringsql="select*from(selectrownumnum,u.*from(select*fromuser_infowheresex=?andhomelike'" +userInfo.getHome() +"%" +"'andcolleagelike'" +userInfo.getColleage() +"%" +"'andcomingyearlike'" +userInfo.getCy() +"%" +"'orderbyid)uwhererownum<=?)wherenum>=?"; userList=newArrayList<UserInfo>(); Connectionconn=DBUtility.getConnection(); pstmt=conn.prepareStatement(sql); pstmt.setString(1,userInfo.getSex()); pstmt.setInt(2,pageNo*pageSize); pstmt.setInt(3,(pageNo-1)*pageSize+1); rs=pstmt.executeQuery(); while(rs.next()){ UserInfouser=newUserInfo(); user.setId(rs.getInt("id")); user.setTruename(rs.getString("truename")); user.setSex(rs.getString("sex")); user.setHome(rs.getString("home")); userList.add(user); } }catch(SQLExceptione){ e.printStackTrace(); thrownewException(e); }finally{ DBUtility.closeResultSet(rs); DBUtility.closePreparedStatement(pstmt); } returnuserList; } publicintgetTotalNum(UserInfouserInfo)throwsException{ PreparedStatementpstmt=null; ResultSetrs=null; intcount=0; try{ Stringsql="selectcount(*)fromuser_infowheresex=?andhomelike'" +userInfo.getHome() +"%" +"'andcolleagelike'" +userInfo.getColleage() +"%" +"'andcomingyearlike'" +userInfo.getCy()+"%"+"'"; Connectionconn=DBUtility.getConnection(); pstmt=conn.prepareStatement(sql); pstmt.setString(1,userInfo.getSex()); rs=pstmt.executeQuery(); if(rs.next()){ count=rs.getInt(1); } }catch(SQLExceptione){ e.printStackTrace(); thrownewException(e); }finally{ DBUtility.closeResultSet(rs); DBUtility.closePreparedStatement(pstmt); } returncount; } }
最后就是servlet将得到的结果返回给jsp页面显示出来。
注:其中DBUtility代码是封装数据库连接操作的代码,如下:
packagekane; importjava.sql.Connection; importjava.sql.DriverManager; importjava.sql.PreparedStatement; importjava.sql.ResultSet; importjava.sql.SQLException; publicclassDBUtility{ privatestaticThreadLocal<Connection>threadLocal=newThreadLocal<Connection>(); publicstaticConnectiongetConnection(){ Connectionconn=null; conn=threadLocal.get(); if(conn==null){ try{ Class.forName("oracle.jdbc.driver.OracleDriver"); conn=DriverManager.getConnection( "jdbc:oracle:thin:@localhost:1521:oracle","admin", "admin"); threadLocal.set(conn); }catch(ClassNotFoundExceptione){ e.printStackTrace(); }catch(SQLExceptione){ e.printStackTrace(); } } returnconn; } //封装设置Connection自动提交 publicstaticvoidsetAutoCommit(Connectionconn,Booleanflag){ try{ conn.setAutoCommit(flag); }catch(SQLExceptione){ e.printStackTrace(); } } //设置事务提交 publicstaticvoidcommit(Connectionconn){ try{ conn.commit(); }catch(SQLExceptione){ e.printStackTrace(); } } //封装设置Connection回滚 publicstaticvoidrollBack(Connectionconn){ try{ conn.rollback(); }catch(SQLExceptione){ e.printStackTrace(); } } //封装关闭Connection、PreparedStatement、ResultSet的函数 publicstaticvoidcloseConnection(){ Connectionconn=threadLocal.get(); try{ if(conn!=null){ conn.close(); conn=null; threadLocal.remove(); } }catch(SQLExceptione){ e.printStackTrace(); } } publicstaticvoidclosePreparedStatement(PreparedStatementpstmt){ try{ if(pstmt!=null){ pstmt.close(); pstmt=null; } }catch(SQLExceptione){ e.printStackTrace(); } } publicstaticvoidcloseResultSet(ResultSetrs){ try{ if(rs!=null){ rs.close(); rs=null; } }catch(SQLExceptione){ e.printStackTrace(); } } }
使用ThreadLocal是为了保证事务的一致,使得同一个线程的所有数据库操作使用同一个Connection。
到此一个简单的代码实现就完成了。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。