網頁分頁功能的實現


最近在學習JavaWeb的時候,用到了分頁功能,現在進行一個記錄,以備不時之需

第一步:先完成PageBean的編寫

就是對當前頁數,每頁顯示的記錄數,總記錄數,總頁數,分頁顯示的信息進行封裝。作為通用的分頁功能的實現,這里用到了泛型

import java.util.List;

/**
 * 分頁封裝
 *
 */
public class PageBean<T> {
    
    private int currPage;//當前頁數
    
    private int pageSize;//每頁顯示記錄數
    
    private int totalCount;//總記錄數
    
    private int totalPage;//總頁數
    
    private List<T> list;//每頁顯示的信息 

    public int getCurrPage() {
        return currPage;
    }

    public void setCurrPage(int currPage) {
        this.currPage = currPage;
    }

    public int getPageSize() {
        return pageSize;
    }

    public void setPageSize(int pageSize) {
        this.pageSize = pageSize;
    }

    public int getTotalCount() {
        return totalCount;
    }

    public void setTotalCount(int totalCount) {
        this.totalCount = totalCount;
    }

    public int getTotalPage() {
        return totalPage;
    }

    public void setTotalPage(int totalPage) {
        this.totalPage = totalPage;
    }

    public List<T> getList() {
        return list;
    }

    public void setList(List<T> list) {
        this.list = list;
    }

}

第二步:在Action類中編寫一個分頁方法

Action中通過調用業務層Service類的分頁方法,Employee就是具體的信息Bean,之前泛型的使用就在於此,在不同項目中使用不同的信息Bean可以完成多種類信息的分頁,employeeService就是具體的業務層Service,Service中我們也有一個叫findAll的方法。這里的currPage生成其set/get方法,等用戶點擊了頁面及具體的頁數,Struts2會獲得具體的頁數,然后將currPage傳給Service

    // 分頁(當前頁)這里等於1是為了使第一頁為默認頁
    private int currPage = 1;
    public int getCurrPage() {
        return currPage;
    }

    public void setCurrPage(int currPage) {
        this.currPage = currPage;
    }
   /**
     * 分頁查詢
     */
    public String findAll() {
        PageBean<Employee> pageBean = employeeService.findAll(currPage);
        ActionContext.getContext().getValueStack().push(pageBean);
        return "findAll";
    }

第三步:編寫Service中的分頁方法

先生成一個PageBean對象(注意泛型),之后開始封裝這個Bean。pageSize(每頁顯示的記錄數)這里設置為3,就是每頁顯示3條記錄,totalCount(總記錄數)通過Dao中的findCount()方法來查到,totalPage(總頁數)=totalCount(總記錄數)/pageSize(每頁大小),Math.ceil可以獲得一個double的近似值(大於等於),之后我們通過Double包裝類的intValue再轉成int型,begin(每一頁的開頭的序號),list的數據也通過Dao的findPage(int,int)方法獲得

public PageBean<Employee> findAll(int currPage) {
        PageBean<Employee> pageBean = new PageBean<>();
        // 封裝pageBean
        pageBean.setCurrPage(currPage);
        int pageSize = 3;
        pageBean.setPageSize(pageSize);
        int totalCount = employeeDao.findCount();
        pageBean.setTotalCount(totalCount);
        Double totalPage = Math.ceil((double) totalCount / pageSize);
        pageBean.setTotalPage(totalPage.intValue());
        int begin = (currPage - 1) * pageSize;
        List<Employee> list = employeeDao.findPage(begin, pageSize);
        pageBean.setList(list);
        return pageBean;
    }

第四步:編寫Dao中的方法

這之前在Service中使用的findCount()和findPage(int,int),值得注意的就是findCount()中的hql語句使用count(*),還有就是findPage(int,int)中使用了org.hibernate.criterion.DetachedCriteria類,查詢時不是用find方法,而是findByCriteria來查詢

   /**
     * 查詢總記錄數
     */
    public int findCount() {
        String hql="select count(*) from Employee";
        List<Long> list = (List<Long>) hibernateTemplate.find(hql);
        if(list.size()>0){
            return list.get(0).intValue();
        }
        return 0;
    }


    /**
     * 分頁信息
     */
    public List<Employee> findPage(int begin, int pageSize) {
        DetachedCriteria criteria=DetachedCriteria.forClass(Employee.class);
        List<Employee> list = (List<Employee>) hibernateTemplate.findByCriteria(criteria, begin, pageSize);
        return list;
    }

基本上通過以上四步就完成了分頁功能邏輯代碼的編寫,接下來就是對視圖層頁面的編寫

下面是個分頁的簡單顯示,處於首頁時,只顯示下一頁和尾頁,處於尾頁時,只顯示首頁和上一頁,其他頁就都顯示。這里使用的Struts2的標簽庫,所以不要忘了要加上

<%@ taglib uri="/struts-tags" prefix="s" %>

為什么我們可以直接currPage,totalPage等屬性?是因為我們之前將PageBean對象放入了值棧中

<table border="0" cellspacing="0" cellpadding="0"  width="900px">
<tr>
<td align="right">
   <span><s:property value="currPage"/>/<s:property value="totalPage"/></span>&nbsp;&nbsp;
   <span>總記錄數:<s:property value="totalCount"/>/每頁顯示:<s:property value="pageSize"/></span>&nbsp;&nbsp;
   <span>
   <s:if test="currPage!=1">
       <a href="department_findAll.action?currPage=1">[首頁]</a>&nbsp;&nbsp;
       <a href="department_findAll.action?currPage=<s:property value="currPage-1"/>">[上一頁]</a>&nbsp;&nbsp;
   </s:if>  
   <s:if test="currPage!=totalPage">
       <a href="department_findAll.action?currPage=<s:property value="currPage+1"/>">[下一頁]</a>&nbsp;&nbsp;
       <a href="department_findAll.action?currPage=<s:property value="totalPage"/>">[尾頁]</a>&nbsp;&nbsp;
   </s:if>  
   </span>
</td>
</tr>
</table>

效果圖:

可以使用了struts2的<s:iterator>標簽來進行迭代顯示數據,這里給個參考

<s:iterator value="list" var="d">
<tr>
<td align="center"><s:property value="#d.dname"/></td>
<td align="center"><a href="">編輯</a></td>
<td align="center"><a href="">刪除</a></td>
</tr>
</s:iterator>

 注意:一定要在Struts.xml文件中配置轉跳到我們編寫的action上(在這里是department_findAll.action),不然打開要分頁的頁面時,不會進行分頁操作,只有你選擇了頁數才會分頁

后記

我在使用的過程中發現,要使用分頁功能的地方不少,在某些地方,使用上面的會出錯:例如對條件查詢之后的結果進行分頁,第一頁很OK,但是你點擊下一頁/某一頁的時候會出現查詢條件的丟失問題,再進行的查詢結果分頁是沒有條件的,就會出錯

解決辦法(我使用Servlet+JDBC實現的,原理是一樣的):

在我們的POJO中添加一個url屬性,表示查詢條件,因為POST方式條件是放在請求頭中的,很不方便,所以再進行條件查詢的的表單使用GET方式:

<form action="<c:url value='/customerServlet'/>" method="get">

我們需要獲得這個url(包括項目名+Servlet名+條件),獲得這個url封裝到POJO中

改進后的PageBean:

import java.util.List;

public class PageBean<T> {
    //當前頁
    private int currPage;
    //每頁記錄數
    private int pageSize;
    //總記錄數
    private int totalCount;
    //數據集合
    private List<T> list;
    //url表示條件查詢的條件(GET方式)
    private String url;

    public int getCurrPage() {
        return currPage;
    }

    public void setCurrPage(int currPage) {
        this.currPage = currPage;
    }

    public int getPageSize() {
        return pageSize;
    }

    public void setPageSize(int pageSize) {
        this.pageSize = pageSize;
    }

    public int getTotalCount() {
        return totalCount;
    }

    public void setTotalCount(int totalCount) {
        this.totalCount = totalCount;
    }

    //設置總頁數(計算得出)
    public int getTotalPage() {
        Double totalPage=Math.ceil((double)totalCount/pageSize);
        return totalPage.intValue();
    }

    public List<T> getList() {
        return list;
    }

    public void setList(List<T> list) {
        this.list = list;
    }

    public String getUrl() {
        return url;
    }
    
    public void setUrl(String url) {
        this.url = url;
    }
}

