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

  • Pageable data list with Hibernate

    Hi all,

    I'm trying to figure out the best way to implement a pageable data list with Spring and Hibernate.

    I've set up a basic app which connects to a MySQL DB, selects all the records from a table and returns them to a JSP as a Collection, i.e.

    getHibernateTemplate().find("from MyClass myObject");

    I've hooked this up to Display Tag (http://displaytag.sourceforge.net), and it works perfectly for small data sets. However, as it reads the entire data set from the DB on every request, it clearly won't scale well.

    Short from implementing the whole thing myself, which I'd rather not do as I'm sure I'd just be reinventing the wheel, the only alternative to Display Tag that I can find is ValueList (http://valuelist.sourceforge.net). ValueList looks like it'll do exactly what I want, but with a fairly steep learning curve.

    I'm keen to hear how other people are tackling this everyday problem. Is there an established best practice? Am I on the right track with ValueList, shall I just get on with learning it?

    Any pointers would be much appreciated.

    Thanks,

    Rob

  • #2


    The valueList can do this? As I know,It seems that the valuelist fetch all data from database once ;-(

    To do this, I have to control the ResultSet myself and move the resultset cursor when I need new data.

    Paging in J2EE is too hard to do the same thing in .NET. Asp.net have DataSet to do paging and sorting . I don't know why java don't have the paging function component like asp.net's DataSet.

    Comment


    • #3
      Yep, it would seem it is intended to facilitate server side paging. From the ValueList site:

      I inherited a J2EE web solution that chose a different component to display tables. Because the other component does all the sorting and paging in the JRE, not the database where it belongs; the solution did not scale at all! I searched the web to find a replacement and was discouraged by the results. So I grabbed code for past projects and started valuelist.sourceforge.net
      I can't believe the only practical solution is .NET - surely someone must be up for fighing J2EE's corner :wink:

      Comment


      • #4
        Rob,

        Hibernate itself provides support for Pagination, through the setMaxResults(int maxResults) and setFirstResult(int firstResult) methods of the Query interface.

        In my DAO's I implemented a solution using this API, Spring's HibernateDaoSupport and the code Gavin King posted here: http://blog.hibernate.org/cgi-bin/bl.../2004/08/14hh/.

        I also worked with ValueList; it does provide some usefull build-in features, but I also found that it adds a lot off overhead in terms of configuration. I am also unsure as to whether ValueList performs well under high load.

        Hope this helps. Thomas

        Comment


        • #5
          Paging in Java/J2EE is hard? Hibernate handles it just fine!
          http://www.hibernate.org/hib_docs/v3...ing-pagination

          Comment


          • #6
            Thanks all.

            Ok great, Spring/Hibernate provide a simple way to split up the data set.

            All I need to do now is integrate this with ValueList and I'm in business.

            This page covers how to do this using the Hibernate adapter:

            http://valuelist.sourceforge.net/ada...20Adapter.html

            I've yet to follow it through properly, but on first glance I see the HQL is buried in the config file. I'd much rather keep this in my DAO object - does anyone know how to do this?

            Comment


            • #7
              I think you can do away with ValueList altogether when you decide to use the built-in Pagination support that Hibernate offers in combination with Spring's HibernateDaoSupport.

              -- Thomas

              Comment


              • #8
                Thanks Thomas, the pattern you describe is surely useful for enabling paging at the DAO level, but unless I'm missing something, it won't help me present the data in a typical pageable, sortable table form. To do this, I'm going to have to write all the code for generating the table, sorting/paging URLs etc, myself.

                This really is an everyday problem, for which I'm sure there must be an established solution. Indeed, a taglib such as ValueList should fit the bill and integrate with your pattern perfectly - I think!?

                What are your thoughts on this - would you normally code all the table generation stuff from scratch?

                Comment


                • #9
                  Rob.

                  You're right - the presentation of the Data in a sortable table form is not covered by the Hibernate / Spring solution.

                  I just found this post describing how to integrate ValueList with existing DAO's:
                  http://forum.springframework.org/vie...ight=valuelist

                  This looks quite good actually, you will get the best of both and no HQL buried in config files (which was the reason I wasn't very enthousiastic about ValueList) HMMM ... I might give this approach a try myself.

                  Rgrds, Thomas

                  Comment


                  • #10
                    Hi,

                    I have done such a taglib for the company I am working for, but I can't give you the sources. However, I can provide some hints. Regarding the UI relates stuff, my taglib implementation is very simillar with the display tag or value list tag implementations; the main difference is how you specify the tabular data that needs to be displayed.
                    My taglib needs is some sort of tabular data source, like value list needs a ValueListAdapter or display tag needs a collection. For this I have a TableModel interface that looks something like this:
                    Code:
                    public interface TabelModel {
                      public int getRowCount();
                      public int getColumnCount();
                      public Object getCellValue(int row, int column);
                    }
                    There is also a SortableTableModel for tabular data that needs sorting by its columns:
                    Code:
                    public interface SortableTableModel extends TabelModel {
                      public void sort(int column, boolean ascending);
                    }
                    When displaying page x of data, the taglib will call TableModel.getCellValue() for each row bewteen x* pageSize and (x+1) * pageSize. When sorting by one of the columns, the SortableTableModel.sort() method will be called.

                    I have some support classes that take care of the pagination like this:
                    When first page is required, obtain the list of all the ids of the rows in the table:
                    Code:
                    select id from my_table where ... order by col1 asc
                    Keeping in memory lists having up to tens of thousands ids (Integer or Long objects) is not a big deal, and it should not cause any memory related problems. Having the list of all ids, you can also display the total number of rows.
                    Besides the list of all ids, it also keeps in memory a local cache for the current page of data being displayed. So, when the getCellValue() is called for the cell of the page, the local cahe is loaded by executing a query like:
                    Code:
                     select * from my_table where id in (id1, id2,id3 ....)
                    Then the rest of the cell values are retrieved from the cache. When dispalying another page, only the page data query is executed:
                    Code:
                     select * from my_table where id in ( ....)
                    The page data query is supposed to be faster, because you explicitely specify the ids of the rows you need. The cached list of all ids is refershed only when sorting by a column or explicitelly requesting a refresh. This suits very well for large datasets and for comoplex queries; you pay the cost of the query only at the initialization or sorting requests, when the ids query is excuted. In my opinion this works better that the solution mentioned on hibernate docs (http://blog.hibernate.org/cgi-bin/bl...hh/%5B/url%5D.) where you have to pay the cost of the query each time you browse back and forth through the pages of data.

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

                    Comment


                    • #11
                      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

                      Comment


                      • #12
                        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.

                        Comment


                        • #13
                          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

                          Comment


                          • #14
                            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

                            Comment


                            • #15
                              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

                              Comment

                              Working...
                              X