<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    每日一得

    不求多得,只求一得 about java,hibernate,spring,design,database,Ror,ruby,快速開發(fā)
    最近關(guān)心的內(nèi)容:SSH,seam,flex,敏捷,TDD
    本站的官方站點(diǎn)是:顛覆軟件

      BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
      220 隨筆 :: 9 文章 :: 421 評(píng)論 :: 0 Trackbacks
    keyword:分頁 緩存 eXtremeTable oscache
    引子:這幾天在弄一個(gè)關(guān)于頁面的分頁,查了一下網(wǎng)上的資料,大都不合要求,要么就是說怎么在數(shù)據(jù)庫這個(gè)層面上如何實(shí)現(xiàn),暈,有了hibernate我用那么費(fèi)勁翻身么.看到一個(gè)用的比較多的方案是做了一個(gè)Page工具類,實(shí)現(xiàn)諸如getBooks(),getNextPage(),看了一下底層實(shí)現(xiàn)居然是"select * from book",嚇?biāo)琅剂?要是有1千萬條記錄那不是要吐血啊,這哪叫分頁啊,這該叫殺人不見血啊. 一氣之下在jbuilder下建了一個(gè)項(xiàng)目就叫FuckPage  :)

    好了,言歸正傳,本文主要說的是關(guān)于在展示層一些常用的方案和實(shí)現(xiàn),目錄如下:
    • 手工實(shí)現(xiàn)分頁
    • 用eXtremeTable標(biāo)簽實(shí)現(xiàn)自動(dòng)分頁
    • 用oscache緩存jsp,提高性能
    第一.自己實(shí)現(xiàn)一個(gè)工具類PageBean完成所有分頁工作.

    本分頁實(shí)現(xiàn)概覽:Struts + hibernate
    PageBean負(fù)責(zé)兩部分內(nèi)容,一是要在頁面顯示的業(yè)務(wù)信息,是一個(gè)ArrayList;另一個(gè)是邏輯控制信息,諸如是否有下一頁,上一頁等等.
    PageBean代碼如下:
    public class PageBean {
      
    int currentPage = 1;//當(dāng)前頁:Action控制
      int totalPages = 0;//總頁數(shù) :自己運(yùn)算
      int pageRecorders = 5//每頁記錄數(shù),默認(rèn)為5,可以在初始化的時(shí)候修改//總數(shù)據(jù)數(shù)
      int pageStartRow = 0//每頁的起始數(shù)
      int pageEndRow = 0//每頁顯示數(shù)據(jù)的終止數(shù)
      boolean hasNextPage = false//是否有下一頁:自己運(yùn)算
      boolean hasPreviousPage = false//是否有前一頁 :自己運(yùn)算
      List objList = new ArrayList();//存放欲展示的對象列表
      int totalRows;//總記錄數(shù),由底層service提供

      
    //是否有上一頁
      public boolean isHasPreviousPage() {
        
    return (currentPage > 1?true:false );
      }

      
    //共有多少頁,service只提供有多少條記錄,多少頁數(shù)由PageBean自己運(yùn)算
      public int getTotalPages() {
        
    return (totalRows/pageRecorders ==0?totalRows/pageRecorders:totalRows/pageRecorders+1);
      }

      
    public int getCurrentPage() {
        
    return currentPage;
      }

      
    public int getPageEndRow() {
        
    return pageEndRow;
      }

      
    //是否有下一頁
      public boolean isHasNextPage() {
        
    return (currentPage < this.getTotalPages() ? true:false);
      }

      
    public int getTotalRows() {
        
    return totalRows;
      }

      
    public int getPageStartRow() {
        
    return pageStartRow;
      }

      
    public int getPageRecorders() {
        
    return pageRecorders;
      }

      
    public void setObjList(List objList) {
        
    this.objList = objList;
      }

      
    public void setHasPreviousPage(boolean hasPreviousPage) {
        
    this.hasPreviousPage = hasPreviousPage;
      }

      
    public void setTotalPages(int totalPages) {
        
    this.totalPages = totalPages;
      }

      
    public void setCurrentPage(int currentPage) {
        
    this.currentPage = currentPage;
      }

      
    public void setPageEndRow(int pageEndRow) {
        
    this.pageEndRow = pageEndRow;
      }

      
    public void setHasNextPage(boolean hasNextPage) {
        
    this.hasNextPage = hasNextPage;
      }

      
    public void setTotalRows(int totalRows) {
        
    this.totalRows = totalRows;
      }

      
    public void setPageStartRow(int pageStartRow) {
        
    this.pageStartRow = pageStartRow;
      }

      
    public void setPageRecorders(int pageRecorders) {
        
    this.pageRecorders = pageRecorders;
      }

      
    public List getObjList() {
        
    return objList;
      }

      
    public PageBean() {}


      
    public void description() {

        String description 
    = "共有數(shù)據(jù)數(shù):" + this.getTotalRows() +

            
    "共有頁數(shù): " + this.getTotalPages() +

            
    "當(dāng)前頁數(shù)為:" + this.getCurrentPage() +

            
    " 是否有前一頁: " + this.isHasPreviousPage() +

            
    " 是否有下一頁:" + this.isHasNextPage() +

            
    " 開始行數(shù):" + this.getPageStartRow() +

            
    " 終止行數(shù):" + this.getPageEndRow();

        System.out.println(description);
      }
    }

    注意,我沒有在PageBean里放具體的業(yè)務(wù)邏輯,諸如getBooks()等,目的很簡單,具有通用性,業(yè)務(wù)邏輯由另一個(gè)業(yè)務(wù)類實(shí)現(xiàn)BookService,BookService獲得的業(yè)務(wù)數(shù)據(jù)都放在了PageBean的ArrayList里.

    BookService代碼如下:
    public class BookService {
      
    private static Logger log = Logger.getLogger(BookService.class.getName());
      
    public BookService() {
      }

      
    /**
       * 獲得book列表
       * 
    @param pageBean PageBean:返回的對象存在pageBean里
       
    */
      
    public static void getBooks(PageBean pageBean) {
        String infoSql 
    = "from Book";//獲得業(yè)務(wù)信息
        String countSql = "select count(*) from Book";//獲得控制信息
        Session session = null;
        
    try {
          session 
    = DBUtil.currentSession();
          Query query 
    = session.createQuery(infoSql);
          query.setFirstResult((pageBean.getCurrentPage()
    -1)* pageBean.getPageRecorders());//起始頁
          query.setMaxResults(pageBean.getPageRecorders());//每頁記錄數(shù)
          pageBean.getObjList().clear();
          
    for (Iterator it = query.iterate(); it.hasNext(); ) {
            Book po 
    = (Book)it.next();
            BookVo vo 
    = new BookVo();
            BeanUtils.copyProperties(vo,po);
            pageBean.getObjList().add(vo);
          }
          session 
    = DBUtil.currentSession();
          query 
    = session.createQuery(countSql);
          
    int totalRecords = ((Integer)query.list().get(0)).intValue();
          pageBean.setTotalRows(totalRecords);
        }
        
    catch (Exception e) {
          e.printStackTrace();
          System.out.println(
    "數(shù)據(jù)庫異常" + e.toString());
        }
        
    finally {
          
    try {
            
    if (null != session) {
              session.close();
            }
          }
          
    catch (HibernateException ex) {
            ex.printStackTrace();
          }
        }

      }


    }

    在Struts的Action中調(diào)用service,返回一個(gè)PageBean給展示頁面
    Action代碼如下:
     1 public class PageListAction extends Action {
     2 
     3   public PageListAction() {}
     4 
     5   ArrayList arrayList = new ArrayList();
     6 
     7   public ActionForward execute(ActionMapping mapping,ActionForm form,HttpServletRequest request,HttpServletResponse response) throws Exception {
     8     String action;
     9     PageBean pageBean = null;
    10     action = request.getParameter("action");
    11     if(action == null || action.equals("null")) { //第一次讀取數(shù)據(jù)
    12       pageBean = new PageBean();
    13     } else {//用戶選擇上一頁或者下一頁
    14       if(action == "nextPage" || action.equals("nextPage")) {
    15         pageBean = (PageBean)request.getSession().getAttribute("pageBean");
    16         pageBean.setCurrentPage(pageBean.getCurrentPage()+1);
    17       }else if(action == "previousPage" || action.equals("previousPage")) {
    18         pageBean = (PageBean)request.getSession().getAttribute("pageBean");
    19         pageBean.setCurrentPage(pageBean.getCurrentPage()-1);
    20       }else if(action == "targetPage" || action.equals("targetPage")){//指定頁
    21         pageBean = (PageBean)request.getSession().getAttribute("pageBean");
    22         System.out.println("targetPage=" + request.getParameter("targetPage"));
    23         //這里根據(jù)需要可以對填寫的目標(biāo)頁進(jìn)行判斷,不要大于最大頁數(shù)[此處省略]
    24         pageBean.setCurrentPage(Integer.parseInt(request.getParameter("targetPage")));
    25       }
    26     }
    27     if(null == pageBean) throw new Exception("獲得PageBean異常");
    28     BookService service = new BookService();
    29     service.getBooks(pageBean);
    30     pageBean.description();
    31     request.getSession().setAttribute("pageBean",pageBean);
    32     request.setAttribute("result",pageBean.getObjList());
    33     return(mapping.findForward("success"));
    34   }
    35 }

    在本Action中判斷了可能出現(xiàn)的三種情況:
    1. 用戶選擇了"上一頁"
    2. 用戶選擇了"下一頁"
    3. 用戶手工輸入了指定的某一頁
    這里有點(diǎn)感覺不爽的是必須hard coding,但是不這么做感覺暫時(shí)也想不出什么好的辦法來,畢竟一個(gè)PageBean不可能封裝所有的細(xì)節(jié),如果你有更好的方式請指點(diǎn)哦 :)

    好了,到了我們呼之欲出的展示頁面了 :)
    show.jsp代碼如下
    <%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>
    <%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
    <%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
    <%@ page contentType="text/html; charset=gb2312" language="java"%>

    <html:html locale="true">
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=gb2312">
      
    <script language="javaScript">
        
    function go(){
          
    try{
          
    var targetValue = document.getElementById("targetPage").value;
          parseInt(targetValue);
          alert(targetValue);
          }
    catch(e){
            alert(
    "請正確填寫目標(biāo)頁");
            
    return;
          }
          
    if(targetValue == null || targetValue == ''){
            alert(
    "請?zhí)顚懩繕?biāo)頁");
            
    return;
          }
          window.location 
    = "/fuck/pageList.do?action=targetPage&targetPage="+targetValue;
        }
      
    </script>
    </head>
    <body>
    <logic:present name="pageBean">
      共有數(shù)據(jù)總數(shù)
    <bean:write name="pageBean" property="totalRows"/>;
    共分
    <bean:write name="pageBean" property="totalPages"/>頁,
    當(dāng)前是第
    <bean:write name="pageBean" property="currentPage"/>
    </logic:present>
    <table border="1">
    <tr><th>書名</th><th>作者</th><th>價(jià)格</th></tr>
        
    <logic:present name="result">
            
    <logic:iterate id="book" name="result">
            
    <logic:present name="book">
            
    <tr>
               
    <td><bean:write name="book" property="name" /></td>
               
    <td> <bean:write name="book" property="author" /></td>
               
    <td><bean:write name="book" property="price" /></td>
            
    /tr>
            
    </logic:present>
            
    </logic:iterate>
        
    </logic:present>
    </table>
    <logic:present name="pageBean">
    <logic:equal name="pageBean" property="hasNextPage" value="true">
        
    <html:link page="/pageList.do?action=nextPage">nextPage</html:link>
    </logic:equal>
    <logic:equal name="pageBean" property="hasPreviousPage" value="true">
        
    <html:link page="/pageList.do?action=previousPage">PreviousPage</html:link>
    </logic:equal>
    <input type="text" name="targetPage" id="targetPage"/>
    <input type="button" value="go!" size="2" onclick="go();"/>
    </logic:present>
    </body>
    </html:html>

    是否有上一頁或者下一頁,全部根據(jù)PageBean里的邏輯值動(dòng)態(tài)判斷.
    這個(gè)頁面沒什么可說的,你可以根據(jù)自己的情況調(diào)整就OK了


    第二. eXtremeTable標(biāo)簽實(shí)現(xiàn)自動(dòng)分

    上面的方案大家已經(jīng)看出來了,實(shí)際上是每一次用戶點(diǎn)擊一個(gè)頁面都會(huì)查詢數(shù)據(jù)庫,這可以算是既是優(yōu)點(diǎn)也是缺點(diǎn),優(yōu)點(diǎn)是數(shù)據(jù)庫不用一次查詢出所有的數(shù)據(jù),在高數(shù)據(jù)量的情況下尤其如此,缺點(diǎn)就是和數(shù)據(jù)庫的交互次數(shù)有點(diǎn)多了,不過這個(gè)完全看你的業(yè)務(wù)策略了,如果用戶大多數(shù)情況下就是看沒幾條的記錄,你又何必把全部數(shù)據(jù)給他取出來呢? 當(dāng)然,在這里我們就說說一次取出全部數(shù)據(jù),然后讓標(biāo)簽幫助我們自動(dòng)分頁,終于可以偷懶了,你所要做的僅僅是取出所需要的業(yè)務(wù)數(shù)據(jù)而已,其他的就交給eXtremeTable標(biāo)簽來完成就OK.
    eXtremeTable
    標(biāo)簽的下載,安裝和文檔請參看官方網(wǎng)站

    public static List getBooks() {
        log.debug(
    "execute getBooks method!");
        String infoSql 
    = "from Book";//獲得業(yè)務(wù)信息
        Session session = null;
        List rtnList 
    = new ArrayList();
        
    try {
          session 
    = DBUtil.currentSession();
          Query query 
    = session.createQuery(infoSql);
          
    for (Iterator it = query.iterate(); it.hasNext(); ) {
            Book po 
    = (Book) it.next();
            BookVo vo 
    = new BookVo();
            BeanUtils.copyProperties(vo,po);
            log.debug(
    "vo = [" + vo + "]");
            rtnList.add(vo);
          }
        }
        
    catch (Exception e) {
          e.printStackTrace();
          System.out.println(
    "數(shù)據(jù)庫異常" + e.toString());
        }
        
    finally {
          
    try {
            
    if (null != session) {
              session.close();
            }
          }
          
    catch (HibernateException ex) {
            ex.printStackTrace();
          }
        }
        
    return rtnList;
      }
    • Action
    代碼如下:
    public class PageListWithTagAction extends Action {
      
    public ActionForward execute(ActionMapping actionMapping, ActionForm actionForm, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) {
        BookService service 
    = new BookService();
       
        //我這里把數(shù)據(jù)放到session中,相當(dāng)于做了緩存,根據(jù)你的業(yè)務(wù)策略也可以不用這么做
        
    //如果session中沒有,則從數(shù)據(jù)庫中查詢
        if(null == httpServletRequest.getSession().getAttribute("result")){
        List result 
    = service.getBooks();
        httpServletRequest.getSession().setAttribute(
    "result",result);
      }
        
    return (actionMapping.findForward("success"));
      }
    }

    • jsp[show.jsp代碼如下,留心里面的標(biāo)簽使用方法]
    <body bgcolor="#ffffff">
    <ec:table tableId="fuck"
            items
    ="result"
            action
    ="${pageContext.request.contextPath}/pageListWithTag.do"
            imagePath
    ="${pageContext.request.contextPath}/jsp/images/table/*.gif"
            title
    ="Books"
            width
    ="60%"
            rowsDisplayed
    ="5"
            locale
    ="zh_CN"
            cellpadding
    ="1"
            cellspacing
    ="1"
            border
    ="1"
            method
    ="post"
            showPagination
    ="false"
            filterable
    ="false"
            
    >
           
    <ec:exportXls fileName="Book.xls" tooltip="導(dǎo)出Excel">
           
    </ec:exportXls>
           
    <ec:exportPdf fileName="Book.pdf" tooltip="導(dǎo)出pdf" headerColor="blue" headerBackgroundColor="red" headerTitle="Book"></ec:exportPdf>
            
    <ec:row highlightRow="true">
                
    <ec:column property="name" title="書名">
                              
    <href="${pageContext.request.contextPath}/bookDetail.do?bookID=${fuck.id}&amp;bookName=${fuck.name}">${fuck.name}
                              
    </a>
                            
    </ec:column>
                
    <ec:column property="author" title="作者">
                              
    <!--here can't use 'result.author'-->
                              ${fuck.author}
                            
    </ec:column>

                
    <ec:column property="price" title="價(jià)格" cell="currency" format="$###,###,##0.00"/>
                            
    <ec:column property="date" title="日期" cell="date" format="yyyy年MM月dd日">
                            
    </ec:column>
            
    </ec:row>
        
    </ec:table>
    </body>

    感覺如何?你不用再畫你的頁面了,不用再畫table了,這點(diǎn)我特別喜歡,因?yàn)槲易约寒嫷臇|西都比較難看,畢竟我的美工功夫不夠  :(   "自從有了eXtremeTable吃嘛嘛香"    :)
    具體的標(biāo)簽使用方法請參考官方文檔的Manual,說明還是比較詳細(xì)的.

    第三.用oscache緩存你的頁面

    為了提高頁面的速度我們想了很多辦法,比如預(yù)編譯的辦法,以及把你常用的數(shù)據(jù)放到內(nèi)存里,是的,除了用內(nèi)存我們還能想到用什么辦法呢,恩,我想以后cpu的緩存也特別大的話我們的下一個(gè)方案肯定就是把數(shù)據(jù)全部放到cpu里得了,哈哈,展望一下  :)

    言歸正傳,oscache的廣告我就不做了,差不多地球人都知道了,這里僅僅提供了一個(gè)想法,我想這確實(shí)是一個(gè)不錯(cuò)的方案,它提供了2個(gè)途徑使用,一是通過tag的方式,可能也是用的最多的方式,另一個(gè)便是調(diào)用API,當(dāng)然就可以在任何想調(diào)用的地方使用了.另外還有一個(gè)特別不錯(cuò)的功能就是有策略的刷新數(shù)據(jù).這是一個(gè)useful的方式,比如你做了增刪改操作那么數(shù)據(jù)庫的數(shù)據(jù)已經(jīng)發(fā)生變化了,你可以通知緩存來更新數(shù)據(jù),方式是通過key或者group.
    下面是幾個(gè)摘自FAQ里的幾個(gè)常用Example
    • Example1
    <cache:cache time="600">
            
    <%= myBean.getTitle() %>
     
    </cache:cache>

    • Example2
    <cache:cache key="foobar" scope="session">
            
    <%= myBean.getTitle() %>
    </cache:cache>

    • Example3
    <cache:cache>
            
    <% try { %>
                
    <%= myBean.getTitle() %>>
            
    <% } catch (Exception e) { %>
                
    <% application.log("Exception occurred in myBean.getTitle(): " + e); %>
                
    <cache:usecached />
            
    <% } %>
    </cache:cache>

    上面的Example3可以實(shí)現(xiàn)在數(shù)據(jù)庫當(dāng)機(jī)的情況下從緩存里讀取數(shù)據(jù)展示,顯得更加友好

    不知你注意到了沒有,在oscache官方展示的例子里的jsp都有一個(gè)我稱之為毛病的東西,或者說是困惑,那就是都用了
    <%=.%>
    這種方式,感覺有點(diǎn)別扭,畢竟這種使用方式對于別人我不知道,反正對于我來說用的比較少,在以前的使用中我記得只有使用xml數(shù)據(jù)島的時(shí)候用過這種方式,其他情況下很少用=的方式來打印出一些動(dòng)態(tài)的數(shù)據(jù),更常見的可能是如下這樣的情況:
    <cache:cache key="dispInfo" groups="disInfo" time="1200">
      
    <%
      BookService service 
    = new BookService();
      List list 
    = service.getBooks();
      request.setAttribute(
    "list",list);
      
    %>
      
    </cache:cache>
     
    <c:forEach items="${list}" var="item">
      
    <c:out value="${item.id}"/> == <c:out value="${item.name}"/><br />
    </c:forEach>

    不幸的是,這個(gè)一廂情愿的做法并不被oscache支持,除了第一次能夠顯示數(shù)據(jù),下一次就顯示不了了.也許oscache所謂的緩存jsp代碼就是指緩存諸如<%=%>的方式才是jsp代碼,其他的java型的就不被支持了?可能是理解不夠,繼續(xù)研究吧,希望有知道的不吝賜教 :)

    恩,就是這么多,關(guān)于頁面的緩存和分頁以及標(biāo)簽.歡迎有這方面的更好的想法來交流.
    本人不才,可能有很多地方理解不夠深入,見笑了  :)




    posted on 2006-02-25 21:26 Alex 閱讀(2680) 評(píng)論(6)  編輯  收藏 所屬分類: java

    評(píng)論

    # re: Fuck the page! 關(guān)于分頁,標(biāo)簽,緩存 2006-02-26 10:45 JAVA夢想
    關(guān)于eXtremeTable:
    我已經(jīng)得到作者(Jeff)同意并翻譯了官方的使用指南(共七篇),發(fā)布在我的blog上。歡迎大家參閱,指正。我現(xiàn)在正在翻譯它的參考手冊。  回復(fù)  更多評(píng)論
      

    # re: Fuck the page! 關(guān)于分頁,標(biāo)簽,緩存 2006-02-26 13:10 Alex
    正在想關(guān)于翻譯的事情要不要弄一下呢,替大伙謝謝你了  回復(fù)  更多評(píng)論
      

    # re: Fuck the page! 關(guān)于分頁,標(biāo)簽,緩存 2006-02-28 14:23 胡子魚
    呵,第一種分頁,封裝不夠徹底;第二種分頁只能小數(shù)據(jù)量,所以建議你改進(jìn)第一種封裝,把分頁邏輯和具體業(yè)務(wù)分開,這樣,每個(gè)業(yè)務(wù),對同一個(gè)getPageBean就完成分頁了。  回復(fù)  更多評(píng)論
      

    # re: Fuck the page! 關(guān)于分頁,標(biāo)簽,緩存 2006-03-29 10:37 keke
    標(biāo)簽太多.不爽.一個(gè)字:亂  回復(fù)  更多評(píng)論
      

    # re: Fuck the page! 關(guān)于分頁,標(biāo)簽,緩存 2006-03-29 12:02 keke
    如果resultset中有1000000條,這種分頁好恐怖.  回復(fù)  更多評(píng)論
      

    # re: Fuck the page! 關(guān)于分頁,標(biāo)簽,緩存 2006-03-29 12:04 keke
    "如果resultset中有1000000條,這種分頁好恐怖." 看錯(cuò)了.這個(gè)可以控制.呵呵  回復(fù)  更多評(píng)論
      

    主站蜘蛛池模板: 亚洲一区二区影视| 亚洲成A人片在线观看无码不卡| 亚洲国产精品狼友中文久久久| 国产精品免费看香蕉| 亚洲精品综合久久| 亚洲爆乳无码一区二区三区| 2022年亚洲午夜一区二区福利| 亚洲а∨天堂久久精品9966| 国产亚洲精品91| 国产午夜成人免费看片无遮挡| 91福利免费视频| 无人影院手机版在线观看免费 | 久久精品国产亚洲一区二区三区| 亚洲成年轻人电影网站www| 中文字幕亚洲男人的天堂网络| 免费看一级毛片在线观看精品视频| 99久久国产精品免费一区二区| 我们的2018在线观看免费高清| 亚洲成a人片在线播放| 久久精品国产亚洲AV无码偷窥| 美女尿口扒开图片免费| 30岁的女人韩剧免费观看| 免费一区二区视频| 亚洲嫩草影院在线观看| 国产在线观看免费av站| 免费高清在线影片一区| 久久久亚洲欧洲日产国码aⅴ| 视频一区在线免费观看| 免费无码A片一区二三区| 久久久久亚洲精品日久生情| 福利免费在线观看| 免费国产美女爽到喷出水来视频| 亚洲一级免费视频| 久久99国产综合精品免费| 亚洲色图综合在线| 亚洲成a∧人片在线观看无码 | 在线观看成人免费| 亚洲一区欧洲一区| 日本高清在线免费| 久久亚洲AV成人无码软件| 国产免费爽爽视频在线观看 |