控制層要添加的方法(encoding()方法根據情況添加):

    /**
     * 得到包含查詢的條件URL
     */
    private String getURL(HttpServletRequest request){
        String contextPath=request.getContextPath();  //項目名
        String servletPath=request.getServletPath();  //servlet路徑,即/*Servlet   建議使用request.getRequestURI()獲得一個包含項目名+Servlet的路徑
        String queryString=request.getQueryString();  //?后面的參數
        //判斷參數中是否帶當前頁(currPage)
        if(queryString.contains("&currPage=")){
            int index=queryString.lastIndexOf("&currPage=");
            queryString=queryString.substring(0, index);
        }
        return contextPath+servletPath+"?"+queryString;
    }
    
    /**
     *對(這里是4個條件)條件進行編碼(GET方式防止中文亂碼,POST方式已經在BaseServlet中配置) 
     * @throws UnsupportedEncodingException 
     *
     */
    private Customer encoding(Customer customer) throws UnsupportedEncodingException{
        String cname=customer.getCname();
        String gender=customer.getGender();
        String cellPhone=customer.getCellphone();
        String email=customer.getEmail();
        if(cname!=null&&!cname.isEmpty()){
           // cname=new String(cname.getBytes("ISO-8859-1"),"UTF-8");    //tomcat8之前tomcat默認字符編碼使用是ISO-8859-1
            cname=new String(cname.getBytes(),"UTF-8");         
            customer.setCname(cname);
        }
        if(gender!=null&&!gender.isEmpty()){
            //gender=new String(gender.getBytes("ISO-8859-1"),"UTF-8");  
            gender=new String(gender.getBytes("ISO-8859-1"),"UTF-8");
            customer.setCname(gender);
        }
        if(cellPhone!=null&&!cellPhone.isEmpty()){
            //cellPhone=new String(cellPhone.getBytes("ISO-8859-1"),"UTF-8");
            cellPhone=new String(cellPhone.getBytes(),"UTF-8");
            customer.setCname(cellPhone);
        }
        if(email!=null&&!email.isEmpty()){
            //email=new String(email.getBytes("ISO-8859-1"),"UTF-8");
            email=new String(email.getBytes(),"UTF-8");
            customer.setCname(email);
        }
        return customer;
    } 

這個geturl()方法就是獲得url的方法,我用來表示當前頁的變量使用的是currPage,根據實際情況更換。encoding()方法是處理get方式獲得的條件中文亂碼問題,如果項目使用tomcat8之后的服務器就不用轉碼了。注意:現在是所有的查詢的方法的需要使用geturl()方法,並將返回值封裝到POJO中。使用request.getRequestURI()方法也可以獲得Struts2中Action的地址。使用框架開發應該就不用考慮encoding()這個編碼方法,只需要處理geturl()方法了

多條件查詢的Servlet方法:

    /**
     * 多條件查詢
     */
    public String query(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //獲得查詢條件
        Customer customer=CommonUtils.toBean(request.getParameterMap(), Customer.class);
        //處理GET請求的編碼格式
        //customer = encoding(customer);              因為我的tomcat是8.5,所以就不轉碼了
        //處理PageBean
        int pageSize=10;         //每頁記錄數為10
        int currPage=getCurrentPage(request);
        int begin=(currPage-1)*pageSize;         //計算每頁的開頭
        PageBean<Customer> pageBean=customerService.query(customer,begin,pageSize);
        //封裝當前頁和每頁記錄數
        pageBean.setCurrPage(currPage);
        pageBean.setPageSize(pageSize);
        //封裝url
        pageBean.setUrl(getURL(request));
        //將pageBean保存request
        request.setAttribute("pb", pageBean);
        return "f:/list.jsp";
    }

注意:因為這種方式的頁碼算是使用的超連接,所以currPage可能會被惡意輸入,需要驗證一下,這里粘一個使用正則驗證是否是數字的方法(其實不僅僅要驗證是否為數字,還應該驗證當前頁不要大於總頁數,也不要小於1):

    /**
     * 使用正則驗證輸入的是否為數字
     * @param string
     * @return
     */
    public static boolean isNum(String string) {
        Pattern pattern=Pattern.compile("[1-9]{1}\\d*");
        Matcher matcher = pattern.matcher(string);
        return matcher.matches();
    }

Dao中多條件查詢:

