Page 2 of 3 FirstFirst 123 LastLast
Results 11 to 20 of 24

Thread: Pageable data list with Hibernate

  1. #11
    Join Date
    Sep 2004
    Posts
    133

    Default

    Hehe ... , l do have a very simple QUICK and DIRTY way to do paging ... please don't laugh if l did something wrong ...

    There are three class only : PagingTag.java , LinkEncoder.java (borrowed from ValueList) , RequestUtil.java (borrowed from ValueList).

    PagingTag.java:
    Code:
    package org.simplePage.tags;
    
    import java.util.Map;
    import java.util.List;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.jsp.tagext.BodyTagSupport;
    import javax.servlet.jsp.JspException;
    import org.simplePage.tags.support.LinkEncoder;
    import org.simplePage.web.RequestUtil;
    
    public class PagingTag extends BodyTagSupport {
    
        private String listName ;
        private int listSize;
        private int pageSize;
        private int page;
        private String previousPageLink;
        private String nextPageLink;
        public static final String PAGE = "page";
        public static final String PAGE_SIZE = "pageSize";
    
        
        public void setlistName(String listName){
               this.listName = listName;
        }
    
        public int doStartTag() throws JspException {
    
               HttpServletRequest request = (HttpServletRequest) pageContext.getRequest();
               Map parameters = RequestUtil.getRequestParameterMap(request);
               LinkEncoder UrlEncoder = new LinkEncoder();
    
               String Page = (String)parameters.get(PAGE);
               this.page = Integer.parseInt(Page);
    
               String PageSize = (String)parameters.get(PAGE_SIZE);
               this.pageSize = Integer.parseInt(PageSize);
               
               this.listSize = ((List)request.getAttribute(listName)).size();
    
               this.previousPageLink = UrlEncoder.encode(makePreviousPageParameters(parameters));
               this.nextPageLink = UrlEncoder.encode(makeNextPageParameters(parameters));
    
               StringBuffer sb = new StringBuffer();
               
               sb.append&#40;"\n<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\">\n"&#41;;
               sb.append&#40;"  <tr>\n"&#41;;
               sb.append&#40;"     <td align=\"left\" nowrap=\"true\">\n"&#41;;
               sb.append&#40;"     </td>\n"&#41;;
               sb.append&#40;"     <td align=\"right\">\n"&#41;;
               sb.append&#40;"        <table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" >\n"&#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><< Prev</B></font></a>\n"&#41;;
               &#125;
                            sb.append&#40;""&#41;;
               if &#40;isNextPage&#40;&#41;&#41; &#123;
                            sb.append&#40;"<a href=\"?"&#41;.append&#40;nextPageLink&#41;;
                            sb.append&#40;"\"><font color=\"blue\"><B>Next &gt;&gt;</B></font></a>\n"&#41;;
               &#125;
               sb.append&#40;"        </table>\n"&#41;;
               sb.append&#40;"     </td>\n"&#41;;
               sb.append&#40;"   </tr>\n"&#41;;
               sb.append&#40;" </table>\n"&#41;;
               
               try &#123;
                   pageContext.getOut&#40;&#41;.print&#40;sb.toString&#40;&#41;&#41;;
               &#125;catch &#40;Exception ex&#41; &#123;
                    System.out.println&#40;"-------- Hello Error !! -------&#58;" + ex.toString&#40;&#41;&#41;;
               &#125;
    
               return SKIP_BODY;
        &#125;
    
        public int doEndTag&#40;&#41; throws JspException &#123;
    
               return EVAL_PAGE;
        &#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;
    LinkEncoder.java:
    Code:
    package org.simplePage.tags.support;
    
    import java.io.UnsupportedEncodingException;
    import java.net.URLEncoder;
    import java.util.Iterator;
    import java.util.Map;
    
    public class LinkEncoder &#123;
    
            private String encoding = "UTF-8";
        
        
    	public String getEncoding&#40;&#41;
    	&#123;
    		return encoding;
    	&#125;
    
    	public void setEncoding&#40;String encoding&#41;
    	&#123;
    		this.encoding = encoding;
    	&#125;
    
    	public String encode&#40;Map parameters&#41;
    	&#123;
    		StringBuffer sb = new StringBuffer&#40;&#41;;
    
    		try
    		&#123;
    			for &#40;Iterator iter = parameters.keySet&#40;&#41;.iterator&#40;&#41;; iter.hasNext&#40;&#41;;&#41;
    			&#123;
    				String key = &#40;String&#41; iter.next&#40;&#41;;
    
    				Object value = parameters.get&#40;key&#41;;
    				if &#40;value instanceof String&#91;&#93;&#41;
    				&#123;
    					String&#91;&#93; values = &#40;String&#91;&#93;&#41; value;
    					for &#40;int i = 0; i < values.length; i++&#41;
    					&#123;
    						sb.append&#40;key&#41;.append&#40;"="&#41;.append&#40;URLEncoder.encode&#40;values&#91;i&#93;, encoding&#41;&#41;.append&#40;"&amp;"&#41;;
    					&#125;
    				&#125;
    				else if &#40;value instanceof String&#41;
    				&#123;
    					sb.append&#40;key&#41;.append&#40;"="&#41;.append&#40;URLEncoder.encode&#40;&#40;String&#41; value, encoding&#41;&#41;.append&#40;"&amp;"&#41;;
    				&#125;
    				else if &#40;value != null&#41;
    				&#123;
    					sb.append&#40;key&#41;.append&#40;"="&#41;.append&#40;URLEncoder.encode&#40;value.toString&#40;&#41;, encoding&#41;&#41;.append&#40;"&amp;"&#41;;
    				&#125;
    
    			&#125;
    		&#125;
    		catch &#40;UnsupportedEncodingException e&#41;
    		&#123;
    			// why no need to declare ?
    			throw new RuntimeException&#40;e&#41;;
    		&#125;
    		return sb.toString&#40;&#41;;
    	&#125;
    
    &#125;
    RequestUtil.java
    Code:
    package org.simplePage.web;
    
    import java.util.Enumeration;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.StringTokenizer;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.jsp.PageContext;
    
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    
    public final class RequestUtil &#123;
    
       /** Commons Logger */
       public static final Log LOGGER = LogFactory.getFactory&#40;&#41;.getInstance&#40;RequestUtil.class&#41;;
    
       /** Protect singleton */
       private RequestUtil&#40;&#41;
       &#123;
       	
       &#125;
    
       public static Map getRequestParameterMap&#40;HttpServletRequest request&#41;
       &#123;
          return getRequestParameterMap&#40;request, ""&#41;;
       &#125;
    
       public static Map getRequestParameterMap&#40;HttpServletRequest request, String id&#41;
       &#123;
          int lenghtOfId = &#40;id == null&#41; ? 0 &#58; id.length&#40;&#41;;
    
          Map parameters = new HashMap&#40;request.getParameterMap&#40;&#41;.size&#40;&#41;&#41;;
          for &#40;Enumeration keys = request.getParameterNames&#40;&#41;; keys.hasMoreElements&#40;&#41;;&#41;
          &#123;
             String key = &#40;String&#41; keys.nextElement&#40;&#41;;
             String&#91;&#93; values = request.getParameterValues&#40;key&#41;;
             Object value = &#40;&#40;values == null&#41; ? null &#58; &#40;values.length == 1 ? &#40;Object&#41; values&#91;0&#93; &#58; &#40;Object&#41; values&#41;&#41;;
    
             if &#40;lenghtOfId > 0&#41;
             &#123;
                if &#40;key.endsWith&#40;id&#41;&#41;
                &#123;
                   parameters.put&#40;key.substring&#40;0, key.length&#40;&#41; - lenghtOfId&#41;, value&#41;;
                &#125;
             &#125;
             else
             &#123;
                parameters.put&#40;key, value&#41;;
             &#125;
    
          &#125;
          return parameters;
       &#125;
    
    &#125;
    my includeTop.jsp for every pages

    Code:
    <%@ page contentType="text/html;charset=UTF-8" %>
    <%@ taglib uri="http&#58;//www.simplePage.org" prefix="simple" %>
    my web.xml
    Code:
    ...
            <taglib>
                    <taglib-uri>http&#58;//www.simplePage.org</taglib-uri>
                    <taglib-location>/WEB-INF/pagingtag.tld</taglib-location>
            </taglib>
    ...
    pagingtag.tld ,
    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" 
      "http&#58;//java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
    
    
    <taglib>
    	<tlib-version>0.1</tlib-version>
        	<jsp-version>1.2</jsp-version>
        	<short-name>paging</short-name>
        	<uri>http&#58;//www.simplePage.org</uri>
        	<discription>A Simple Paging Tag</discription>
        	<tag>
            	<name>paging</name>
            	<tag-class>org.simplePage.tags.PagingTag</tag-class>
            	<body-content>JSP</body-content>
            	<display-name>table</display-name>
    		<attribute>
    			<name>listName</name>
    			<required>true</required>
    			<rtexprvalue>true</rtexprvalue>
    		</attribute>
        	</tag>
    </taglib>
    l have this code snippet in my jsp ,

    Code:
    	
    ...
      <FORM action="<c&#58;url value="/admin/SubjectSearch.UD.htm"/>" method="POST" >
    <!--**** for first time injection for page and pageSize *****-->
      <input type="hidden" name="page" value="0"/>
      <input type="hidden" name="pageSize" value="10"/>
    ....
    <c&#58;if test="$&#123;!empty model_name_subjects&#125;" >
    
      <!--******** Here is my simple paging tag *********-->
    	<simple&#58;paging listName="model_name_subjects"/>
      <!--******** No DisplayTag or ValueList here , just simple jstl tag for display , easy for changes and controls , make NO change to your controller implementation , ALL simple .. &#58;&#41; *********-->
    	
    		<table>
    		
    			<tr>
    				<th width="10%"><fmt&#58;message key="subject.id"/></th>
    				<th width="60%"><fmt&#58;message key="subject.name"/></th>
    				<th width="15%">Edit</th>
    				<th width="15%">Delete</th>
    			</tr>
    
    			<c&#58;forEach var="subject" items="$&#123;model_name_subjects&#125;">
    				<tr>
    					<td><c&#58;out value="$&#123;subject.id&#125;"/></td>
    					<td><c&#58;out value="$&#123;subject.subjectName&#125;"/></td>
    					<td><a href="SubjectEdit.htm?id=<c&#58;out value="$&#123;subject.id&#125;"/>">Edit</a></td>
    					<td><a href="SubjectDelete.htm?id=<c&#58;out value="$&#123;subject.id&#125;"/>">Delete</a></td>
    				</tr>
    			</c&#58;forEach>
    
    		</table>
        </c&#58;if>
    My Controller ,
    Code:
    package org.yourschool.library.web;
    
    import java.util.ArrayList;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import org.springframework.web.servlet.ModelAndView;
    import org.springframework.web.bind.RequestUtils;
    import org.yourschool.library.domain.Subject;
    
    public class SubjectSearchController extends AbstractLibraryController &#123;
    
    
    	public ModelAndView handleRequestInternal&#40;HttpServletRequest request, HttpServletResponse response&#41; throws Exception &#123;
    
                   String subjectName = request.getParameter&#40;"subjectName"&#41;;
    
                   // TODO catch if not integer.
                   int page = RequestUtils.getRequiredIntParameter&#40;request, "page"&#41;;
                   int pageSize = RequestUtils.getRequiredIntParameter&#40;request, "pageSize"&#41;;
    
                   if&#40;subjectName != null&#41;&#123;
    
                            ArrayList subjects = &#40;ArrayList&#41;getLibrary&#40;&#41;.findSubjectsByName&#40;subjectName,page*pageSize,pageSize&#41;;
    
                            if &#40;subjects.size&#40;&#41; < 1&#41; &#123;
    
                               // no subject found
                               return new ModelAndView&#40;getSuccessView&#40;&#41;,"message_no_subject_found","no.subject.found"&#41;;
                            &#125;
    
                            // multiple subjects found
    		        return new ModelAndView&#40;getSuccessView&#40;&#41;,"model_name_subjects",subjects&#41;;
    
    	        &#125;
    
    	        return new ModelAndView&#40;getSuccessView&#40;&#41;&#41;;
    
            &#125;
    &#125;
    my DAO ,
    Code:
            public Collection findSubjectsByName&#40;final String subjectName , final int firstResult , final int maxResults&#41;
                   throws DataAccessException &#123;
                   return getHibernateTemplate&#40;&#41;.executeFind&#40;new HibernateCallback&#40;&#41; &#123;
                          public Object doInHibernate&#40;Session session&#41; throws HibernateException,SQLException &#123;
                                 Query query = session.createQuery&#40;"from Subject subject where subject.subjectName like &#58;subjectName"&#41;;
                                 query.setString&#40;"subjectName", subjectName&#41;;
                                 query.setFirstResult&#40;firstResult&#41;;
                                 //System.out.println&#40;"^^^^^^^^"+firstResult+"^^^^^^^^^"&#41;;
                                 query.setMaxResults&#40;maxResults&#41;;
                                 return query.list&#40;&#41;;
                          &#125;
                    &#125;&#41;;
            &#125;
    l make it very fast ... just to test my idea work or not ....it seen that it DID works !! ...hehehe

    the codes above is not so important(since it is quick and dirty) , the ideas that l am having here are

    1. A simple paging tag <simpleaging/>just use for paging.
    2. easy to change html page, because it use only jstl tag
    3. without any changes to your controllers which is just return a collection
    4. all under your controll , just 3 easy understandable class only.
    5. it can be use to page a "1,000,000,000 elements" resultset.

    any comments ??

    moon

  2. #12
    Join Date
    Dec 2004
    Location
    Bucuresti, Romania
    Posts
    72

    Default

    Hi,
    I looked at your solution and it seems simple, but it seems to have a small problem. You do the same query for each page o data, but with different limiit and offset. When such a query is costly, this could lead to performance problems. Of course, you won't see a problem for simple queries as the one you have mentioned. In the solution I have described, you perform the costly query (for ids only) as rare as possible, only on initial search, refresh or sort by column. When navigating through pages of, the taglib will issue just a
    Code:
    select * from my_table where id in &#40;...&#41;
    sql query which is not costly at all, since you explictly specify the primary keys of the rows you need.

    Working with a Collecation (or a List) as the model of for the tabular data set is ok form simple cases. But when you want to provide lazy loading capabilities (as in my example), it becomes awkard: either you have to provide your own collection implementation (which lazy loads pages of data as you iterate through it), or you need to perform potentially costly queries each time you need to view a page of tabular data.

    Mircea.

  3. #13
    Join Date
    Sep 2004
    Posts
    133

    Default

    Hi croco ,

    l did not go that far ,. l will look at it when l go further , thank you for your reminder.

    l did this simple implementation because l am not satified with the service concept in ValueList (it is suitable for report type display) , and also the "join" with the DAOs --> ValueListHandler (as the author said himself : what is the ValueListHandler in the picture for ? http://forum.springframework.org/vie...ight=valuelist).

    Neither is the gavin's Page class , the result List have to wrap in the Page class , if the controller have to return a page just for paging , then it will break a lot my controllers "return" code , .(l don't know how other people did their paging , just my imagination)

    What l wish to find are ,

    1. a simple way to page my "medium large size" resultset .

    simple enough that every one can easily take control if they don't satified with my implementation , make change to fit theirs requirement -- because my code is easy to hack .
    l had the experience to look inside the displaytag codes , huh~ , a lot to read , cannot digest and deadline coming , hehe ....

    2. an invisible "demon" (something like my simple pagingTag) separate from the "return collection" to do paging.

    Gavin's Page class wrap the list inside the class to do paging, do it this way , it will break those controller's codes which are mostly return a collection if l return a page. l HOPE paging and DAO can be separate.

    3. "easy to change" html pages .

    All DIY html page make you easy to take full control the style of the html page , because l use only jstl tag for data display. --> if u cannot make ur jsp page better , that is your fault , because l did nothing , just jstl tag only !! (of course , + a simple paging tag) hihi .....

    and etc...etc...

    l need more comments ( thanks croco) , l think somebody will find l design fault and make wonderful suggestions ... .

    moon

  4. #14
    Join Date
    Sep 2004
    Posts
    133

    Default

    Hihi ....l did some exercise , here are simple enhanced version.
    Google style paging :
    << Prev 1 ... 6 7 8 9 10 11 12 ... 14 Next >>
    PagingTag.java:
    Code:
    package org.simplePage.tags;
    
    import java.util.Map;
    import java.util.List;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.jsp.tagext.BodyTagSupport;
    import javax.servlet.jsp.JspException;
    import org.simplePage.tags.support.LinkEncoder;
    import org.simplePage.web.RequestUtil;
    
    public class PagingTag extends BodyTagSupport &#123;
        private String modelName;
        private int listSize;
        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 = "page";
        public static final String PAGE_SIZE = "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;
    
               HttpServletRequest request = &#40;HttpServletRequest&#41; pageContext.getRequest&#40;&#41;;
               Map parameters = RequestUtil.getRequestParameterMap&#40;request&#41;;
    
               String Page = &#40;String&#41;parameters.get&#40;PAGE&#41;;
               this.page = Integer.parseInt&#40;Page&#41;;
    
               String PageSize = &#40;String&#41;parameters.get&#40;PAGE_SIZE&#41;;
               this.pageSize = Integer.parseInt&#40;PageSize&#41;;
               
               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 = UrlEncoder.encode&#40;makePreviousPageParameters&#40;parameters&#41;&#41;;
               this.nextPageLink = UrlEncoder.encode&#40;makeNextPageParameters&#40;parameters&#41;&#41;;
    
               StringBuffer sb = new StringBuffer&#40;&#41;;
               
               sb.append&#40;"\n<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\">\n"&#41;;
               sb.append&#40;"  <tr>\n"&#41;;
               sb.append&#40;"     <td align=\"left\" nowrap=\"true\">\n"&#41;;
               sb.append&#40;"     </td>\n"&#41;;
               sb.append&#40;"     <td align=\"right\">\n"&#41;;
               sb.append&#40;"        <table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" >\n"&#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><< Prev</B></font></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|
    **/
    
               // 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 ;
    
               //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>Next &gt;&gt;</B></font></a>\n"&#41;;
                     &#125;
               &#125;
               sb.append&#40;"        </table>\n"&#41;;
               sb.append&#40;"     </td>\n"&#41;;
               sb.append&#40;"   </tr>\n"&#41;;
               sb.append&#40;" </table>\n"&#41;;
               
               try &#123;
                   pageContext.getOut&#40;&#41;.print&#40;sb.toString&#40;&#41;&#41;;
               &#125;catch &#40;Exception ex&#41; &#123;
                    System.out.println&#40;"-------- Hello Error !! -------&#58;" + ex.toString&#40;&#41;&#41;;
               &#125;
    
               return SKIP_BODY;
        &#125;
    
        public int doEndTag&#40;&#41; throws JspException &#123;
               return EVAL_PAGE;
        &#125;
    
        public String makePageLink&#40;Map parameters, int pageNumber&#41;&#123;
               parameters.put&#40;PAGE,""+pageNumber&#41;;
               return UrlEncoder.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;
    pagingtag.tld ,
    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" 
      "http&#58;//java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
    
    
    <taglib>
    	<tlib-version>0.1</tlib-version>
        	<jsp-version>1.2</jsp-version>
        	<short-name>paging</short-name>
        	<uri>http&#58;//www.simplePage.org</uri>
        	<discription>A Simple Paging Tag</discription>
        	<tag>
            	<name>paging</name>
            	<tag-class>org.simplePage.tags.PagingTag</tag-class>
            	<body-content>JSP</body-content>
            	<display-name>table</display-name>
    		<attribute>
    			<name>modelName</name>
    			<required>true</required>
    			<rtexprvalue>true</rtexprvalue>
    		</attribute>
    		<attribute>
    			<name>pagingWidth</name>
    			<required>false</required>
    			<rtexprvalue>true</rtexprvalue>
    		</attribute>
        	</tag>
    </taglib>
    my jsp,
    Code:
    	<c&#58;if test="$&#123;!empty model_name_subjects&#125;" >
    	
    <simple&#58;paging modelName="model_name_subjects" pagingWidth="7"/>
    ***************************************************************		
    		<table>
    		
    			<tr>
    				<th width="10%"><fmt&#58;message key="subject.id"/></th>
    				<th width="60%"><fmt&#58;message key="subject.name"/></th>
    				<th width="15%">Edit</th>
    				<th width="15%">Delete</th>
    			</tr>
    
    			<c&#58;forEach var="subject" items="$&#123;model_name_subjects._resultset&#125;">
                                              *********************************
    				<tr>
    					<td><c&#58;out value="$&#123;subject.id&#125;"/></td>
    					<td><c&#58;out value="$&#123;subject.subjectName&#125;"/></td>
    					<td><a href="SubjectEdit.htm?id=<c&#58;out value="$&#123;subject.id&#125;"/>">Edit</a></td>
    					<td><a href="SubjectDelete.htm?id=<c&#58;out value="$&#123;subject.id&#125;"/>">Delete</a></td>
    				</tr>
    			</c&#58;forEach>
    
    		</table>
        </c&#58;if>
    My Controller ,
    Code:
    public class SubjectSearchController extends AbstractLibraryController &#123; 
    
    
       public ModelAndView handleRequestInternal&#40;HttpServletRequest request, HttpServletResponse response&#41; throws Exception &#123; 
    
                   String subjectName = request.getParameter&#40;"subjectName"&#41;; 
    
                   // TODO catch if not integer. 
                   int page = RequestUtils.getRequiredIntParameter&#40;request, "page"&#41;; 
                   int pageSize = RequestUtils.getRequiredIntParameter&#40;request, "pageSize"&#41;; 
    
                   if&#40;subjectName != null&#41;&#123; 
    //******************************************************************************************
                            Map model = getLibrary&#40;&#41;.findSubjectsByNameWithTotal&#40;subjectName,page*pageSize,pageSize&#41;;
    
                            ArrayList subjects = &#40;ArrayList&#41;model.get&#40;"_resultset"&#41;;
    //******************************************************************************************
                            if &#40;subjects.size&#40;&#41; < 1&#41; &#123; 
    
                               // no subject found 
                               return new ModelAndView&#40;getSuccessView&#40;&#41;,"message_no_subject_found","no.subject.found"&#41;; 
                            &#125; 
    
                            // multiple subjects found 
                  return new ModelAndView&#40;getSuccessView&#40;&#41;,"model_name_subjects",model&#41;; 
                                                                              //*******
               &#125; 
    
               return new ModelAndView&#40;getSuccessView&#40;&#41;&#41;; 
    
            &#125; 
    &#125;
    my DAO ,
    Code:
    //**@1**
    public Map findSubjectsByNameWithTotal&#40;String subjectName , int firstResult , int maxResults&#41;&#123;
    
         ArrayList subjects = &#40;ArrayList&#41;findSubjectsByName&#40;subjectName,firstResult,maxResults&#41;;
         Integer totalFound = findSubjectsTotalByName&#40;subjectName&#41;;
         Map model = new HashMap&#40;&#41;;
    	  model.put&#40;"_totalElements",totalFound&#41;;
    	  model.put&#40;"_resultset",subjects&#41;;
    
    	  return model;
    &#125;
    
    public Collection findSubjectsByName&#40;final String subjectName , final int firstResult , final int maxResults&#41; throws DataAccessException &#123;
                   return getHibernateTemplate&#40;&#41;.executeFind&#40;new HibernateCallback&#40;&#41; &#123;
                          public Object doInHibernate&#40;Session session&#41; throws HibernateException,SQLException
           &#123;
                                 Query query = session.createQuery&#40;"from Subject subject where subject.subjectName like &#58;subjectName"&#41;
                                                      .setString&#40;"subjectName", subjectName&#41;
                                                      .setFirstResult&#40;firstResult&#41;
                                                      .setMaxResults&#40;maxResults&#41;;
                                 return query.list&#40;&#41;;
                          &#125;
                    &#125;&#41;;
    &#125;
    
    public Integer findSubjectsTotalByName&#40;final String subjectName&#41; throws DataAccessException &#123;
                   return &#40;Integer&#41;getHibernateTemplate&#40;&#41;.execute&#40;new HibernateCallback&#40;&#41; &#123;
                          public Object doInHibernate&#40;Session session&#41; throws HibernateException,SQLException
          &#123;
                                 Integer count = &#40;Integer&#41;session.createQuery&#40;"select count&#40;*&#41; from Subject subject where subject.subjectName like &#58;subjectName"&#41;
                                                                 .setString&#40;"subjectName", subjectName&#41;
                                                                 .uniqueResult&#40;&#41;;
                                 return count;
                          &#125;
                    &#125;&#41;;
    &#125;
    Same for LinkEncoder.java , RequestUtil.java , includeTop.jsp .

    Remark :

    1. This is a "poor man" google style paging , for those database with no scrollable resultset support.
    2. More overhead . Performance not fast as previous version , because add another query to the database --> count(*) to obtain the total .
    ----It indeed a problem if the resultset is large enough (1,000,000) , one solution is to limit the return resultset if you still need the google style navigation service .
    3. Method **@1** findSubjectsByNameWithTotal not necessary in DAO , can be done in controller but lost transaction support advantage as in DAO.
    4. Hard code part --> _totalElements , _resultset
    5. This enhanced version PagingTag.java class can be separated from the previous version PagingTag.java class .
    ----Simply because the previous version are more powerful than this version if the google style navigation service are not needed ...
    6. Becareful ...this is fast code ...

    if l have time , l will try sorting .....hihihi ....

    moon

  5. #15
    Join Date
    Sep 2004
    Posts
    133

    Default

    Sorting version..

    PagingTag.java ( minor change , delete something not necessary )
    Code:
    package org.simplePage.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.tags.support.LinkEncoder;
    import org.simplePage.web.RequestUtil;
    
    public class PagingTag extends BodyTagSupport &#123;
    
        private Map parameters;
        private String modelName;
        private int listSize;
        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 = "page";
        public static final String PAGE_SIZE = "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;;
    
               try&#123;
                  	writePaging&#40;&#41;;
               &#125;
               catch&#40;IOException ex&#41; &#123;
                    ex.getMessage&#40;&#41;;
               &#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;;
               this.page = Integer.parseInt&#40;Page&#41;;
    
               String PageSize = &#40;String&#41;parameters.get&#40;PAGE_SIZE&#41;;
               this.pageSize = Integer.parseInt&#40;PageSize&#41;;
    
               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 = UrlEncoder.encode&#40;makePreviousPageParameters&#40;parameters&#41;&#41;;
               this.nextPageLink = UrlEncoder.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 UrlEncoder.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 ( which extends MessageTag.java from Spring , but of course you can make yourself a sortingTag.java totally decouple from Spring Package )
    Code:
    package org.simplePage.tags;
    
    import java.util.Map;
    import java.io.IOException;
    import javax.servlet.http.HttpServletRequest;
    import org.springframework.web.servlet.tags.MessageTag;
    import org.simplePage.tags.support.LinkEncoder;
    import org.simplePage.web.RequestUtil;
    
    public class SortingTag extends MessageTag &#123;
    
        private Map parameters;
        private String sortColumn;
        private String sortColumnLink;
        public static final String PAGE = "page";
        public static final String SORT_COLUMN = "sortColumn";
        public static final String ASCENDING = "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.sortColumnLink = UrlEncoder.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;;
               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;
    
                    String ascending = &#40;String&#41;parameters.get&#40;ASCENDING&#41;;
    
                    if&#40;ascending.equals&#40;"true"&#41;&#41;&#123;
                            parameters.put&#40;ASCENDING,"false"&#41;;
                    &#125;else &#123;
                            parameters.put&#40;ASCENDING,"true"&#41;;
                    &#125;
    
                &#125;else&#123;
                    parameters.put&#40;ASCENDING,"true"&#41;;
                &#125;
               return parameters;
    
        &#125;
    
    &#125;
    pagingtag.tld
    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" 
      "http&#58;//java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
    
    
    <taglib>
    	<tlib-version>0.1</tlib-version>
        	<jsp-version>1.2</jsp-version>
        	<short-name>paging</short-name>
        	<uri>http&#58;//www.simplePage.org</uri>
        	<discription>A Simple Paging Tag</discription>
    
        	<tag>
            	<name>paging</name>
            	<tag-class>org.simplePage.tags.PagingTag</tag-class>
            	<body-content>JSP</body-content>
    		<attribute>
    			<name>modelName</name>
    			<required>true</required>
    			<rtexprvalue>true</rtexprvalue>
    		</attribute>
    		<attribute>
    			<name>pagingWidth</name>
    			<required>false</required>
    			<rtexprvalue>true</rtexprvalue>
    		</attribute>
        	</tag>
    
    	<tag>
    
    		<name>sorting</name>
    		<tag-class>org.simplePage.tags.SortingTag</tag-class>
    		<body-content>JSP</body-content>
    
    		<description>
    			Retrieves the message with the given code, or text if code isn't resolvable.
    			The HTML escaping flag participates in a page-wide or application-wide setting
    			&#40;i.e. by HtmlEscapeTag or a "defaultHtmlEscape" context-param in web.xml&#41;.
    		</description>
    
    		<attribute>
    			<name>sortColumn</name>
    			<required>true</required>
    			<rtexprvalue>true</rtexprvalue>
    		</attribute>
    
    		<attribute>
    			<name>code</name>
    			<required>false</required>
    			<rtexprvalue>true</rtexprvalue>
    		</attribute>
    
    		<attribute>
    			<name>arguments</name>
    			<required>false</required>
    			<rtexprvalue>true</rtexprvalue>
    		</attribute>
    
    		<attribute>
    			<name>text</name>
    			<required>false</required>
    			<rtexprvalue>true</rtexprvalue>
    		</attribute>
    
    		<attribute>
    			<name>var</name>
    			<required>false</required>
    			<rtexprvalue>true</rtexprvalue>
    		</attribute>
    
    		<attribute>
    			<name>scope</name>
    			<required>false</required>
    			<rtexprvalue>true</rtexprvalue>
    		</attribute>
    
    		<attribute>
    			<name>htmlEscape</name>
    			<required>false</required>
    			<rtexprvalue>true</rtexprvalue>
    		</attribute>
    
    		<attribute>
    			<name>javaScriptEscape</name>
    			<required>false</required>
    			<rtexprvalue>true</rtexprvalue>
    		</attribute>
    
    	</tag>
    
    </taglib>
    My DAO,
    Code:
    public Map findPublishersByNameWithTotal&#40;String publisherName,int firstResult,int maxResults,String sortColumn,boolean ascending&#41; throws DataAccessException&#123;
    
          ArrayList publishers = &#40;ArrayList&#41;findPublishersByNameWithSorting&#40;publisherName,firstResult,maxResults,sortColumn,ascending&#41;;
          Integer totalFound = findPublishersTotalByName&#40;publisherName&#41;;
          Map model = new HashMap&#40;&#41;;
          model.put&#40;"_totalElements",totalFound&#41;;
          model.put&#40;"_resultset",publishers&#41;;
    
          return model;
            &#125;
    
    public Collection findPublishersByNameWithSorting&#40;final String publisherName , final int firstResult , final int maxResults , final String sortColumn , final boolean ascending&#41; throws DataAccessException &#123;
                   return getHibernateTemplate&#40;&#41;.executeFind&#40;new HibernateCallback&#40;&#41; &#123;
                          public Object doInHibernate&#40;Session session&#41; throws HibernateException,SQLException &#123;
    //******** Have to use Criteria API instead of Query API to do dynamic Sorting ********
                                 Criteria criteria = session.createCriteria&#40;Publisher.class&#41;
    					       .add&#40; Expression.like&#40;"publisherName", publisherName&#41; &#41;
                                                   .setFirstResult&#40;firstResult&#41;
                                                   .setMaxResults&#40;maxResults&#41;;
                                 if&#40;ascending&#41; &#123;
                                    criteria.addOrder&#40; Order.asc&#40;sortColumn&#41; &#41;;
                                 &#125;else&#123;
                                    criteria.addOrder&#40; Order.desc&#40;sortColumn&#41; &#41;;
                                 &#125;
                                 return criteria.list&#40;&#41;;
                          &#125;
                    &#125;&#41;;
            &#125;
    
    public Integer findPublishersTotalByName&#40;final String publisherName&#41; throws DataAccessException &#123;
                   return &#40;Integer&#41;getHibernateTemplate&#40;&#41;.execute&#40;new HibernateCallback&#40;&#41; &#123;
                          public Object doInHibernate&#40;Session session&#41; throws HibernateException,SQLException &#123;
                                 Integer count = &#40;Integer&#41;session.createQuery&#40;"select count&#40;*&#41; from Publisher publisher where publisher.publisherName like &#58;publisherName"&#41;
                                           .setString&#40;"publisherName", publisherName&#41;
                                           .uniqueResult&#40;&#41;;
                                 return count;
                          &#125;
                    &#125;&#41;;
            &#125;
    My Controller ( Using SpringWebFlow ),
    Code:
    	public Event SearchByName&#40;RequestContext context&#41; throws Exception &#123;
    
                    String publisherName = &#40;String&#41;context.getSourceEvent&#40;&#41;.getParameter&#40;"publisherName"&#41;;
                    String sortColumn = &#40;String&#41;context.getSourceEvent&#40;&#41;.getParameter&#40;"sortColumn"&#41;;
    
                    // TODO catch if not integer.
                    int page = new Long&#40;&#40;String&#41;context.getSourceEvent&#40;&#41;.getParameter&#40;"page"&#41;&#41;.intValue&#40;&#41;;
                    int pageSize = new Long&#40;&#40;String&#41;context.getSourceEvent&#40;&#41;.getParameter&#40;"pageSize"&#41;&#41;.intValue&#40;&#41;;
                    boolean ascending = new Boolean&#40;&#40;String&#41;context.getSourceEvent&#40;&#41;.getParameter&#40;"ascending"&#41;&#41;.booleanValue&#40;&#41;;
                    //int page = RequestUtils.getRequiredIntParameter&#40;request, "page"&#41;;
                    //int pageSize = RequestUtils.getRequiredIntParameter&#40;request, "pageSize"&#41;;
    
    		if&#40;publisherName != null&#41;&#123;
    
                            //Map model = getLibrary&#40;&#41;.findPublishersByNameWithTotal&#40;publisherName,page*pageSize,pageSize&#41;;
                            Map model = getLibrary&#40;&#41;.findPublishersByNameWithTotal&#40;publisherName,page*pageSize,pageSize,sortColumn,ascending&#41;;
    
                            ArrayList publishers = &#40;ArrayList&#41;model.get&#40;"_resultset"&#41;;
    
                            if &#40;publishers.size&#40;&#41; < 1&#41; &#123;
                               // no publisher found
                               context.getRequestScope&#40;&#41;.setAttribute&#40;"message_no_publisher_found",
                                    getMessageSourceAccessor&#40;&#41;.getMessage&#40;"no.publisher.found"&#41;&#41;;
    
                               return success&#40;&#41;;
    
                            &#125;
                            // multiple publishers found
    		        context.getRequestScope&#40;&#41;.setAttribute&#40;"model_name_publishers", model&#41;;
    
    		        return success&#40;&#41;;
    		&#125;
    		
    		return success&#40;&#41;;
    
            &#125;
    jsp (publisher.Search.for.Update.Delete.jsp),
    Code:
    <%@ page contentType="text/html;charset=UTF-8" %>
    <%@ include file="/WEB-INF/jsp/includeTop.jsp" %>
    
    <HTML>
    <HEAD>
    
    </HEAD>
    
    <BODY>
    <DIV align="center">
    	<c&#58;if test="$&#123;!empty publisher&#125;" >						
    		<spring&#58;bind path="publisher.*">
    			<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>
    </DIV>
    
    <a href="/library/admin/index.htm"><spring&#58;message code="home"/></a> &gt;
    
    <br>
    
    <DIV align="center">	
      	<FORM name="searchForm" method="POST" action="publisher.Search.for.Update.Delete.htm">
     		<INPUT type="hidden" name="_flowExecutionId" value="<c&#58;out value="$&#123;flowExecutionId&#125;"/>"/>
    		<INPUT type="hidden" name="_eventId" value="searchByName"/>
      		<input type="hidden" name="page" value="0"/>
      		<input type="hidden" name="pageSize" value="10"/>
    		<input type="hidden" name="sortColumn" value="publisherName"/>
    		<input type="hidden" name="ascending" value="true"/>	
    		<!-- ******************* first time parameters injection *************************-->
    	<TABLE>
        	<TR> 
          		<TD COLSPAN="3"><h3 align="center"><spring&#58;message code="title.search.publisher"/></h3></TD>
        	</TR>
        	<TR> 
          		<TD COLSPAN="3"><HR></TD>
        	</TR>
        	<TR> 
          		<TD><spring&#58;message code="input.title.publisher.name"/> &#58;</TD>
          		<TD><input type="text" name="publisherName"/></TD>
          		<TD>
    				<input type="button" onclick="javascript&#58;document.searchForm.submit&#40;&#41;" value='<spring&#58;message code="label.search"/>'/>
          		</TD>
        	</TR>
    		<TR> 
          		<TD align="center" colspan="3">
    	  			<c&#58;if test="$&#123;!empty message_no_publisher_found&#125;" >
    					<spring&#58;message text="$&#123;message_no_publisher_found&#125;"/>
    					<c&#58;remove var="message_no_publisher_found"/>
    				</c&#58;if>
    	  		</TD>
        	</TR>
        	<TR> 
          		<TD COLSPAN="3"><HR></TD>
        	</TR>
      	</TABLE>
    	</FORM>
    
    	<c&#58;if test="$&#123;!empty model_name_publishers&#125;" >
    	
    	<simple&#58;paging modelName="model_name_publishers" pagingWidth="7"/>		
    		<table>
    		
    			<tr>
    				<th width="10%">No</th>
    				<th width="60%"><simple&#58;sorting code="publisher.name" sortColumn="publisherName"/></th>
    <!--***** this is sorting tag , you can make it totally decouple for Spring Package if you want ****-->
    				<th width="15%">Edit</th>
    				<th width="15%">Delete</th>
    			</tr>
    
    			<c&#58;forEach var="publisher" items="$&#123;model_name_publishers._resultset&#125;" varStatus="status">
    				<tr>
    					<td><c&#58;out value="$&#123;status.count + param&#91;'page'&#93;*param&#91;'pageSize'&#93;&#125;"/></td>
    				<!--************** auto increment item no. using only jstl tag **********-->
    					<td><c&#58;out value="$&#123;publisher.publisherName&#125;" escapeXml='false'/></td>
    					<td><a href="publisherEdit.htm?id=<c&#58;out value="$&#123;publisher.id&#125;"/>">Edit</a></td>
    					<td><a href="publisherDelete.htm?id=<c&#58;out value="$&#123;publisher.id&#125;"/>">Delete</a></td>
    				</tr>
    			</c&#58;forEach>
    
    		</table>
        </c&#58;if>
    
    </DIV>
    
    </BODY>
    </HTML>
    Same for LinkEncoder.java , RequestUtil.java , includeTop.jsp .

    Remark:
    1. Fast code ( a lot not "type save" parameters).
    2. A lot combination pagings. you can make simple paging , google paging , "simple + sorting" paging , "google + sorting" paging .
    3. Separated Tags. Notice that all tags ( simpleaging , simple:sorting , jstl tags (c:forEach , c:out) ) are decouple from each others , can be used independently depend on situations.It is so flexible that your paging tags can be put every where inside your jsp page without even inside the display table.
    4. Extensible . These three version pagings can be totally separate from Spring package , that means the ideas can be use in other frameworks if u want. Other ORM's pagingTag can be easy be implement if they support paging like hibernate , even using plain jdbc.

    Question:
    1. l discovered that it is unexpected simple to do paging after these three different version pagings , am l doing wrong ? ( althought it is fast code )
    how your guys implements paging ? l would like to know ...

    For Spring Team:
    Is this a useful idea doing paging ? hihi....because all people do paging sooner or later , if Spring add more support for paging , l guess it will attract more people using Spring (of course , not using my code above .... :oops: hihihi) , just like the successful story of hibernate --> all people need databases.

    moon

  6. #16
    Join Date
    Sep 2004
    Posts
    133

    Default

    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

  7. #17
    Join Date
    Sep 2004
    Posts
    133

    Default

    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 at 03:36 AM.

  8. #18
    Join Date
    Jun 2005
    Posts
    2

    Default 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

  9. #19
    Join Date
    Sep 2004
    Posts
    133

    Default

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

    DAO,
    Code:
    	public Map findItemsByCriteriaWithTotal&#40;ItemCommand itemCommand&#41;
    			throws DataAccessException &#123;
    
    		ArrayList items = &#40;ArrayList&#41; findItemsByCriteriaWithLimit&#40;itemCommand&#41;;
    		Integer totalFound = findItemsTotalByCriteria&#40;itemCommand&#41;;
    
    		Map model = new HashMap&#40;&#41;;
    		model.put&#40;"_totalElements", totalFound&#41;;
    		model.put&#40;"_resultset", items&#41;;
    
    		return model;
    	&#125;
    
    	public Collection findItemsByCriteriaWithLimit&#40;ItemCommand itemCommand&#41;
    			throws DataAccessException &#123;
    
    		final Item item = itemCommand.getItem&#40;&#41;;
    		final Book ibook = item.getBook&#40;&#41;;
    
    		final String sortColumn = itemCommand.getS_sortColumn&#40;&#41;;
    		final int page = itemCommand.getS_page&#40;&#41;;
    		final int pageSize = itemCommand.getS_pageSize&#40;&#41;;
    		final int ascending = itemCommand.getS_ascending&#40;&#41;;
    
    		return getHibernateTemplate&#40;&#41;.executeFind&#40;new HibernateCallback&#40;&#41; &#123;
    			public Object doInHibernate&#40;Session session&#41;
    					throws HibernateException, SQLException &#123;
    
    				Example exampleItem = Example.create&#40;item&#41;.ignoreCase&#40;&#41;
    						.enableLike&#40;MatchMode.ANYWHERE&#41;;
    				Example exampleBook = Example.create&#40;ibook&#41;.ignoreCase&#40;&#41;
    						.enableLike&#40;MatchMode.ANYWHERE&#41;;
    
    				Criteria criteria = session.createCriteria&#40;Item.class&#41;
    						.add&#40;exampleItem&#41;;
    				
    				if &#40;ascending > 0&#41; &#123;
    					criteria.addOrder&#40;Order.asc&#40;sortColumn&#41;&#41;;
    				&#125; else &#123;
    					criteria.addOrder&#40;Order.desc&#40;sortColumn&#41;&#41;;
    				&#125;
    				
    				criteria.createCriteria&#40;"book"&#41;
    						.add&#40;exampleBook&#41;
    						.setFirstResult&#40;page * pageSize&#41;
    						.setMaxResults&#40;pageSize&#41;;
    
    				return criteria.list&#40;&#41;;
    			&#125;
    		&#125;&#41;;
    	&#125;
    
    	public Integer findItemsTotalByCriteria&#40;ItemCommand itemCommand&#41;
    			throws DataAccessException &#123;
    
    		final Item item = itemCommand.getItem&#40;&#41;;
    		final Book ibook = item.getBook&#40;&#41;;
    
    		return &#40;Integer&#41; getHibernateTemplate&#40;&#41;.execute&#40;
    				new HibernateCallback&#40;&#41; &#123;
    					public Object doInHibernate&#40;Session session&#41;
    							throws HibernateException, SQLException &#123;
    
    						Example exampleItem = Example.create&#40;item&#41;.ignoreCase&#40;&#41;
    								.enableLike&#40;MatchMode.ANYWHERE&#41;;
    						Example exampleBook = Example.create&#40;ibook&#41;
    								.ignoreCase&#40;&#41;.enableLike&#40;MatchMode.ANYWHERE&#41;;
    
    						Integer count = &#40;Integer&#41; session.createCriteria&#40;Item.class&#41;
    								.setProjection&#40;Projections.rowCount&#40;&#41;&#41;
    								.add&#40;exampleItem&#41;
    								.createCriteria&#40;"book"&#41;
    								.add&#40;exampleBook&#41;
    								.uniqueResult&#40;&#41;;
    					
    						return count;
    
    					&#125;
    				&#125;&#41;;
    	&#125;
    Domain 1 - Item.java
    Code:
    public class Item  implements java.io.Serializable &#123;
    
        // 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
         ......
    &#125;
    Domain 2 - Book.java
    Code:
    public class Book implements java.io.Serializable &#123;
    
          // 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&#40;&#41;;
          private Set subjects = new HashSet&#40;&#41;;
          private Set seriez = new HashSet&#40;&#41;;
          private Set otherTitles = new HashSet&#40;&#41;;
          private Set reservations;
          private Note note;
          private Publisher publisher;
          // get , set
          ......
    &#125;
    Controller , (AbstractPagingFormController extends AbstractLibraryFormController , and AbstractLibraryFormController extends SimpleFormController)
    Code:
    public class ItemSearch extends AbstractPagingFormController &#123;
    
    	private String itemColumnKey;
    	
    	public ItemSearch&#40;&#41; &#123;
    		setCommandClass&#40;ItemCommand.class&#41;;
    		setCommandName&#40;"itemCommand"&#41;;
    		setSessionForm&#40;true&#41;;
    	&#125;
    	
    	public void setItemColumnKey&#40;String itemColumnKey&#41; &#123;
    		this.itemColumnKey = itemColumnKey;
    	&#125;
    
    	public ModelAndView onSubmit&#40;HttpServletRequest request,
    			HttpServletResponse response, Object command, BindException errors&#41;
    			throws Exception &#123;
    
    		ItemCommand itemCommand = &#40;ItemCommand&#41; command;
    
    		Map model = getLibrary&#40;&#41;.findItemsByCriteriaWithTotal&#40;itemCommand&#41;;
    
    		ArrayList items = &#40;ArrayList&#41; model.get&#40;"_resultset"&#41;;
    			
    		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

  10. #20
    Join Date
    Sep 2004
    Posts
    133

    Default 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 at 12:31 PM.

Similar Threads

  1. Odd behaviour when injecting TransactionTemplate
    By damon311 in forum Container
    Replies: 3
    Last Post: Jul 23rd, 2005, 11:21 AM
  2. Loosing my SecureContext
    By sklakken in forum Security
    Replies: 3
    Last Post: Jul 21st, 2005, 01:44 PM
  3. Multiple Data Sources + Hibernate + Spring
    By joeserel in forum Data
    Replies: 2
    Last Post: May 18th, 2005, 09:22 AM
  4. Replies: 3
    Last Post: Dec 8th, 2004, 10:23 AM
  5. Replies: 3
    Last Post: Nov 19th, 2004, 07:16 PM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •