Struts2 table with paging ability provided by the pager tag library
The problem
I wanted to be able to display a table of data with a table pager so that a user could call the next 10 results when they wanted.
Download the war file (Stuts2 table with JSPtags pager)
Download the war file (JSPtags pager example simplified)
I needed to display a table of data in a web application that used the Struts2 framework recently. The Struts2 table tag plugin seemed to be the thing for the job but there was not a lot of information on its use apart from a code snippet on the Struts2 table tag wiki entry. After hunting around for a while I came across an SVN entry that was indexed by Google with the word example in the name. This led me to downloading the SVN version of that tag which was just the ticket to getting started. It contained three examples of tables created with the Struts2 table tag that also used the included paging tag. Unfortunately I didn't find the paging tag either very nice to use or as functional as the pager tag library from JSP tags. This was because I seemed to have to add at least 100 lines of code into my action to get it to work. Maybe this was just me doing something wrong but I really didn't want all of that in my action. In the end I removed the code for the struts2 table pager and integrated the Struts2 table tag with the JSP pager tag. This is how the finished result looks:
If you download the JSP tags pager library there are several examples of how to use it. My only problem with it was that the examples took over 600 lines of code in the JSP, once I had hacked away the unnecessary bits I got it down to under 60 lines of code that actually did what I wanted! That is why I have included my pager tag war for you. It may be easier than looking at the actual example.
Ok, lets look at some code (at last I hear you say?)
The Struts2 action code
@Override
public String execute(){
// The pager offset is put into the request by the pg:pager tag of the JSP page. If it exists in the request then get it and use it.
int pagerOffset = 0;
if(servletRequest.getParameter("pager.offset") != null) pagerOffset = new Integer((String) servletRequest.getParameter("pager.offset")).intValue();
// START: Get the result of the search. We are making it up here but you will probably go to a database to get this
UserBean userBean;
int userNumber;
for(int j = 0 ; j < searchResultPagerSize ; j++){
userNumber = j + 1;
userBean = new UserBean(new Integer(userNumber) , "username " + userNumber , "user" + userNumber + "@example.com");
searchResult.add(userBean);
}
// END: Get the result of the search. We are making it up here but you will probably go to a database to get this
/* Although our searchResult may have returned 75 results we only want the table to show 'numberOfItemsPerPage' results. So
* take the relevent subset of the the searchResult and add them to the 'searchResultSubset' ArrayList which will contain the
* actual search result that you want to show in the table.
*/
for(int i = pagerOffset ; i < (pagerOffset + numberOfItemsPerPage) && i < searchResultPagerSize ; i++){
getSearchResultSubset().add(searchResult.get(i));
}
// As the pg:pager is not part of Struts it doesn't read values from the ValueStack. We must drop them into the request for it to get them
servletRequest.setAttribute("searchResultPagerSize" , searchResultPagerSize);
servletRequest.setAttribute("searchResult" , searchResult);
servletRequest.setAttribute("numberOfItemsPerPage" , numberOfItemsPerPage);
servletRequest.setAttribute("maxNumberOfPagesToShow" , maxNumberOfPagesToShow);
return SUCCESS;
}
This is a standard Strts2 action execute method. The pagerOffset is the number of the pager that is currently showing. In the above image that is 71-75 or page 8 so the pagerOffset value is 8. The pagerOffset is held in the request and if it is not available then we assume the user wanted the first page of the results.
The next part where we create the UserBean is where the we create ALL the items that the pager will know about and the Struts2 table tag will show a subset of this. I have simply filled an array with the UserBean objects but you would probably go to your database and get the results you wanted to show here instead. The next bit is the interesting bit and so I have copied it below:
for(int i = pagerOffset ; i < (pagerOffset + numberOfItemsPerPage) && i < searchResultPagerSize ; i++){
getSearchResultSubset().add(searchResult.get(i))
}
The pager tag and the table tag cannot be synchronous. By that I mean that the pager tag needs to know about everything that can possibly be shown while the table tag should only know about the items it needs to show. This means that while the pager tag knows about all the possible 75 results available but the table tag is only displaying results 71-75 - see the above image. The piece of code above is responsible for getting the subset from the full result set and making them available to the table tag.
The last piece of code adds things into the request. We need to do this because although the table tag is a Struts2 tag and can read from the ValueStack, the pager tag is not and so relies upon the request to pass parameters about. In case you are wondering then yes, this does tie your application to the JSP container as you now have a reference to the HttpServletRequest object in your action code. You can not use the Struts2 request map as the pager tag will not be able to access it, it may be possible to work around this if you need to but I don't have that requirement.
The JSP code
The last thing of interest then is the JSP which really consists of three things:
ArrayList searchResult = (ArrayList) request.getAttribute("searchResult");
int numberOfItemsPerPage = (Integer) request.getAttribute("numberOfItemsPerPage");
int maxNumberOfPagesToShow = (Integer) request.getAttribute("maxNumberOfPagesToShow");
int searchResultPagerSize = (Integer) request.getAttribute("searchResultPagerSize");
The above piece simply reads out the parameters that the action placed into the HttpServletRequest.
<pg:pager
items="<%= searchResultPagerSize %>"
index="center"
url=""
maxPageItems="<%= numberOfItemsPerPage %>"
maxIndexPages="<%= maxNumberOfPagesToShow %>"
isOffset="<%= true %>"
export="offset,currentPageNumber=pageNumber"
scope="request">
<%-- START: the visual element of the pager --%>
<%--
START: You can take any of the pages in the pagertags war file in the folder /WEB-INF/JSP and put them in here instead
--%>
<pg:index export="totalItems=itemCount">
<pg:page export="firstItem, lastItem">
<div class="resultInfo">
Displaying results <strong><%= firstItem%>-<%= lastItem%></strong> of <strong><%= totalItems%></strong> found
</div>
</pg:page>
<div class="rnav">
<span class="rnavLabel">Results:</span>
<pg:prev export="pageUrl">
<a href="<%= pageUrl%>" class="rnavLink">« Prev</a>
</pg:prev>
<pg:pages export="pageUrl,pageNumber,firstItem,lastItem">
<% if (pageNumber == currentPageNumber) {%>
<span class="rnavCurr"><%= firstItem%>-<%= lastItem%></span>
<% } else {%>
<a href="<%= pageUrl%>" class="rnavLink"><%= firstItem%>-<%= lastItem%></a>
<% }%>
</pg:pages>
<pg:next export="pageUrl">
<a href="<%= pageUrl%>" class="rnavLink">Next »</a>
</pg:next>
</div>
</pg:index>
<%--
END: You can take any of the pages in the pagertags war file in the folder /WEB-INF/JSP and put them in here instead
--%>
<%-- END: the visual element of the pager --%>
</pg:pager>
The next (see above code snippet) is the pager tag which displays the pager and its associated information. There is a note saying:
You can take any of the pages in the pagertags war file …
Which means that if you want to change the style of the pager to one of the other ones provided by the JSPTags example then you can download the JSPTags example war file and copy the contents of the files in the /WEB-INF/JSP and paste it between the START: and END: parts of my code above.
I would also suggest that you look at the pager documentation as there are a couple of other useful tag included with it. For my real application (not this demo code) I also had to use the <pg:param ... > tag to get it to work as I wanted. This page should get you started with the pager tag library though and you can go from there.
The last part is the display of the actual Struts2 table which uses the subset of the result available to the pager tag - do you remember that I mentioned getting the subset of the results above when discussing the action code?
<stt:table value="searchResultSubset" clientSort="true">
<stt:column title="Id" sortKey="sortKeyId">
<s:property value="searchResultUserId" />
</stt:column>
<stt:column title="Username" sortKey="sortKeyUsername">
<s:property value="searchResultUsername" />
</stt:column>
<stt:column title="Email" sortKey="sortKeyEmail">
<s:property value="searchResultEmail" />
</stt:column>
</stt:table>
The value attribute of the table tag references the Struts2 action method getSearchResultSubset() and then uses that data to populate itself. The clientSort attribute allows the user to click the table heading and have the data sorted using JavaScript. This requires the presence of the <s:head theme="ajax"> in the head section of the JSP page. Other than that it is probably self explanatory.
17.04.2009 12:50 - Posted by doahh - Comments: 2 - Java

Comments:
Hi..i am trying to deploy the same using struts 2.1.8.1 into apache tomcat 6.0.20,but getting the following expceiton,
java.lang.NoSuchMethodError: org.apache.struts2.views.util.UrlHelper.buildParametersString(Ljava/util/Map;Ljava/lang/StringBuffer;)V
at com.googlecode.tabletags.components.AbstractURLComponent.evaluateExtraParams(AbstractURLComponent.java:55)
at com.googlecode.tabletags.components.Table.evaluateExtraParams(Table.java:61)
at org.apache.struts2.components.UIBean.evaluateParams(UIBean.java:856)
at com.googlecode.tabletags.components.Table.start(Table.java:86)
at org.apache.struts2.views.jsp.ComponentTagSupport.doStartTag(ComponentTagSupport.java:53)
Could be please help me on this??
Thanks in advance..
27.04.2010 06:32 - Posted by Narasimha reddy - Permalink
Hi,
I have a table consisting of data in jsp.
now my task is to read that table data using for loop in action class how can i read..
could u pls help me…
pls.....
27.04.2011 11:49 - Posted by Swathi - Permalink