/**
     * 多條件查詢
     * 
     */
    public PageBean<Customer> query(Customer customer, int begin, int pageSize) {
        try {
            PageBean<Customer> pageBean=new PageBean<Customer>();
            
            /**
             * 根據條件查詢出總記錄數
             * 拼sql語句
             */
            StringBuilder cntSql=new StringBuilder("select count(*) from t_customer");
            StringBuilder whereSql=new StringBuilder(" where 1=1");
            List<Object> params=new ArrayList<Object>();
            
            String cname=customer.getCname();
            if(cname!=null&&!cname.trim().isEmpty()){
                whereSql.append(" and cname like ?");
                params.add("%"+cname+"%");
            }
            
            String gender=customer.getGender();if(gender!=null&&!gender.trim().isEmpty()){
                whereSql.append(" and gender=?");
                params.add(gender);
            }
            
            String phone=customer.getCellphone();
            if(phone!=null&&!phone.trim().isEmpty()){
                whereSql.append(" and cellphone like ?");
                params.add("%"+phone+"%");
            }
            
            String email=customer.getEmail();
            if(email!=null&&!email.trim().isEmpty()){
                whereSql.append(" and email like ?");
                params.add("%"+email+"%");
            }
            //運行sql
            Number count=(Number) qr.query(cntSql.append(whereSql).toString(), new ScalarHandler(),params.toArray());
            pageBean.setTotalCount(count.intValue());

            
            /**
             * 根據條件查詢出每頁數據
             */
            StringBuilder listSql=new StringBuilder("select * from t_customer");
            //limit子句分頁
            StringBuilder limitSql=new StringBuilder(" order by cname limit ?,?");
            //添加這兩個參數
            params.add(begin);
            params.add(pageSize);
            //運行sql
            List<Customer> beanList=qr.query(listSql.append(whereSql).append(limitSql).toString(), 
                    new BeanListHandler<Customer>(Customer.class),
                    params.toArray());
            pageBean.setList(beanList);
            return pageBean;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

我還是使用的是拼接sql的方式,與眾不同的是分頁中使用的count語句limit語句都是帶where條件的

 在頁面中也需要進行相應的修改(我這里使用的是JSTL):

第${pb.currPage }頁/共${pb.totalPage }頁
<c:if test="${pb.currPage>1 }">
<a href="${pb.url }&currPage=1">首頁</a>
<a href="${pb.url }&currPage=${pb.currPage-1 }">上一頁</a>
</c:if>

<c:if test="${pb.currPage<pb.totalPage }"> <a href="${pb.url }&currPage=${pb.currPage+1 }">下一頁</a> <a href="${pb.url }&currPage=${pb.totalPage }">尾頁</a> </c:if>

pb就是我放在request中的pageBean的名字,注意url需要我們從pageBean的url中取出,頁面只關心當前頁,不去關心路徑到底是什么

一個頁碼的實現

可能說一個頁碼又什么好實現的,直接把所有頁數寫出來,都加上超鏈接不就好了,但是觀察百度等有頁碼的網站,你會發現頁面是會隨着頁數變換的,比如說:先顯示10頁,但是當你點擊第7頁的時候,第1頁應該隱藏,第11頁應該出現,只有出現11頁我們才能點擊,這就是要實現的功能

<%-- 頁碼 --%>
<c:choose>
<%-- 總頁數小於等於10頁,把所有頁顯示 --%>
  <c:when test="${pb.totalPage<=10 }">
    <c:set var="begin" value="1"/>
    <c:set var="end" value="${pb.totalPage }"/>
  </c:when>
  <c:otherwise>
    <%--總頁數>10,計算begin和end  --%>
    <c:set var="begin" value="${pb.currPage-5 }"/>
    <c:set var="end" value="${pb.currPage+4 }"/>
    <%--處理頭溢出  --%>
    <c:if test="${begin<1 }">
      <c:set var="begin" value="1"/>
      <c:set var="end" value="10"/>
    </c:if>
    <%-- 處理尾溢出 --%>
    <c:if test="${end>pb.totalPage }">
      <c:set var="begin" value="${pb.totalPage-9 }"/>
      <c:set var="end" value="${pb.totalPage }"/>
    </c:if>
  </c:otherwise>
</c:choose>
<c:forEach begin="${begin }" end="${end }" var="i">
  <c:choose>
   <c:when test="${i eq pb.currPage }">
     [${i }]
   </c:when>
   <c:otherwise>
     <a href="${pb.url }&currPage=${i }">[${i }]</a>
   </c:otherwise>
  </c:choose>
</c:forEach>

這是一個顯示10頁,點擊第7頁后,1頁消失11頁出現,點擊8頁后,2頁消失12頁出現,以此類推

效果圖(這是我把頁碼放在上一頁和下一頁之間的效果):


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM