Announcement Announcement Module
Collapse
No announcement yet.
Pageable data list with Hibernate Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • #16
    Note 1:

    It is time to make some command objects to wrap those parameters from the web.

    l have

    - 3 parameters command object (keyword , page , pageSize) for Simple Paging , l called it SimpleCommand.java
    - 5 parameters command object (keyword , page , pageSize , sortColumn , ascending ) for Google+Sorting Paging , called it GoogleSortCommand.java.
    .....etc....a lot of commands can be make which depend on what paging you use....

    l have now two package , library (my main application , org.yourschool.library.*) and simplePage (org.simplePage.*) package , my question now is , which package those commands live ?

    it seem trivial to put those commands into the simplePage package because of the usability of those commands , but it will cause library package to depend on simplePage package API when the library application choose simplePaging as the application paging .

    How about putting it into the library package ? if l do this , those commands will become library package "property" , cannot be reuse in another application Y , Y have to make himself another similar commands.

    Both have pro and con , so my conclusion , choose one you think more suitable for yourself....

    any other thought ?

    Note 2:

    These paging patterns (simple,google,...) are not new , and l just found an similar example which implement paging using velocity , http://www.javabb.org .... ...l think it is more easy to use velocity to implement paging.

    moon

    Comment


    • #17
      Note 3.
      Question:
      1. l discovered that it is unexpected simple to do paging after these three different version pagings , am l doing wrong ?
      l wish to confess here that paging is simple to do ...hihihi.

      l have some minor progress since then --> l have the feeling that paging are depend on the frameowrks (more complex frameworks).

      Let me explain the feeling ,

      l have an initProperties() method to feed the simpleTag the necessary properties , especially the Map - parameters , it is the heart of the simpleTag . Where l get the parameters ? if you look at my code , you will find that it just before the request vanish ! -- that means the parameters are not feed by controllers , but get it from the web server using
      Code:
      HttpServletRequest request = (HttpServletRequest) pageContext.getRequest();
      this.parameters = RequestUtil.getRequestParameterMap(request);
      Paging alway use "url + parameters" to make link , this type of pagings are work well in current frameworks (SpringMVC , Webwork , Struts...), but what if (for some cases)

      1. we cannot get those parameters using code above ? ( for example , SWF lock it in the flow * after the first request and not throwing out in the third request) .

      2. there is some other parameters** except for the command parameters (page , pageSize , sortColumn , ...) in the same page to be handled (_flowExecutionId , _EventId ,... for example) ? and they are needed for submition to make the MVC framework function ? ( like SWF, for example . But not just limit to SWF , other more complex MVC frameworks may have subject to the same problem if they are using parameters for work flow controll )

      SWF are the only example that l can find to express "my feeling" ....

      Is that my feeling about "paging are sometime depend on frameworks" true ?

      * http://forum.springframework.org/showthread.php?t=15862
      ** http://forum.springframework.org/showthread.php?t=15960

      moon
      Last edited by robyn; May 16th, 2006, 04:36 AM.

      Comment


      • #18
        find returns empty list

        Object [] params2 = new Object[]{gsmno};
        System.out.println("HibernateinvoiceDao-->getInvoicebyGsmNo-->gsmno"+gsmno+" startDate="+startDate.toString());
        if(getHibernateTemplate() == null)
        System.out.println("getHibernateTemplate()is NULL");

        List tmp = getHibernateTemplate().find("from com.telsim.ccb.model.CcbInvoiceMaster cim where cim.id.gsmNo=?",gsmno);
        System.out.println("getInvoicebyGsmNo-->SIZE=="+tmp.size());
        return tmp;

        I noticed that it stops reading the resultset when coloumn value in a row is NULL.
        Length of the returrning list is OK but all the values in the list is set to nULL..
        What can be the problem..

        Related messages are below:




        2005-06-28 09:35:15,455 DEBUG [org.hibernate.jdbc.AbstractBatcher] - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
        2005-06-28 09:35:15,455 DEBUG [org.hibernate.SQL] - select ccbinvoice0_.INVOICE_NO as INVOICE1_, ccbinvoice0_.INVOICE_STATUS as INVOICE2_, ccbinvoice0_.PAYMENT_SOURCE as PAYMENT3_, ccbinvoice0_.PAYTYPE as PAYTYPE, ccbinvoice0_.GSM_NO as GSM5_, ccbinvoice0_.START_DATE as START6_, ccbinvoice0_.CUSTOMER_ID as CUSTOMER7_, ccbinvoice0_.BILLING_PERIOD as BILLING8_, ccbinvoice0_.GROUP_CODE as GROUP9_, ccbinvoice0_.GROUP_START_DATE as GROUP10_, ccbinvoice0_.INVOICE_DATE as INVOICE11_, ccbinvoice0_.DUE_DATE as DUE12_, ccbinvoice0_.DUE_AMOUNT as DUE13_, ccbinvoice0_.INVOICE_AMOUNT as INVOICE14_, ccbinvoice0_.PAYMENT_DATE as PAYMENT15_, ccbinvoice0_.PAYMENT_VALUE as PAYMENT16_, ccbinvoice0_.PAYMENT_SOURCE_DEP as PAYMENT17_, ccbinvoice0_.SEND_DATE as SEND18_, ccbinvoice0_.SEND_FILE as SEND19_, ccbinvoice0_.RECEIVED_DATE as RECEIVED20_, ccbinvoice0_.RECEIVED_FILE as RECEIVED21_, ccbinvoice0_.PAYMENT_PROCESS_DATE as PAYMENT22_, ccbinvoice0_.ASSUMED_PAY_TYPE as ASSUMED23_, ccbinvoice0_.CITY_CODE as CITY24_, ccbinvoice0_.SCT_LATE as SCT25_, ccbinvoice0_.EARTQUAKE_FLAG as EARTQUAKE26_, ccbinvoice0_.YTS_IND as YTS27_, ccbinvoice0_.WARNING_REMINDER_IND as WARNING28_, ccbinvoice0_.FLAG as FLAG, ccbinvoice0_.LATE_PAYMENT_INTEREST_FLAG as LATE30_, ccbinvoice0_.CR_USER as CR31_, ccbinvoice0_.CR_DATE as CR32_, ccbinvoice0_.UPD_USER as UPD33_, ccbinvoice0_.UPD_DATE as UPD34_, ccbinvoice0_.UPD_SEQ as UPD35_, ccbinvoice0_.OTS_INSTITUTION as OTS36_, ccbinvoice0_.OTS_DIRECTION as OTS37_, ccbinvoice0_.OTS_LOG_DATE as OTS38_, ccbinvoice0_.OTS_LOG_TIME as OTS39_, ccbinvoice0_.OTS_LOG_SEQUENCE as OTS40_ from CCB.CCB_INVOICE_MASTER ccbinvoice0_ where ccbinvoice0_.GSM_NO=?
        Hibernate: select ccbinvoice0_.INVOICE_NO as INVOICE1_, ccbinvoice0_.INVOICE_STATUS as INVOICE2_, ccbinvoice0_.PAYMENT_SOURCE as PAYMENT3_, ccbinvoice0_.PAYTYPE as PAYTYPE, ccbinvoice0_.GSM_NO as GSM5_, ccbinvoice0_.START_DATE as START6_, ccbinvoice0_.CUSTOMER_ID as CUSTOMER7_, ccbinvoice0_.BILLING_PERIOD as BILLING8_, ccbinvoice0_.GROUP_CODE as GROUP9_, ccbinvoice0_.GROUP_START_DATE as GROUP10_, ccbinvoice0_.INVOICE_DATE as INVOICE11_, ccbinvoice0_.DUE_DATE as DUE12_, ccbinvoice0_.DUE_AMOUNT as DUE13_, ccbinvoice0_.INVOICE_AMOUNT as INVOICE14_, ccbinvoice0_.PAYMENT_DATE as PAYMENT15_, ccbinvoice0_.PAYMENT_VALUE as PAYMENT16_, ccbinvoice0_.PAYMENT_SOURCE_DEP as PAYMENT17_, ccbinvoice0_.SEND_DATE as SEND18_, ccbinvoice0_.SEND_FILE as SEND19_, ccbinvoice0_.RECEIVED_DATE as RECEIVED20_, ccbinvoice0_.RECEIVED_FILE as RECEIVED21_, ccbinvoice0_.PAYMENT_PROCESS_DATE as PAYMENT22_, ccbinvoice0_.ASSUMED_PAY_TYPE as ASSUMED23_, ccbinvoice0_.CITY_CODE as CITY24_, ccbinvoice0_.SCT_LATE as SCT25_, ccbinvoice0_.EARTQUAKE_FLAG as EARTQUAKE26_, ccbinvoice0_.YTS_IND as YTS27_, ccbinvoice0_.WARNING_REMINDER_IND as WARNING28_, ccbinvoice0_.FLAG as FLAG, ccbinvoice0_.LATE_PAYMENT_INTEREST_FLAG as LATE30_, ccbinvoice0_.CR_USER as CR31_, ccbinvoice0_.CR_DATE as CR32_, ccbinvoice0_.UPD_USER as UPD33_, ccbinvoice0_.UPD_DATE as UPD34_, ccbinvoice0_.UPD_SEQ as UPD35_, ccbinvoice0_.OTS_INSTITUTION as OTS36_, ccbinvoice0_.OTS_DIRECTION as OTS37_, ccbinvoice0_.OTS_LOG_DATE as OTS38_, ccbinvoice0_.OTS_LOG_TIME as OTS39_, ccbinvoice0_.OTS_LOG_SEQUENCE as OTS40_ from ZZ.WW_YY_XX ccbinvoice0_ where ccbinvoice0_.XX_AA=?
        2005-06-28 09:35:15,471 DEBUG [org.hibernate.jdbc.AbstractBatcher] - preparing statement
        2005-06-28 09:35:15,471 DEBUG [org.hibernate.type.StringType] - binding '5423877659' to parameter: 1
        2005-06-28 09:35:15,627 DEBUG [org.hibernate.jdbc.AbstractBatcher] - about to open ResultSet (open ResultSets: 0, globally: 0)
        2005-06-28 09:35:15,627 DEBUG [org.hibernate.loader.Loader] - processing result set
        2005-06-28 09:35:15,627 DEBUG [org.hibernate.loader.Loader] - result set row: 0
        2005-06-28 09:35:15,674 DEBUG [org.hibernate.type.StringType] - returning 'FBXXXXXXX' as column: INVOICE1_
        2005-06-28 09:35:15,674 DEBUG [org.hibernate.type.StringType] - returning 'AKTIF' as column: INVOICE2_
        2005-06-28 09:35:15,674 DEBUG [org.hibernate.type.StringType] - returning null as column: PAYMENT3_
        2005-06-28 09:35:15,674 DEBUG [org.hibernate.loader.Loader] - result row: null
        2005-06-28 09:35:15,674 DEBUG [org.hibernate.loader.Loader] - done processing result set (1 rows)
        2005-06-28 09:35:15,674 DEBUG [org.hibernate.jdbc.AbstractBatcher] - about to close ResultSet (open ResultSets: 1, globally: 1)
        2005-06-28 09:35:15,674 DEBUG [org.hibernate.jdbc.AbstractBatcher] - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
        2005-06-28 09:35:15,690 DEBUG [org.hibernate.jdbc.AbstractBatcher] - closing statement
        2005-06-28 09:35:15,690 DEBUG [org.hibernate.loader.Loader] - total objects hydrated: 0
        2005-06-28 09:35:15,690 DEBUG [org.hibernate.engine.PersistenceContext] - initializing non-lazy collections
        2005-06-28 09:35:15,690 DEBUG [org.springframework.transaction.support.Transactio nSynchronizationManager] - Retrieved value [org.springframework.orm.hibernate3.SessionHolder@1 e2c841] for key [org.hibernate.impl.SessionFactoryImpl@1c958af] bound to thread [http-8080-Processor23]

        Thanks
        Alper Aykac

        Comment


        • #19
          even more powerful if we use this paging pattern with hibernate dynamic queries(H3).

          DAO,
          Code:
          	public Map findItemsByCriteriaWithTotal(ItemCommand itemCommand)
          			throws DataAccessException {
          
          		ArrayList items = (ArrayList) findItemsByCriteriaWithLimit(itemCommand);
          		Integer totalFound = findItemsTotalByCriteria(itemCommand);
          
          		Map model = new HashMap();
          		model.put("_totalElements", totalFound);
          		model.put("_resultset", items);
          
          		return model;
          	}
          
          	public Collection findItemsByCriteriaWithLimit(ItemCommand itemCommand)
          			throws DataAccessException {
          
          		final Item item = itemCommand.getItem();
          		final Book ibook = item.getBook();
          
          		final String sortColumn = itemCommand.getS_sortColumn();
          		final int page = itemCommand.getS_page();
          		final int pageSize = itemCommand.getS_pageSize();
          		final int ascending = itemCommand.getS_ascending();
          
          		return getHibernateTemplate().executeFind(new HibernateCallback() {
          			public Object doInHibernate(Session session)
          					throws HibernateException, SQLException {
          
          				Example exampleItem = Example.create(item).ignoreCase()
          						.enableLike(MatchMode.ANYWHERE);
          				Example exampleBook = Example.create(ibook).ignoreCase()
          						.enableLike(MatchMode.ANYWHERE);
          
          				Criteria criteria = session.createCriteria(Item.class)
          						.add(exampleItem);
          				
          				if (ascending > 0) {
          					criteria.addOrder(Order.asc(sortColumn));
          				} else {
          					criteria.addOrder(Order.desc(sortColumn));
          				}
          				
          				criteria.createCriteria("book")
          						.add(exampleBook)
          						.setFirstResult(page * pageSize)
          						.setMaxResults(pageSize);
          
          				return criteria.list();
          			}
          		});
          	}
          
          	public Integer findItemsTotalByCriteria(ItemCommand itemCommand)
          			throws DataAccessException {
          
          		final Item item = itemCommand.getItem();
          		final Book ibook = item.getBook();
          
          		return (Integer) getHibernateTemplate().execute(
          				new HibernateCallback() {
          					public Object doInHibernate(Session session)
          							throws HibernateException, SQLException {
          
          						Example exampleItem = Example.create(item).ignoreCase()
          								.enableLike(MatchMode.ANYWHERE);
          						Example exampleBook = Example.create(ibook)
          								.ignoreCase().enableLike(MatchMode.ANYWHERE);
          
          						Integer count = (Integer) session.createCriteria(Item.class)
          								.setProjection(Projections.rowCount())
          								.add(exampleItem)
          								.createCriteria("book")
          								.add(exampleBook)
          								.uniqueResult();
          					
          						return count;
          
          					}
          				});
          	}
          Domain 1 - Item.java
          Code:
          public class Item  implements java.io.Serializable {
          
              // Fields    
          
               private Long id;
               private Long version;
               private String barcode;
               private String shelfMark;
               private Date lastCheckin;
               private Borrow borrow;
               private Book book;
               private ItemDuration itemDuration;
               private ItemType itemType;
               private Location location;
               private ItemStatusType itemStatusType;
          
               // get ,set
               ......
          }
          Domain 2 - Book.java
          Code:
          public class Book implements java.io.Serializable {
          
                // Fields
                private Long id;
                private Long version;
                private String title;
                private Integer publishingYear;
                private String isbn;
                private String edition;
                private String description;
                private String publicationPlace;
                private String classMark;
                private String attachment;
                private Set items;
                private Set authors = new HashSet();
                private Set subjects = new HashSet();
                private Set seriez = new HashSet();
                private Set otherTitles = new HashSet();
                private Set reservations;
                private Note note;
                private Publisher publisher;
                // get , set
                ......
          }
          Controller , (AbstractPagingFormController extends AbstractLibraryFormController , and AbstractLibraryFormController extends SimpleFormController)
          Code:
          public class ItemSearch extends AbstractPagingFormController {
          
          	private String itemColumnKey;
          	
          	public ItemSearch() {
          		setCommandClass(ItemCommand.class);
          		setCommandName("itemCommand");
          		setSessionForm(true);
          	}
          	
          	public void setItemColumnKey(String itemColumnKey) {
          		this.itemColumnKey = itemColumnKey;
          	}
          
          	public ModelAndView onSubmit(HttpServletRequest request,
          			HttpServletResponse response, Object command, BindException errors)
          			throws Exception {
          
          		ItemCommand itemCommand = (ItemCommand) command;
          
          		Map model = getLibrary().findItemsByCriteriaWithTotal(itemCommand);
          
          		ArrayList items = (ArrayList) model.get("_resultset");
          			
          		if &#40;items.size&#40;&#41; < 1&#41; &#123;
          			// no item found
          			return new ModelAndView&#40;getSuccessView&#40;&#41;, "NoItemFound",
          						"notEmptyString"&#41;;
          		&#125;
          		// multiple items found
          		return new ModelAndView&#40;getSuccessView&#40;&#41;, "Items", model&#41;;			
          
          	&#125;
          	
          	protected void onBindAndValidate&#40;HttpServletRequest request,
          			Object command, BindException errors&#41; throws Exception &#123;
          
          		String sortColumn = &#40;&#40;ItemCommand&#41; command&#41;.getS_sortColumn&#40;&#41;;
          
          		if &#40;!PagingUtil.IsSortColumnMatch&#40;sortColumn, itemColumnKey&#41;&#41; &#123;
          			// Reconsider !!
          			errors.rejectValue&#40;"s_sortColumn", "SortColumnNotMatch",
          					"Action and SortColumn Not Match !"&#41;;
          
          		&#125;
          
          	&#125;
          AbstractPagingFormController.java ,
          Code:
          public abstract class AbstractPagingFormController extends AbstractLibraryFormController &#123;
          
          	// Just for Paging
          	protected boolean isFormSubmission&#40;HttpServletRequest request&#41; &#123;
          
          	        if &#40;"POST".equals&#40;request.getMethod&#40;&#41;&#41;&#41; return true ;
          
                          Enumeration paramNames = request.getParameterNames&#40;&#41;;
                          while&#40;paramNames.hasMoreElements&#40;&#41;&#41; &#123;
                                  String parm = &#40;String&#41;paramNames.nextElement&#40;&#41;;
                                  if &#40;parm.startsWith&#40;"s_"&#41;&#41; return true;
                          &#125;
          
                          return false;
          	&#125;
          
          &#125;
          itemColumnKey is use to block direct url writing in browser's address bar.

          library-servlet.xml ,
          Code:
          	<bean id="simplePagingPropertyConfigurer"
          		class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
          		<property name="locations">
          			<list>
          				<value>/WEB-INF/sortColumn.properties</value>
          			</list>
          		</property>
          	</bean>
          .....
          	<bean id="itemSearchForm" class="org.yourschool.library.web.ItemSearch">
          		<property name="library"><ref bean="library"/></property>
           		<property name="validator"><ref bean="beanValidator"/></property>
          		<property name="formView"><value>itemSearchForm</value></property>
          		<property name="successView"><value>item.results</value></property>
          		<property name="itemColumnKey"><value>$&#123;itemSC&#125;</value></property>
                 // *******************************************************		
          	</bean>
          PagingUtil.java ,
          Code:
          public class PagingUtil  &#123;
          
                 private static String delimiter = ",";
                 
                 public void setDelimiter&#40;String delimiter&#41; &#123;
                        PagingUtil.delimiter = delimiter;
                 &#125;
          
                 public static boolean IsSortColumnMatch&#40;String sortColumn,String key&#41; &#123;
          
                        boolean isSortColumnMatch = false;
                        StringTokenizer st = new StringTokenizer&#40;key,delimiter&#41;;
                        while &#40;st.hasMoreTokens&#40;&#41;&#41; &#123;
                              if &#40;st.nextToken&#40;&#41;.equals&#40;sortColumn&#41;&#41; &#123;
                                 isSortColumnMatch = true;
                                 break;
                              &#125;
                        &#125;
          
                        return isSortColumnMatch;
                 &#125;
          
          
          &#125;
          sortColumn.properties ,
          Code:
          #Created by JInto - www.guh-software.de
          #Tue Aug 30 18&#58;39&#58;33 SGT 2005
          authorSC=id,authorName
          bookSC=id,title,publishingYear,isbn,edition,description,publicationPlace,classMark,attachment
          itemSC=id,barcode,shelfMark,lastCheckin
          otherTitleSC=id,otherTitleName
          publisherSC=id,publisherName
          seriesSC=id,seriesName
          subjectSC=id,subjectName
          commond validator constrains to parameter s_sortColumn , s_page , ...
          Code:
          	<formset>
                  <form name="itemCommand">
                      <field property="s_sortColumn" depends="required">
                          <arg0 key="_sortColumn"/>
                      </field>
                      <field property="s_page" depends="required,integer,intRange">
                          <arg0 key="_page"/>
                          <arg1 name="intRange" key="$&#123;var&#58;min&#125;" resource="false"/>
                          <arg2 name="intRange" key="$&#123;var&#58;max&#125;" resource="false"/>
                          <var><var-name>min</var-name><var-value>0</var-value></var>
                          <var><var-name>max</var-name><var-value>1000000000</var-value></var>
                      </field>
                      <field property="s_pageSize" depends="required,integer,intRange">
                          <arg0 key="_pageSize"/>
                          <arg1 name="intRange" key="$&#123;var&#58;min&#125;" resource="false"/>
                          <arg2 name="intRange" key="$&#123;var&#58;max&#125;" resource="false"/>
                          <var><var-name>min</var-name><var-value>0</var-value></var>
                          <var><var-name>max</var-name><var-value>50</var-value></var>
                      </field>
                      <field property="s_ascending" depends="required,integer,intRange">
                          <arg0 key="_ascending"/>
                          <arg1 name="intRange" key="$&#123;var&#58;min&#125;" resource="false"/>
                          <arg2 name="intRange" key="$&#123;var&#58;max&#125;" resource="false"/>
                          <var><var-name>min</var-name><var-value>0</var-value></var>
                          <var><var-name>max</var-name><var-value>1</var-value></var>
                       </field>
                  </form>
              </formset>
          Command - ItemCommand.java ,
          Code:
          public class ItemCommand implements Serializable &#123;
          
          	private int page;
          	private int pageSize;
          	private int ascending;
          	private String sortColumn;
          	private Item item;
          
          	public ItemCommand&#40;&#41; &#123;
          		
          		this.item = new Item&#40;&#41;;
          		
          		Date lastCheckin = null;
          		item.setLastCheckin&#40;lastCheckin&#41;;
          		
          		Book book = new Book&#40;&#41;;
          		item.setBook&#40;book&#41;;
          
          	&#125;
                ..... // get , set
          &#125;
          GoogleTag.java (minor change),
          Code:
          public class GoogleTag extends BodyTagSupport &#123;
          
              private Map parameters;
              private String modelName;
              private int listSize;
              // Some databases are not allow pageSize to be negative &#40;Hibernate's MaxResults has to be >= 0&#41;
              private int pageSize;
              private int page;
              private int totalElements;
              private int pagingWidth = 11;
              //TODO pagingWidth cannot be negative !!
              private String previousPageLink;
              private String nextPageLink;
              //private LinkEncoder UrlEncoder = new LinkEncoder&#40;&#41;;
              public static final String PAGE = "s_page";
              public static final String PAGE_SIZE = "s_pageSize";
          
              public void setModelName&#40;String modelName&#41;&#123;
                     this.modelName = modelName;
              &#125;
          
              public void setPagingWidth&#40;int pagingWidth&#41;&#123;
                     this.pagingWidth = pagingWidth;
              &#125;
          
              public int doStartTag&#40;&#41; throws JspException &#123;
                     
                     initProperties&#40;&#41;;
          
                     if&#40;pageSize > 0&#41;&#123;
                          try&#123;
                        	    writePaging&#40;&#41;;
                          &#125;catch&#40;IOException ex&#41; &#123;
                              ex.getMessage&#40;&#41;;
                          &#125;
                     &#125;
          
                     return SKIP_BODY;
              &#125;
          
              public int doEndTag&#40;&#41; throws JspException &#123;
                     return EVAL_PAGE;
              &#125;
          
              public void initProperties&#40;&#41;&#123;
          
                     HttpServletRequest request = &#40;HttpServletRequest&#41; pageContext.getRequest&#40;&#41;;
                     this.parameters = RequestUtil.getRequestParameterMap&#40;request&#41;;
          
                     String Page = &#40;String&#41;parameters.get&#40;PAGE&#41;;
                     // The reason for doing this is due to the page , pageSize , ascending are int and NOT Integer&#40;Object&#41; ,
                     // then "0" will be given by the Spring binder if clients are not supply the parameter name &#40;not parameter value&#41;.
                     if &#40;Page == null || Page.equals&#40;""&#41;&#41;&#123;
                           this.page = 0;
                     &#125;else&#123;
                           this.page = Integer.parseInt&#40;Page&#41;;
                     &#125;
          
                     String PageSize = &#40;String&#41;parameters.get&#40;PAGE_SIZE&#41;;
          
                     if &#40;PageSize == null || PageSize.equals&#40;""&#41;&#41;&#123;
                           this.pageSize = 0;
                     &#125;else&#123;
                           this.pageSize = Integer.parseInt&#40;PageSize&#41;;
                     &#125;
          
                     this.listSize = &#40;&#40;List&#41;&#40;&#40;Map&#41;request.getAttribute&#40;modelName&#41;&#41;.get&#40;"_resultset"&#41;&#41;.size&#40;&#41;;
                     this.totalElements =  &#40;&#40;Integer&#41;&#40;&#40;Map&#41;request.getAttribute&#40;modelName&#41;&#41;.get&#40;"_totalElements"&#41;&#41;.intValue&#40;&#41;;
          
                     this.previousPageLink = LinkEncoder.encode&#40;makePreviousPageParameters&#40;parameters&#41;&#41;;
                     this.nextPageLink = LinkEncoder.encode&#40;makeNextPageParameters&#40;parameters&#41;&#41;;
          
              &#125;
          
              public void writePaging&#40;&#41; throws IOException &#123;
          
                     StringBuffer sb = new StringBuffer&#40;&#41;;
          
                     // Declare Variable
                     int totalPages ;
          
                     if&#40;totalElements%pageSize == 0&#41;&#123;
                          totalPages = &#40;totalElements/pageSize&#41; ;
                     &#125;else&#123;
                          totalPages = &#40;totalElements/pageSize&#41; + 1 ;
                     &#125;
          
                     int pageA = &#40;pagingWidth/2&#41; + 1 ;
                     int pageC = totalPages - pageA ;
                     int lastPage = totalPages - 1 ;
          
                     //Display total number
                     sb.append&#40;"|"&#41;.append&#40;totalElements&#41;.append&#40;"|......."&#41;;
                     //.append&#40;page+1&#41;.append&#40;"/"&#41;.append&#40;totalPages&#41;.append&#40;"......."&#41;;
          
                     if &#40;isPreviousPage&#40;&#41;&#41; &#123;
                                  sb.append&#40;"<a href=\"?"&#41;.append&#40;previousPageLink&#41;;
                                  sb.append&#40;"\"><font color=\"blue\"><B><<<</B></font></a>\n"&#41;;
                                  //sb.append&#40;"\"><img alt=\"Next\" src=\"../img/btn_prev.gif\" border=\"0\"/></a>\n"&#41;;
                     &#125;
                                  sb.append&#40;""&#41;;
          
                     //Reminder &#58; First page in Hibernate ---> page = 0 , not page = 1 !!
          /**
          
           page &#58;    0 , 1 , 2 , ..... , pageA , pageA + 1 , ..... , pageC -1 , pageC , ....., totalPages - 1
                     |                         |                              |                         |
                     firstPage                 |                              |              lastPage
                     page = 0                  |                              |              page = totalPages - 1
                     |                         |                              |                         |
                     |-------- Region A -------|----------- Region B ---------|-------- Region C -------|
                     |  0 <= page <= pageA     |   pageA < page < pageC       |pageC <= page <= lastPage|
          **/
          
                     //Case 1 &#58; if lastPage < pagingWidth + 2
          
                     if &#40; lastPage < pagingWidth + 2 &#41;&#123;
          
                           for&#40; int i = 0 ; i < lastPage + 1 ; i++ &#41;&#123;
                                if&#40; page == i &#41;&#123;
                                    sb.append&#40;page+1&#41;.append&#40;""&#41;;
                                &#125;else&#123;
                                    sb = numberLinkMaker&#40;sb , makePageLink&#40;parameters,i&#41; , i+1&#41;;
                                &#125;
                           &#125;
          
                     &#125;else&#123;
          
                     //Case 2 &#58; if lastPage => pagingWidth + 2
          
                        //First Page
                        if&#40; page == 0 &#41;&#123;
                              sb.append&#40;page+1&#41;.append&#40;""&#41;;
                        &#125;else&#123;
                              sb = numberLinkMaker&#40;sb , makePageLink&#40;parameters,0&#41; , 1&#41;;
                        &#125;
                        //if page in Region A
                        if &#40; 0 <= page & page <= pageA &#41;&#123;
                           for&#40; int i = 1 ; i <= pagingWidth ; i++ &#41;&#123;
          
                                if&#40; page == i &#41;&#123;
                                    sb.append&#40;page+1&#41;.append&#40;""&#41;;
                                &#125;else&#123;
                                    sb = numberLinkMaker&#40;sb , makePageLink&#40;parameters,i&#41; , i+1&#41;;
                                &#125;
          
                           &#125;
                           sb.append&#40;"..."&#41;;
          
                        //if page in Region B
                        &#125;else if &#40; pageA < page & page < pageC&#41;&#123;
          
                           sb.append&#40;"..."&#41;;
          
                           for &#40; int i = page - pagingWidth/2 ; i <= page + pagingWidth/2 ; i++ &#41;&#123;
          
                                if&#40; page == i &#41;&#123;
                                    sb.append&#40;page+1&#41;.append&#40;""&#41;;
                                &#125;else&#123;
                                    sb = numberLinkMaker&#40;sb , makePageLink&#40;parameters,i&#41; , i+1&#41;;
                                &#125;
          
                           &#125;
          
                           if&#40;page != pageC - 1&#41;sb.append&#40;"..."&#41;;
          
                        //if page in Region C
                        &#125;else if &#40; pageC <= page & page <= lastPage &#41;&#123;
          
                           sb.append&#40;"..."&#41;;
          
                           for&#40; int i = lastPage - pagingWidth ; i < lastPage ; i++ &#41;&#123;
          
                                if&#40; page == i &#41;&#123;
                                    sb.append&#40;page+1&#41;.append&#40;""&#41;;
                                &#125;else&#123;
                                    sb = numberLinkMaker&#40;sb , makePageLink&#40;parameters,i&#41; , i+1&#41;;
                                &#125;
          
                            &#125;
                        &#125;
          
                        //Last Page
                        if&#40; page == lastPage &#41;&#123;
                             sb.append&#40;page+1&#41;.append&#40;""&#41;;
                        &#125;else&#123;
                             sb = numberLinkMaker&#40;sb , makePageLink&#40;parameters,lastPage&#41; , lastPage + 1 &#41;;
                        &#125;
          
                     &#125;
          
                     if&#40;totalElements%pageSize == 0 & page == lastPage&#41;&#123;
                           //Do Nothing
                     &#125;else&#123;
                           if &#40;isNextPage&#40;&#41;&#41; &#123;
                                  sb.append&#40;"<a href=\"?"&#41;.append&#40;nextPageLink&#41;;
                                  sb.append&#40;"\"><font color=\"blue\"><B>&gt;&gt;&gt;</B></font></a>\n"&#41;;
                                  //sb.append&#40;"\"><img alt=\"Next\" src=\"../img/btn_next.gif\" border=\"0\"/></a>\n"&#41;;
                           &#125;
                     &#125;
                     
                     //Print out to jsp
                     pageContext.getOut&#40;&#41;.print&#40;sb.toString&#40;&#41;&#41;;
          
              &#125;
          
              public String makePageLink&#40;Map parameters, int pageNumber&#41;&#123;
                     parameters.put&#40;PAGE,""+pageNumber&#41;;
                     return LinkEncoder.encode&#40;parameters&#41;;
              &#125;
          
              public StringBuffer numberLinkMaker&#40;StringBuffer stringBuffer , String pageLink , int pageNumber&#41;&#123;
                     stringBuffer.append&#40;"<a href=\"?"&#41;.append&#40;pageLink&#41;;
                     stringBuffer.append&#40;"\"><font color=\"blue\"><B>"&#41;.append&#40;pageNumber&#41;.append&#40;"</B></font></a>\n"&#41;;
                     stringBuffer.append&#40;""&#41;;
                     return stringBuffer;
              &#125;
          
              public Map makePreviousPageParameters&#40;Map parameters&#41;&#123;
          
                     int previousPage;
                     previousPage = page-1;
                     //NumberFormatException
                     parameters.put&#40;PAGE,""+previousPage&#41;;
                     return parameters;
              &#125;
          
              public Map makeNextPageParameters&#40;Map parameters&#41;&#123;
          
                     int nextPage;
                     nextPage = page+1;
                     parameters.put&#40;PAGE,""+nextPage&#41;;
                     return parameters;
              &#125;
          
              public boolean isNextPage&#40;&#41; &#123;
                     return listSize > pageSize-1;
              &#125;
          
              public boolean isPreviousPage&#40;&#41; &#123;
                     return page > 0;
              &#125;
          
          &#125;
          SortingTag.java (minor change) ,
          Code:
          public class SortingTag extends MessageTag &#123;
          
              private Map parameters;
              private String sortColumn;
              private String sortColumnLink;
              private String ascending;
              public static final String PAGE = "s_page";
              public static final String SORT_COLUMN = "s_sortColumn";
              public static final String ASCENDING = "s_ascending";
              //private LinkEncoder UrlEncoder = new LinkEncoder&#40;&#41;;
              
              public void setSortColumn&#40;String sortColumn&#41;&#123;
                     this.sortColumn = sortColumn;
              &#125;
          
              public void writeMessage&#40;String msg&#41; throws IOException &#123;
          
                     initProperties&#40;&#41;;
          
                     try&#123;
                        	decorateMessage&#40;msg&#41;;
                     &#125;
                     catch&#40;IOException ex&#41; &#123;
                          ex.getMessage&#40;&#41;;
                     &#125;
          
          	&#125;
          
              public void initProperties&#40;&#41;&#123;
          
                     HttpServletRequest request = &#40;HttpServletRequest&#41; pageContext.getRequest&#40;&#41;;
                     this.parameters = RequestUtil.getRequestParameterMap&#40;request&#41;;
                     this.ascending = &#40;String&#41;parameters.get&#40;ASCENDING&#41;;
                     //this.sortColumnLink = UrlEncoder.encode&#40;makeSortColumnParameters&#40;parameters&#41;&#41;;
                     this.sortColumnLink = LinkEncoder.encode&#40;makeSortColumnParameters&#40;parameters&#41;&#41;;
              &#125;
              
              public void decorateMessage&#40;String msg&#41; throws IOException &#123;
          
                     StringBuffer sb = new StringBuffer&#40;&#41;;
          
                     sb.append&#40;"<a href=\"?"&#41;.append&#40;sortColumnLink&#41;;
                     sb.append&#40;"\"><font color=\"blue\"><B>"&#41;.append&#40;msg&#41;.append&#40;"</B></font></a>"&#41;;
          
                     pageContext.getOut&#40;&#41;.print&#40;sb.toString&#40;&#41;&#41;;
              &#125;
              
              public Map makeSortColumnParameters&#40;Map parameters&#41;&#123;
                     
                     int firstPage = 0;
                     // NumberFormatException
                     parameters.put&#40;PAGE,""+firstPage&#41;;
                     // Cannot change order of the following two line of codes , Differents Behaviour !!
                     String sortColumnFromRequest = &#40;String&#41;parameters.get&#40;SORT_COLUMN&#41;;
                     parameters.put&#40;SORT_COLUMN,sortColumn&#41;;
          
                     if &#40;sortColumn.equals&#40;sortColumnFromRequest&#41;&#41; &#123;
                          // Just to prevent NullPointerException &#40;NPE&#41;
                          if&#40;ascending == null || ascending.equals&#40;""&#41;&#41; ascending = "0";
                          // 1 is true , 0 is false
                          if&#40;ascending.equals&#40;"1"&#41;&#41;&#123;
                                  parameters.put&#40;ASCENDING,"0"&#41;;
                          &#125;else &#123;
                                  parameters.put&#40;ASCENDING,"1"&#41;;
                          &#125;
          
                     &#125;else&#123;
                          parameters.put&#40;ASCENDING,"1"&#41;;
                     &#125;
          
                     return parameters;
          
              &#125;
          
          &#125;
          ItemSearchForm.jsp (this search page is easy enough , but it is powerful to do any item related search , for example - search item by book's classMark)
          Code:
          <%@ page contentType="text/html;charset=UTF-8" %>
          <%@ include file="/WEB-INF/jsp/includeTop.jsp" %>
          
          <html>
          <head>
          	<title>Welcome to YourSchool's Library System</title>
          </head>
          
          <body>
          
          <div align="center">
          
             <form name="searchItemForm" method="post" action="<c&#58;url value='/admin/itemSearchForm.htm'/>"> 
          		<spring&#58;message code="search"/> &#58;
                  	<input type="hidden" name="s_page" value="0"/> 
                  	<input type="hidden" name="s_pageSize" value="15"/> 
                		<input type="hidden" name="s_sortColumn" value="barcode"/> 
                		<input type="hidden" name="s_ascending" value="1"/>
          <table width="70%"  border="0">
            <tr>
              <td>barcode&#58;</td>
              <td><input type="text" size="40" name="item.barcode"/></td>
            </tr>
            <tr>
              <td>shelfmark&#58;</td>
              <td><input type="text" size="40" name="item.shelfMark"/></td>
            </tr>
            <tr>
              <td>book title&#58;</td>
              <td><input type="text" size="40" name="item.book.title"/></td>
            </tr>
            <tr>
              <td>classMark&#58;</td>
              <td><input type="text" size="40" name="item.book.classMark"/></td>
            </tr>
            <tr>
              <td></td>
              <td></td>
            </tr>
          </table>
          
          		<input type="button" onclick="javascript&#58;document.searchItemForm.submit&#40;&#41;" value='<spring&#58;message code="search"/>'/>
          
          		<c&#58;if test="$&#123;!empty itemCommand&#125;" >						
          			<spring&#58;bind path="itemCommand.*">
          				<c&#58;forEach var="error" items="$&#123;status.errorMessages&#125;">
          					<b><font color=red>
          							<BR><c&#58;out value="$&#123;error&#125;"/>
          						</font>
          					</b>
            				</c&#58;forEach>
          			</spring&#58;bind>
          		</c&#58;if>
            </form>
          	
          </div>
          
          </body>
          
          </html>
          item.result.jsp ,
          Code:
          <!-- display search results -->
          		
          	<c&#58;if test="$&#123;!empty Items&#125;" >
          		<br>
          		<b><spring&#58;message code="search.result"/></b>&#58;<br><br>
          		<simple&#58;google modelName="Items" pagingWidth="5"/>
          			<table border="1">
          				<tr>
          					<th width="10%"><spring&#58;message code="serial.no"/></th>
          					<th width="10%"><spring&#58;message code="version"/></th>
          					<th width="10%"><simple&#58;sorting code="system.id" sortColumn="id"/></th>
          					<th width="55%"><simple&#58;sorting code="item.barcode" sortColumn="barcode"/></th>
          					<th width="15%"><spring&#58;message code="action"/></th>
          				</tr>
          				<c&#58;forEach var="item" items="$&#123;Items._resultset&#125;" varStatus="status">
          				<tr>
          					<td><c&#58;out value="$&#123;status.count + param&#91;'s_page'&#93;*param&#91;'s_pageSize'&#93;&#125;"/></td>
          					<td><c&#58;out value="$&#123;item.version&#125;"/></th>
          					<td><c&#58;out value="$&#123;item.id&#125;"/></td>
          					<td><c&#58;out value="$&#123;item.barcode&#125;" escapeXml='false'/></td>
          					<td><a href='<c&#58;url value="/admin/itemEditForm.htm"/>?<simple&#58;sortlinkg idValue="$&#123;item.id&#125;"/>'>
          								<spring&#58;message code="edit"/></a>|
          							  <a href='<c&#58;url value="/admin/itemDeleteAfterSearch.htm"/>?<simple&#58;sortlinkg idValue="$&#123;item.id&#125;"/>'> 
          								<spring&#58;message code="delete"/></a>
          					</td>
          				</tr>
          				</c&#58;forEach>
          			</table>
          			<br>
          	</c&#58;if>
          almost the same for other related classes .

          Remark :

          1. as usual , fast code.

          2. l used to do the items search by using ,
          Code:
          	Collection findItemsByShelfMark&#40;String shelfMark&#41;;
          	Collection findItemsByLastCheckin&#40;Date lastcheckin&#41;;
          	Collection findItemsByTitle&#40;String title&#41;;
          	Collection findItemsByClassMark&#40;String classMark&#41;;
          	Collection findItemsByIsbn&#40;String isbn&#41;;
          	Collection findItemsByItemDuration&#40;String itemduration&#41;;
          	Collection findItemsByItemStatus&#40;String itemstatus&#41;;
          	Collection findItemsByItemType&#40;String itemtype&#41;;
          	Collection findItemsByLocation&#40;String location&#41;;
          now no more.

          3. for hibernate dynamic query , we can refer to

          (a) "hibernate in action"(HIA) pg 276-279 , the last example even more powerful --->
          " we can combine User properties and Item properties in the same search:" quoted from HIA.

          (b) Hibernate Criteria API: Multi-Criteria Search Made Easy from devx . http://www.devx.com/Java/Article/28754

          4. Some extra codes above are use to block "direct url writing the paging link" , just to make the paging more stable.

          5. All codes above done in Hibernate 3.1 and spring 1.2.3

          6. All parameters use to do paging have been changed to s_xxx , with prefix "s_" , to avoid conflict with other request parameters , for example , SWF or Spring use prefix "_xxx" very often.

          7. it seem that we have to make a lot of commands if we use this paging pattern. (ItemCommand , BookCommand , ...etc ..)
          Question : any other better way ?

          8. performance not tested.

          9. Reminder : have to set a StringTrimmerEditor("xxx",true) to make it work correctly.
          Code:
          	protected void initBinder&#40;HttpServletRequest request,
          			ServletRequestDataBinder binder&#41; &#123;
          ...
          		binder.registerCustomEditor&#40;String.class, null,
          				new StringTrimmerEditor&#40;"\r\n\f", true&#41;&#41;;
          
          ...
          	&#125;
          of course , set it to be false still working , but may be not what you want.You can check the output sql query string from hibernate(hibernate.show_sql=true).

          l really love simple thing ... , hibernate dynamic query is simple.

          moon

          Comment


          • #20
            How to do paging in domain object model ?

            l have a problem when l try to do paging in domain object model.

            We cannot avoid 'Object-Relational(O/R) Impedance mismatch' if we persist our data in relational database and code in OO, so we can alway ask a question for pagination too :

            If we do paging , we do it in object oriented(OO) or relational(R) side ?

            Review the codes we wrote before, we can find two keywords frequently , for example , in hibernate - "setFirstResult","setMaxResults" . So , with these two keywords , which sides we are when doing pagination ? we realised suddenly that we are alway in R side , because those words are from SQL language.

            Let's consider an example.

            Assume that l have three tables , their relationships are ,

            AUTHORS <--M:M--> BOOKS <-- M:1 --> PUBLISHERS

            Book.java
            Code:
            public class Book implements java.io.Serializable {
            
            	private Long id;
            	private Long version;
            	private String title;
            	private Integer publishingYear;
            	private String isbn;
            	private String edition;
            	private String description;
            	private String publicationPlace;
            	private String classMark;
            	private String attachment;
            
            	private Set authors = new HashSet();
            .....
            	private Publisher publisher;
            .....
            there is a requirement from the client - when search books by criteria , book's detail have to display like

            title | authors | publisher | isbn | publishingYear | ..

            ( search using any keyword in http://webpac.lib.nthu.edu.tw/Webpac2/msearch.dll/ to get an idea. )

            so my search page is assume to be ,
            Code:
            <%@ page contentType="text/html;charset=UTF-8" %>
            <%@ include file="/WEB-INF/jsp/includeTop.jsp" %>
            
            <html>
            <head>
            	<title>Your's Library Automation System</title>
            	<link rel="stylesheet" href="<c:url value='/css/main.css'/>" type="text/css" />
            </head>
            
            <body>
            
            <div align="center">
            
            <!-- Header -->
            <table border=0 cellSpacing=0 cellPadding=5 width="100%">
            	<tbody>
              		<tr>
              		  <td width="18%" class="logo">JLibrary</td>
              		  <td width="82%" align="center" valign="baseline" class="header"><spring:message code="book.search"/></td>
                  </tr>
            	</tbody>
            </table>
            
            <form name="searchBookForm" method="post" action="<c:url value='/searchBook.htm'/>"> 
            	<spring:message code="search"/> :
            	
            <p></p>
            
                    <input type="hidden" name="s_page" value="0"/> 
                    <input type="hidden" name="s_pageSize" value="3"/> 
                  	<input type="hidden" name="s_sortColumn" value="title"/> 
                  	<input type="hidden" name="s_ascending" value="1"/>
            <table width="70%"  border="0">
              <tr>
                <td><spring:message code="book.title"/>:</td>
                <td><input type="text" size="60" name="book.title"/></td>
              </tr>
              <tr>
                <td><spring:message code="book.isbn"/>:</td>
                <td><input type="text" size="30" name="book.isbn"/></td>
              </tr>
              <tr>
                <td><spring:message code="publisher"/>:</td>
                <td><input type="text" size="30" name="book.publisher.publisherName"/></td>
              </tr>
               <tr>
                <td><spring:message code="author"/>:</td>
                <td><input type="text" size="30" name="author.authorName"/></td>
              </tr>
              <tr>
                <td>&nbsp;</td>
                <td>&nbsp;</td>
              </tr>
            </table>
            
            <p></p>
            
            <table width="70%"  border="0">
              <tr>
                <td align="right"><input type="button" onclick="javascript:document.searchBookForm.submit()" value='<spring:message code="search"/>'/></td>
              </tr>
            </table>
            
              </form>
            	
            </div>
            
            </body>
            
            </html>
            and results page is,
            Code:
            <%@ page contentType="text/html;charset=UTF-8" %>
            <%@ include file="/WEB-INF/jsp/includeTop.jsp" %>
            
            <html>
            <head>
            	<title>Your's Library Automation System</title>
            	<link rel="stylesheet" href="<c:url value='/css/main.css'/>" type="text/css" />
            </head>
            
            <body>
            
            <div align="center">
            
            <!-- Header -->
            <table border=0 cellSpacing=0 cellPadding=5 width="100%">
            	<tbody>
              		<tr>
              		  <td width="18%" class="logo">JLibrary</td>
              		  <td width="82%" align="center" valign="baseline" class="header"><spring:message code="book.search"/></td>
                  </tr>
            	</tbody>
            </table>
            
            <!-- display constraint violation messages -->
            
            	<c:if test="${!empty constraint_violation}" >
            		<spring:message text="${constraint_violation}"/>
            		<c:remove var="constraint_violation"/>
            	<br>
            	</c:if>
            
            <!-- display no book found messgae -->
            	
            	<c:if test="${!empty NoBookFound}" >
            	<br>
            		<fmt:message key="book.not.found"/>
            	</c:if>
            
            <!-- display search results -->
            		
            	<c:if test="${!empty Books}" >
            		<br>
            		<b><spring:message code="search.result"/></b>:<br><br>
            		
            		<table width="70%" class="paging" cellspacing="1" cellpadding="2">
              			<tr>
                			<td class="google"><simple:totalpaging modelName="Books"/></td>
              			</tr>
            		</table>
            		
            			<table width="100%" class="paging" cellspacing="1" cellpadding="2">
            				<tr>
            					<th width="5%"><spring:message code="serial.no"/></th>
            					<th width="40%"><spring:message code="book.title"/></th>
            					<th width="20%"><spring:message code="author"/></th>
            					<th width="15%"><spring:message code="publisher"/></th>
            					<th width="10%"><spring:message code="book.isbn"/></th>
            					<th width="10%"><spring:message code="book.publishingYear"/></th>
            				</tr>
            				<c:forEach var="book" items="${Books._resultset}" varStatus="status">
            				<tr>
            					<td><c:out value="${status.count + param['s_page']*param['s_pageSize']}"/></td>
            					<td id="left"><c:out value="${book.title}" escapeXml='false'/></td>
            					<td id="left">
            						<c:forEach var="author" items="${book.authors}" varStatus="status">
            							<c:out value="${author.authorName}" escapeXml='false'/>,
            						</c:forEach>
            					</td>
            					<td id="left"><c:out value="${book.publisher.publisherName}" escapeXml='false'/></td>
            					<td><c:out value="${book.isbn}" escapeXml='false'/></td>
            					<td><c:out value="${book.publishingYear}" escapeXml='false'/></td>
            				</tr>
            				</c:forEach>
            			</table>
            			<br>
            	</c:if>
            	
            </div>
            
            </body>
            </html>
            now the problem --> how can l display the book results with authors and publisher fetching eagerly with pageSize = 3 (or any # ) . We are doing pagination for a domain object's (Book) collections now , not a pagination for the book rows that in database ! [we usually do it in R , remember ?]

            either we use inner or outer join to get the book collections, we might get a result of 1 book or 2 books instead of 3 books for each pages , because of the join needed to perform the non-lazy loading !

            yes , you can get the results of the search too , but not 3 books each pages , but < 3 books each pages -- this is not what we want ! what we want is - 3 books each pages .

            How to do paging in hibernate (or more general , domain object model ) ?

            moon
            Last edited by yfmoan; Feb 17th, 2006, 01:31 PM.

            Comment


            • #21
              hihi ... l have a funny solution ,

              my DAO - HiberBookDao.java
              Code:
              ..
              	public Map findBooksByCriteriaWithTotal(BookCommand bookCommand)
              			throws DataAccessException {
              		
              		ArrayList books = (ArrayList) findBooksByCriteriaWithLimit(bookCommand);
              		Integer totalFound = findBooksTotalByCriteria(bookCommand);
              
              		Map model = new HashMap();
              		model.put("_totalElements", totalFound);
              		model.put("_resultset", books);
              
              		return model;
              	}
              
              	private BookCommand makeMCommand(BookCommand source){
              		
              		int m = (source.getS_page() == 0)? 0 : source.getS_page()-1;
              		BookCommand target = new BookCommand();
              		BeanUtils.copyProperties(source,target);
              		target.setS_page(m);
              		return target;
              	}
              	
              	public Collection findBooksByCriteriaWithLimit(BookCommand bookCommand) 
              			throws DataAccessException {
              
              		final int page = bookCommand.getS_page();
              		final BookCommand nbookCommand = bookCommand;
              		final BookCommand mbookCommand = makeMCommand(bookCommand);
              		final Book book = bookCommand.getBook();
              		final Author iAuthor = bookCommand.getAuthor();
              		final Publisher iPublisher = book.getPublisher();
              
              		return getHibernateTemplate().executeFind(
              				new HibernateCallback() {
              					public Object doInHibernate(Session session)
              							throws HibernateException, SQLException {
              						
              						StringBuffer queryString = new StringBuffer();
              						boolean conditionFound = false;
              						String title = book.getTitle();
              						String isbn = book.getIsbn();
              						String authorName = iAuthor.getAuthorName();
              						String publisherName = iPublisher.getPublisherName();
              						
              						if(title != null){
              							queryString.append("lower(b.title) like :title ");
              							conditionFound=true;
              						}
              						if(isbn != null){
              							if (conditionFound) queryString.append("and ");
              							queryString.append("lower(b.isbn) like :isbn ");
              							conditionFound=true;
              						}
              						if (authorName != null) {
              							if (conditionFound) queryString.append("and ");
              							queryString.append("lower(a.authorName) like :authorName ");
              							conditionFound=true;
              						}
              						if (publisherName != null) {
              							if (conditionFound) queryString.append("and ");
              							queryString.append("lower(p.publisherName) like :publisherName ");
              							conditionFound=true;
              						}
              						
              						String fromClause = conditionFound ?
              								"from Book b " +
              								"left join fetch b.authors a " +
              								"left join fetch b.publisher p where " 
              								: 
              								"from Book b " +
              								"left join fetch b.authors a " +
              								"left join fetch b.publisher p ";
              						
              						queryString.insert(0, fromClause).append("order by b.title");
              						
              						Query query = getSession().createQuery( queryString.toString() );
              						
              						if (title != null)
              							query.setString( "title",'%' + title.toLowerCase() + '%' );
              						if (isbn != null)
              							query.setString( "isbn",'%' + isbn.toLowerCase() + '%' );
              						if (authorName != null)
              							query.setString( "authorName",'%' + authorName.toLowerCase() + '%' );
              						if (publisherName != null)
              							query.setString( "publisherName",'%' + publisherName.toLowerCase() + '%' );
              						
              						if(page == 0){
              							query.setFirstResult(0)
              							 	 .setMaxResults(pageNodeByCriteria(nbookCommand).intValue());
              						}else{
              							query.setFirstResult(pageNodeByCriteria(mbookCommand).intValue())
              							 	 .setMaxResults(pageNodeByCriteria(nbookCommand).intValue()
              									 		- pageNodeByCriteria(mbookCommand).intValue());
              						}
              						
              						Set distinctResults = new HashSet(query.list());
              						List result = new ArrayList(distinctResults);
              						Collections.sort(result,new BookNameComparator());
              
              						return result;
              					}
              			});
              
              	}
              
              	public Integer pageNodeByCriteria(BookCommand bookCommand)
              			throws DataAccessException {
              		
              		final Book book = bookCommand.getBook();
              		final Author iAuthor = bookCommand.getAuthor();
              		final Publisher iPublisher = book.getPublisher();
              		final int page = bookCommand.getS_page();
              		final int pageSize = bookCommand.getS_pageSize();
              		
              		return (Integer) getHibernateTemplate().execute(
              				new HibernateCallback() {
              					public Object doInHibernate(Session session)
              							throws HibernateException, SQLException {
              
              						StringBuffer queryString = new StringBuffer();
              						boolean conditionFound = false;
              						String title = book.getTitle();
              						String isbn = book.getIsbn();
              						String authorName = iAuthor.getAuthorName();
              						String publisherName = iPublisher.getPublisherName();
              						
              						if(title != null){
              							queryString.append("lower(b.title) like :title ");
              							conditionFound=true;
              						}
              						if(isbn != null){
              							if (conditionFound) queryString.append("and ");
              							queryString.append("lower(b.isbn) like :isbn ");
              							conditionFound=true;
              						}
              						if (authorName != null) {
              							if (conditionFound) queryString.append("and ");
              							queryString.append("lower(a.authorName) like :authorName ");
              							conditionFound=true;
              						}
              						if (publisherName != null) {
              							if (conditionFound) queryString.append("and ");
              							queryString.append("lower(p.publisherName) like :publisherName ");
              							conditionFound=true;
              						}
              						
              						String fromClause = conditionFound ?
              								"select count(*) from Book b " +
              								"left join b.authors a " +
              								"left join b.publisher p where " 
              								: 
              								"select count(*) from Book b " +
              								"left join b.authors a " +
              								"left join b.publisher p ";
              						
              						queryString.insert(0, fromClause).append("group by b.id order by b.title");
              						
              						Query query = getSession().createQuery( queryString.toString() );
              						
              						if (title != null)
              							query.setString( "title",'%' + title.toLowerCase() + '%' );
              						if (isbn != null)
              							query.setString( "isbn",'%' + isbn.toLowerCase() + '%' );
              						if (authorName != null)
              							query.setString( "authorName",'%' + authorName.toLowerCase() + '%' );
              						if (publisherName != null)
              							query.setString( "publisherName",'%' + publisherName.toLowerCase() + '%' );
              						
              						Iterator iter = query.setFirstResult(0)
              							 				 .setMaxResults((page+1) * pageSize)
              							 				 .list()
              							 				 .iterator();
              						
              						int sum = 0;
              						while ( iter.hasNext() ) {
              							Integer count = (Integer) iter.next();
              							sum = sum + count.intValue();
              						}
              						
              						return new Integer(sum);				
              						
              			}
              		});
              		
              	}
              	
              	public Integer findBooksTotalByCriteria(BookCommand bookCommand)
              			throws DataAccessException {
              		
              		final Book book = bookCommand.getBook();
              		final Author iAuthor = bookCommand.getAuthor();
              		final Publisher iPublisher = book.getPublisher();
              
              		return (Integer) getHibernateTemplate().execute(
              				new HibernateCallback() {
              					public Object doInHibernate(Session session)
              							throws HibernateException, SQLException {
              
              						StringBuffer queryString = new StringBuffer();
              						boolean conditionFound = false;
              						String title = book.getTitle();
              						String isbn = book.getIsbn();
              						String authorName = iAuthor.getAuthorName();
              						String publisherName = iPublisher.getPublisherName();
              						
              						if(title != null){
              							queryString.append("lower(b.title) like :title ");
              							conditionFound=true;
              						}
              						if(isbn != null){
              							if (conditionFound) queryString.append("and ");
              							queryString.append("lower(b.isbn) like :isbn ");
              							conditionFound=true;
              						}
              						if (authorName != null) {
              							if (conditionFound) queryString.append("and ");
              							queryString.append("lower(a.authorName) like :authorName ");
              							conditionFound=true;
              						}
              						if (publisherName != null) {
              							if (conditionFound) queryString.append("and ");
              							queryString.append("lower(p.publisherName) like :publisherName ");
              							conditionFound=true;
              						}
              						
              						String fromClause = conditionFound ?
              								"select count(distinct b.id) from Book b " +
              								"left join b.authors a " +
              								"left join b.publisher p where " 
              								: 
              								"select count(distinct b.id) from Book b " +
              								"left join b.authors a " +
              								"left join b.publisher p ";
              						
              						queryString.insert(0, fromClause);
              						
              						Query query = getSession().createQuery( queryString.toString() );
              						
              						if (title != null)
              							query.setString( "title",'%' + title.toLowerCase() + '%' );
              						if (isbn != null)
              							query.setString( "isbn",'%' + isbn.toLowerCase() + '%' );
              						if (authorName != null)
              							query.setString( "authorName",'%' + authorName.toLowerCase() + '%' );
              						if (publisherName != null)
              							query.setString( "publisherName",'%' + publisherName.toLowerCase() + '%' );
              						
              						return (Integer)query.uniqueResult();				
              						
              			}
              		});
              		
              	}
              to be continue...

              Comment


              • #22
                BookCommand.java
                Code:
                package org.yourschool.library.domain.command;
                
                import org.yourschool.library.domain.Author;
                import org.yourschool.library.domain.Book;
                import org.yourschool.library.domain.Note;
                import org.yourschool.library.domain.OtherTitle;
                import org.yourschool.library.domain.Publisher;
                import org.yourschool.library.domain.Series;
                import org.yourschool.library.domain.Subject;
                
                public class BookCommand extends BaseCommand {
                
                	private Book book;
                	private Author author;
                	private OtherTitle otherTitle;
                	private Series series;	
                	private Subject subject;
                
                
                	public BookCommand() {
                		
                		this.book = new Book();
                		book.setNote(new Note());
                		book.setPublisher(new Publisher());
                		
                		this.author = new Author();
                		this.otherTitle = new OtherTitle();
                		this.series = new Series();
                		this.subject = new Subject();
                		
                	}
                
                
                	public Author getAuthor() {
                		return author;
                	}
                
                
                	public Book getBook() {
                		return book;
                	}
                
                
                	public OtherTitle getOtherTitle() {
                		return otherTitle;
                	}
                
                
                	public Series getSeries() {
                		return series;
                	}
                
                
                	public Subject getSubject() {
                		return subject;
                	}
                
                	
                	
                }
                TotalPagingTag.java ,

                Code:
                package org.simplePage.web.tags;
                
                import java.util.Map;
                import java.util.List;
                import java.io.IOException;
                import javax.servlet.http.HttpServletRequest;
                import javax.servlet.jsp.tagext.BodyTagSupport;
                import javax.servlet.jsp.JspException;
                import org.simplePage.web.tags.support.LinkEncoder;
                import org.simplePage.web.util.RequestUtil;
                
                public class TotalPagingTag extends BodyTagSupport {
                
                    private Map parameters;
                    private String modelName ;
                    private int listSize;
                    private int pageSize;
                    private int page;
                    private int totalElements;
                    private String previousPageLink;
                    private String nextPageLink;
                    public static final String PAGE = "s_page";
                    public static final String PAGE_SIZE = "s_pageSize";
                    //private LinkEncoder UrlEncoder = new LinkEncoder();
                    
                    public void setModelName(String modelName){
                        this.modelName = modelName;
                    }
                
                    public int doStartTag() throws JspException {
                                                                	
                           initProperties();
                
                           if(pageSize > 0){
                                try{
                              	    writePaging();
                                }catch(IOException ex) {
                                    ex.getMessage();
                                }
                           }
                
                           return SKIP_BODY;
                    }
                
                    public int doEndTag() throws JspException {
                
                           return EVAL_PAGE;
                    }
                
                    public void initProperties(){
                
                           HttpServletRequest request = (HttpServletRequest) pageContext.getRequest();
                           this.parameters = RequestUtil.getRequestParameterMap(request);
                    
                           String Page = (String)parameters.get(PAGE);
                
                           if (Page == null || Page.equals("")){
                                 this.page = 0;
                           }else{
                                 this.page = Integer.parseInt(Page);
                           }
                
                           String PageSize = (String)parameters.get(PAGE_SIZE);
                
                           if (PageSize == null || PageSize.equals("")){
                                 this.pageSize = 0;
                           }else{
                                 this.pageSize = Integer.parseInt(PageSize);
                           }
                
                           this.listSize = ((List)((Map)request.getAttribute(modelName)).get("_resultset")).size();
                           this.totalElements =  ((Integer)((Map)request.getAttribute(modelName)).get("_totalElements")).intValue();
                
                           this.previousPageLink = LinkEncoder.encode(makePreviousPageParameters(parameters));
                           this.nextPageLink = LinkEncoder.encode(makeNextPageParameters(parameters));
                
                    }
                
                    public void writePaging() throws IOException {
                
                           StringBuffer sb = new StringBuffer();
                
                           //Display total number
                           sb.append("|").append(totalElements).append("|&nbsp;.......");
                           
                           if (isPreviousPage()) {
                                        sb.append("<a href=\"?").append(previousPageLink);
                                        sb.append("\"><font color=\"blue\"><B>&lt;&lt;&lt;</B></font></a>\n");
                           }
                                        sb.append("&nbsp;");
                           if (isNextPage()) {
                                        sb.append("<a href=\"?").append(nextPageLink);
                                        sb.append("\"><font color=\"blue\"><B>&gt;&gt;&gt;</B></font></a>\n");
                           }
                
                           //Print out to jsp
                           pageContext.getOut().print(sb.toString());
                
                    }
                
                    public Map makePreviousPageParameters(Map parameters){
                
                           int previousPage;
                           previousPage = page-1;
                           //NumberFormatException
                           parameters.put(PAGE,""+previousPage);
                           return parameters;
                    }
                
                    public Map makeNextPageParameters(Map parameters){
                
                           int nextPage;
                           nextPage = page+1;
                           parameters.put(PAGE,""+nextPage);
                           return parameters;
                    }
                
                    public boolean isNextPage() {
                           return listSize > pageSize-1;
                    }
                
                    public boolean isPreviousPage() {
                           return page > 0;
                    }
                
                }
                moon

                Comment


                • #23
                  l just found a thread form the hibernate forum "*weep* solving paginated non-distinct eager fetch"
                  http://forum.hibernate.org/viewtopic.php?t=936589 ,

                  the recommendation from the hibernate developer michael said that :

                  the only advice I can give you is dont use eager fetching when doing pagination.
                  .....

                  moon

                  Comment


                  • #24
                    ids and records ==&gt; method invoking table model

                    Originally posted by croco
                    This is just a specific implementation of the TableModel, targeted at browsing through large tabular data sets. Of course you can provide your own TableModel implementation that is more suitable in other cases.
                    ---

                    A natural extension of this approach is a generic implementation of the table model that is based not necessarily on SQL, but has as configurable properties a bean and method for getting the id's and a method for getting the records with those id's - let's say, MethodInvokingTableModel.

                    The advantage is that then you can use Hibernate instead of SQL, with potential more stuff like fetching nested objects .

                    ---

                    Other good upgrades starting from these models are to have optional search filters, which works both with the JDBC and Hibernate model, that gives a lot of flexibility too and adds for faster development.

                    Comment

                    Working...
                    X