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

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

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

    隨筆-34  評論-1965  文章-0  trackbacks-0

    在《SSF入門》中,我曾經提過“雖然Seam針對在JSF里進行數據分頁和排序提供了解決方法,但我認為此方法過于簡陋,而且不能使用Richfaces的分頁控件<rich:datascroller>進行分頁。通過SSF數據訪問方式,您可以完美結合Richfaces的分頁控件簡單地實現分頁功能。”所以本文旨在給大家演示在SSF中,實現數據分頁和排序是如何的方便和快捷。

    效果預覽

    如果大家已經通過上一篇文章正確下載和配置了SSF的話,就已經可以通過菜單“管理->日志”查看分頁和排序的效果,如下圖所示。可能大家的環境里的日志可能還不足于超過一頁的記錄(10條),需要增加一些日志記錄。要做到這點,只需重復幾次登入、登出操作,當然為了使日志更加多樣,可以在登入時嘗試使用錯誤的密碼或者不存在的用戶。

    分布效果圖

    實現原理

    首先,我可以看一下日志頁面對應的頁面邏輯代碼(SSF將這些代碼稱為Action),如下清單所示。

     1 package com.whatisjee.ssf.web.action;
     2 
     3 import static com.whatisjee.ssf.web.jsf.FacesUtils.getService;
     4 
     5 import java.io.Serializable;
     6 
     7 import org.jboss.seam.ScopeType;
     8 import org.jboss.seam.annotations.Create;
     9 import org.jboss.seam.annotations.Name;
    10 import org.jboss.seam.annotations.Scope;
    11 
    12 import com.whatisjee.ssf.domain.entity.Log;
    13 import com.whatisjee.ssf.domain.service.AppService;
    14 import com.whatisjee.ssf.misc.LogCriteria;
    15 import com.whatisjee.ssf.misc.Page;
    16 import com.whatisjee.ssf.misc.PagingList;
    17 import com.whatisjee.ssf.web.jsf.PagingDataModel;
    18 
    19 @Name("logsAct")
    20 @Scope(ScopeType.PAGE)
    21 public class LogsAction implements Serializable {
    22     private static final long serialVersionUID = -5252797451562495196L;
    23     
    24     private LogCriteria criteria;
    25     private PagingDataModel<Log> data;
    26     private String detail;
    27 
    28     public LogCriteria getCriteria() {
    29         return criteria;
    30     }
    31 
    32     public PagingDataModel<Log> getData() {
    33         return data;
    34     }
    35 
    36     public String getDetail() {
    37         return detail;
    38     }
    39 
    40     public void setDetail(String detail) {
    41         this.detail = detail;
    42     }
    43 
    44     @Create
    45     public void init() {
    46         criteria = new LogCriteria();
    47         data = new PagingDataModel<Log>("#{logsAct.find}"false);
    48     }
    49     
    50     public PagingList<Log> find(Page page) {
    51         AppService service = getService("appService", AppService.class);
    52         return service.findLogs(criteria, page);
    53     }
    54     
    55     public void find() {
    56         data.refresh();
    57     }
    58     
    59     public void showDetail() {
    60         Log log = (Log) data.getRowData();
    61         detail = log.getDetail();
    62     }
    63 }

    如果朋友們有看過我之前的文章《Seam的頁面邏輯實現》,應該對上述代碼不會陌生,值得注意的是類型分別為LogCriteria和PaginDataModel<Log>的兩個域,前者是為了封裝界面上傳過來的查詢條件,后者則是整個數據分頁和排序的關鍵。只需將它綁定到Richfaces的數據列表組件(如<rich:dataTable>、<rich:dataGrid>等),即可實現分頁和排序。上例中通過兩個參數構造PagingDataModel:第一個字符串參數el用來指明PagingDataModel應該調用那個方法獲得數據。它是一個EL表達式,類似#{xxx.xxx}。前半部分的xxx多數情況下與Action的名稱相同,在本例中同為“loginAct”。后半部分xxx就是數據獲取方法的名稱,這個方法必須有且只有一個參數而且類型為com.whatisjee.ssf.misc.Page,返回值必須為com.whatisjee.ssf.misc.PagingList類型。Page類包含分頁和排序必不可少的信息如:從第幾行開始獲取數據,獲取多少行,通過什么列進行排序,升序還是降序等。而PagingList則封裝了總共有多少行和本頁數據的信息。如本例的find方法通過將LogCriteria和Page傳給AppService的findLogs方法,查詢數據庫獲取數據。第二個布爾參數stateful指明PagingDataModel是否需要自己保存狀態。如果它是位于有狀態的Action中,即Action的Scope為Application、Session、Conversation或者Page,則無需自己保存狀態,如本例中應為false。對于那些沒有狀態的Action,即Scope為Request或Event,應為true。另外,PagingDataModel還有兩個可選的構造參數:一個是Page類型指明page首次加載數據時分頁信息,另外一個字符串類型id僅用于在stateful為true且在一個頁面上有多個PagingDataModel時,將它們區分開來。

    至于,詳細的PagingDataModel的實現大家如果有興趣的話,可以過目一下,由于時間有限,我就不做詳細解釋了。

      1 package com.whatisjee.ssf.web.jsf;
      2 
      3 import static com.whatisjee.ssf.misc.Page.ORDER_ASC;
      4 import static com.whatisjee.ssf.misc.Page.ORDER_DESC;
      5 import static org.richfaces.model.Ordering.ASCENDING;
      6 import static org.richfaces.model.Ordering.DESCENDING;
      7 
      8 import java.io.IOException;
      9 import java.io.Serializable;
     10 import java.util.Collection;
     11 import java.util.Collections;
     12 import java.util.List;
     13 import java.util.Map;
     14 import java.util.Set;
     15 
     16 import javax.el.ELContext;
     17 import javax.el.ELException;
     18 import javax.el.ExpressionFactory;
     19 import javax.el.MethodExpression;
     20 import javax.faces.application.Application;
     21 import javax.faces.component.UIViewRoot;
     22 import javax.faces.context.FacesContext;
     23 
     24 import org.ajax4jsf.model.DataVisitor;
     25 import org.ajax4jsf.model.Range;
     26 import org.ajax4jsf.model.SequenceRange;
     27 import org.ajax4jsf.model.SerializableDataModel;
     28 import org.apache.commons.logging.Log;
     29 import org.apache.commons.logging.LogFactory;
     30 import org.richfaces.model.FilterField;
     31 import org.richfaces.model.Modifiable;
     32 import org.richfaces.model.Ordering;
     33 import org.richfaces.model.SortField2;
     34 
     35 import com.whatisjee.ssf.misc.Page;
     36 import com.whatisjee.ssf.misc.PagingList;
     37 import com.whatisjee.ssf.misc.Page.Order;
     38 
     39 /**
     40  * This PagingDataModel is built to support "true" paging and sorting for Richfaces's data iteration components
     41  *  e.g. &lt;rich:dataTable/&gt;, &lt;rich:dataGrid/&gt;. The "true" paging and sorting means those kinds of things can be
     42  *  done in database by SQL.
     43  * @author Max Yuan(max.m.yuan@gmail.com)
     44  * @param <T> A class which must be Serializable.
     45  */
     46 public class PagingDataModel<extends Serializable> extends SerializableDataModel implements
     47         Modifiable {
     48     private static final long serialVersionUID = -5956332259881655981L;
     49     private static final Log _LOG = LogFactory.getLog(PagingDataModel.class);
     50     private static final String KEY_PAGE = "PAGE";
     51     private static final String KEY_LIST = "LIST";
     52     
     53     public static final int DEFAULT_ROWS = 10;
     54     public static final String DEFAULT_ID = "DEFAULT";
     55     
     56     private Page page;
     57     private PagingList<T> list;
     58     private String el;
     59     private String keyPage;
     60     private String keyList;
     61     private boolean stateful;
     62 
     63     private Integer rowKey = new Integer(0);
     64     private boolean cached, changed, modified;
     65     
     66     private static Map<String, Object> DUMMY_MAP = new Map<String, Object>() {
     67         public void clear() {}
     68 
     69         public boolean containsKey(Object key) { return false; }
     70 
     71         public boolean containsValue(Object value) { return false; }
     72 
     73         public Set<java.util.Map.Entry<String, Object>> entrySet() { return null; }
     74 
     75         public Object get(Object key) { return null; }
     76 
     77         public boolean isEmpty() { return false; }
     78 
     79         public Set<String> keySet() { return null; }
     80 
     81         public Object put(String key, Object value) { return null; }
     82 
     83         public void putAll(Map<? extends String, ? extends Object> m) {}
     84 
     85         public Object remove(Object key) { return null; }
     86 
     87         public int size() { return 0; }
     88 
     89         public Collection<Object> values() { return null; }
     90     };
     91     
     92     
     93     /**
     94      * This is construction method to create a PagingDataModel which you can fully control it's behavior.
     95      * @param el An EL expression points to a method which must like "public PagingList<T> xxx(Page xxx)".
     96      * @param page To specify the total records and initial sorting criteria.
     97      * @param id Use to identify this PagingDataModel from another one.
     98      * @param stateful Use to specify whether to keep the state to avoid loading data every time page is loaded.
     99      * If the Managed Bean who contains this PagingDataModel can keep state, e.g. Session Scope Bean, Application Scope Bean,
    100      * Page Scope(only available for Seam) Bean, then this parameter can be "false", otherwise please set it "true".
    101      */
    102     public PagingDataModel(String el, Page page, String id, boolean stateful) {
    103         this.el = el;
    104         this.keyPage = KEY_PAGE + "$" + id;
    105         this.keyList = KEY_LIST + "$" + id;
    106         this.stateful = stateful;
    107 
    108         Map<String, Object> attrs = getAttributes();
    109         Object _page = attrs.get(keyPage);
    110         if(_page != null) {
    111             this.page = (Page) _page;
    112             cached = true;
    113         } else {
    114             this.page = page;
    115             attrs.put(keyPage, page);
    116         }
    117     }
    118     
    119     /**
    120      * This construction method create a PagingDataModel with default amount of rows is 10.
    121      * @param el An EL expression points to a method which must like "public PagingList<T> xxx(Page xxx)".
    122      * @param id Use to identify this PagingDataModel from another one.
    123      * @param stateful Use to specify whether to keep the state to avoid loading data every time page is loaded.
    124      * If the Managed Bean which contains this PagingDataModel can keep state, e.g. Session Scope Bean, Application Scope Bean,
    125      * Page Scope(only available for Seam) Bean, then this parameter can be "false", otherwise please set it "true".
    126      */
    127     public PagingDataModel(String el, String id, boolean stateful) {
    128         this(el, new Page(0, DEFAULT_ROWS), id, stateful);
    129     }
    130     
    131     /**
    132      * This construction method create a PagingDataModel with default amount of rows is 10 and the id set to be "DEFAULT"
    133      *  for only one PagingDataModel in a page.
    134      * @param el An EL expression points to a method which must like "public PagingList<T> xxx(Page xxx)".
    135      * @param stateful Use to specify whether to keep the state to avoid loading data every time page is loaded.
    136      * If the Managed Bean which contains this PagingDataModel can keep state, e.g. Session Scope Bean, Application Scope Bean,
    137      * Page Scope(only available for Seam) Bean, then this parameter can be "false", otherwise please set it "true".
    138      */
    139     public PagingDataModel(String el, boolean stateful) {
    140         this(el, new Page(0, DEFAULT_ROWS), DEFAULT_ID, stateful);
    141     }
    142     
    143     /**
    144      * This construction method create a PagingDataModel with default amount of rows is 10 and can keep state.
    145      * @param el An EL expression points to a method which must like "public PagingList<T> xxx(Page xxx)".
    146      * @param id Use to identify this PagingDataModel from another one.
    147      */
    148     public PagingDataModel(String el, String id) {
    149         this(el, new Page(0, DEFAULT_ROWS), id, true);
    150     }
    151     
    152     /**
    153      * This construction method create a PagingDataModel with default amount of rows is 10, can keep state and
    154      *  the id parameter set to be "DEFAULT" for only one PagingDataModel in a page.
    155      * @param el An EL expression points to a method which must like "public PagingList<T> xxx(Page xxx)".
    156      */
    157     public PagingDataModel(String el) {
    158         this(el, new Page(0, DEFAULT_ROWS), DEFAULT_ID, true);
    159     }
    160     
    161     @Override
    162     public void update() {
    163         // DO NOTHING
    164     }
    165 
    166     @Override
    167     public Object getRowKey() {
    168         return rowKey;
    169     }
    170 
    171     @Override 
    172     public void setRowKey(Object rowKey) {
    173         this.rowKey = (Integer) rowKey;
    174     }
    175     
    176     private Map<String, Object> getAttributes() {
    177         Map<String, Object> attrs = null;
    178         if(stateful){
    179             UIViewRoot root = FacesContext.getCurrentInstance().getViewRoot();
    180             attrs = root.getAttributes();
    181         } else {
    182             attrs = DUMMY_MAP;
    183         }
    184         return attrs;
    185     }
    186     
    187     @SuppressWarnings("unchecked")
    188     private PagingList<T> getList() {
    189         if(changed) {
    190             refresh();
    191         } else if(stateful) {
    192             list = (PagingList<T>) getAttributes().get(keyList);
    193         }
    194         return list;
    195     }
    196 
    197     @Override
    198     public void walk(FacesContext context, DataVisitor visitor, Range range,
    199             Object argument) throws IOException {
    200         SequenceRange seqRange = (SequenceRange) range;
    201         boolean isNew = page.getFirstRow() != seqRange.getFirstRow();
    202         if (isNew) {
    203             page.setFirstRow(seqRange.getFirstRow());
    204         }
    205         page.setRows(seqRange.getRows());
    206         
    207         if(!cached || isNew || modified) {
    208             changed = true;
    209             modified = false;
    210             cached = true;
    211         }
    212 
    213         int i = 0;
    214         List<T> data = getList().getData();
    215         if (data != null) {
    216             for (@SuppressWarnings("unused") T t : data) {
    217                 visitor.process(context, i++, argument);
    218             }
    219         }
    220     }
    221 
    222     @Override
    223     public int getRowCount() {
    224         PagingList<T> list = getList();
    225         return (list == null? 0 : list.getCount();
    226     }
    227 
    228     @Override
    229     public Object getRowData() {
    230         PagingList<T> list = getList();
    231         return (list == null || list.getData() == null || rowKey == null? null
    232                 : list.getData().get(rowKey.intValue());
    233     }
    234 
    235     @Override
    236     public int getRowIndex() {
    237         throw new UnsupportedOperationException();
    238     }
    239 
    240     @Override
    241     public Object getWrappedData() {
    242         throw new UnsupportedOperationException();
    243     }
    244 
    245     @Override
    246     public boolean isRowAvailable() {
    247         PagingList<T> list = getList();
    248         return (list != null&& (list.getData() != null&& (rowKey != null)
    249                 && (rowKey.intValue() < list.getData().size());
    250     }
    251 
    252     @Override
    253     public void setRowIndex(int arg0) {
    254         throw new UnsupportedOperationException();
    255     }
    256 
    257     @Override
    258     public void setWrappedData(Object arg0) {
    259         throw new UnsupportedOperationException();
    260     }
    261 
    262     /**
    263      * Use to execute the <i>el</i> method to refresh data manually.
    264      */
    265     @SuppressWarnings("unchecked")
    266     public void refresh() {
    267         list = (PagingList<T>) evaluateEL(el, PagingList.class,
    268                 new Class<?>[] { Page.class }, page);
    269         if(list == null) {
    270             list = PagingList.EMPTY_LIST;
    271         }
    272         getAttributes().put(keyList, list);
    273         changed = false;
    274     }
    275     
    276     private static Object evaluateEL(String el, Class<?> returnType,
    277             Class<?>[] paramTypes, Object params) {
    278         Object result = null;
    279         FacesContext fc = FacesContext.getCurrentInstance();
    280         ELContext elc = fc.getELContext();
    281         Application app = fc.getApplication();
    282         ExpressionFactory ef = app.getExpressionFactory();
    283         MethodExpression me = ef.createMethodExpression(elc, el, returnType, paramTypes);
    284         try {
    285             result = me.invoke(elc, params);
    286         } catch (ELException e) {
    287             Throwable cause = e.getCause();
    288             if(cause instanceof RuntimeException) {
    289                 throw ((RuntimeException) cause);
    290             } else {
    291                 if(_LOG.isErrorEnabled()) {
    292                     _LOG.error("Exception occured during evaluation of EL, because ", cause);
    293                 }
    294             }
    295         }
    296         return result;
    297     }
    298     
    299     @Override
    300     public  SerializableDataModel getSerializableModel(Range range) {
    301         return this;
    302     }
    303     
    304     public Page getPage() {
    305         return page;
    306     }
    307     
    308     @SuppressWarnings("unchecked")
    309     public List<T> getData() {
    310         PagingList<T> list = getList();
    311         return list != null ? list.getData() : Collections.EMPTY_LIST;
    312     }
    313 
    314     public void modify(List<FilterField> filterFields,
    315             List<SortField2> sortFields) {
    316         if(sortFields != null && sortFields.size() > 0) {
    317             SortField2 sf = sortFields.iterator().next();
    318             
    319             String prop = sf.getExpression().getExpressionString();
    320             String orderBy = prop.substring(2, prop.length() - 1);
    321             if(!orderBy.equals(page.getOrderBy())) {
    322                 page.setOrderBy(orderBy);
    323                 modified = true;
    324             }
    325             
    326             Ordering ordering = sf.getOrdering();
    327             Order order = page.getOrder();
    328             if(ASCENDING.equals(ordering) && !ORDER_ASC.equals(order)) {
    329                 page.setOrder(ORDER_ASC);
    330                 modified = true;
    331             } else if(DESCENDING.equals(ordering) && !ORDER_DESC.equals(order)) {
    332                 page.setOrder(ORDER_DESC);
    333                 modified = true;
    334             }
    335         }
    336     }
    337 
    338 }

    再來看看頁面的XHTML代碼片段,如下列表所示。

     1 <rich:dataTable id="dtLogs" value="#{logsAct.data}" var="_log" rows="#{logsAct.data.page.rows}" styleClass="list">
     2     <rich:column sortBy="#{loggedAt}" styleClass="align-c" headerClass="align-c" selfSorted="true" sortOrder="DESCENDING">
     3         <f:facet name="header">
     4             <h:outputText value="#{messages['log.loggedAt']}"/>
     5         </f:facet>
     6         <h:outputText value="#{_log.loggedAt}">
     7             <s:convertDateTime pattern="#{messages['cmm.shortDateTime']}" />
     8         </h:outputText>
     9     </rich:column>
    10     <rich:column sortBy="#{username}" styleClass="align-l" headerClass="align-l">
    11         <f:facet name="header">
    12             <h:outputText value="#{messages['log.username']}"/>
    13         </f:facet>
    14         <h:outputText value="#{_log.username}" />
    15     </rich:column>
    16     <rich:column sortBy="#{terminal}" styleClass="align-c" headerClass="align-c">
    17         <f:facet name="header">
    18             <h:outputText value="#{messages['log.terminal']}"/>
    19         </f:facet>
    20         <h:outputText value="#{_log.terminal}" />
    21     </rich:column>
    22     <rich:column sortBy="#{severity}" styleClass="align-c" headerClass="align-c">
    23         <f:facet name="header">
    24             <h:outputText value="#{messages['log.severity']}"/>
    25         </f:facet>
    26         <h:outputText value="#{messages[$c['LOG_LABELS'][_log.severity - 1][1]]}" />
    27     </rich:column>
    28     <rich:column sortBy="#{summary}" styleClass="align-l" headerClass="align-l">
    29         <f:facet name="header">
    30             <h:outputText value="#{messages['log.summary']}"/>
    31         </f:facet>
    32         <h:outputText value="#{sf:getLogSummary(_log)}" />
    33     </rich:column>
    34     <rich:column styleClass="align-c" headerClass="align-c">
    35         <f:facet name="header">
    36             <h:outputText value="#{messages['log.detail']}"/>
    37         </f:facet>
    38         <a4j:commandLink action="#{logsAct.showDetail}" reRender="itDetail" oncomplete="Richfaces.showModalPanel('mpDetail')" rendered="#{not empty _log.detail}" styleClass="icon">
    39             <h:graphicImage value="/common/image/view.gif" alt="#{messages['cmm.remove']}" />
    40         </a4j:commandLink>
    41     </rich:column>
    42 </rich:dataTable>
    43 <rich:datascroller for="dtLogs" />

    這里也有幾點需要注意:<rich:dataTable>的rows應該如本例所示,直接使用PagingDataModel里的page的rows域,以免產生不一至。另外,<rich:column>的sortBy屬性應為“#{xxx}”的形式,通常為數據庫表的列名或Hiberante的實體的域名稱。

    小結

    本文簡單地描述了SSF針對SEAM和JSF里的數據分頁和排序問題的解決方法。只要大家在項目用到Racefaces,相信上述有代碼都會有所幫助。

    posted on 2011-01-04 01:10 Max 閱讀(4502) 評論(2)  編輯  收藏 所屬分類: Seam系列

    評論:
    # re: 簡便快捷的SSF數據分頁與排序 2011-01-04 08:58 | air nailer
    不錯,寫的非常詳細,學習了  回復  更多評論
      
    # re: 簡便快捷的SSF數據分頁與排序 2011-01-04 10:13 | ugg boots stores
    這些的代碼估計也不認得我啊、、  回復  更多評論
      
    主站蜘蛛池模板: 国产成人高清精品免费观看| 美女羞羞视频免费网站| 亚洲乱码av中文一区二区| 亚洲人成网站999久久久综合| 无码天堂亚洲国产AV| 韩国免费a级作爱片无码| 91精品免费高清在线| 成全视频在线观看免费高清动漫视频下载 | 国内精品免费在线观看| 最近最好最新2019中文字幕免费| 成人黄18免费视频| 久久久久亚洲爆乳少妇无| 亚洲国产综合91精品麻豆| 亚洲一区AV无码少妇电影| kk4kk免费视频毛片| 18成禁人视频免费网站| 日韩一区二区免费视频| 亚洲一区二区三区免费| 亚洲高清美女一区二区三区| 亚洲av无码专区在线观看亚| 在线观看片免费人成视频播放| 色se01短视频永久免费| 亚洲国产日韩成人综合天堂| 亚洲一区二区电影| 黄色网址大全免费| 在线免费观看亚洲| 亚洲国产精品激情在线观看 | 亚洲∧v久久久无码精品| 亚洲精品一卡2卡3卡四卡乱码| 国产一级黄片儿免费看| 毛片免费视频观看| 国产AV无码专区亚洲Av| 亚洲熟妇丰满xxxxx| 日本高清免费观看| 免费国产a国产片高清| 久久久久亚洲AV无码专区首JN| 黄色毛片视频免费| 国产情侣激情在线视频免费看| 国产亚洲大尺度无码无码专线| 国产亚洲sss在线播放| 大地资源在线资源免费观看|