Recipe4.4.Sorting HTML Tables


Recipe 4.4. Sorting HTML Tables

Problem

You need to sort the results of a displayed table by clicking on a column header.

Solution

Create an Action, as shown in Example 4-8, that uses the BeanComparator class of the Jakarta Commons BeanUtils library to sort the underlying Collection.

Example 4-8. Sorting tabular data with an Action
package com.oreilly.strutsckbk.ch04; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.beanutils.BeanComparator; import org.apache.commons.collections.comparators.ReverseComparator; import org.apache.struts.action.Action; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; public class ViewForecastAction extends Action {   public ActionForward execute(ActionMapping mapping,       ActionForm form,       HttpServletRequest request,       HttpServletResponse response) throws Exception {     // create the weather bean     WeeklyWeather weather = new WeeklyWeather( );             // create a list to hold the forecast     List list = new ArrayList( );     list.addAll( weather.getWeekForecast( ) );     // get the sort by request param     String sortBy = request.getParameter("sortBy");     // get the reverse request param     boolean reverse = false;     String reverseParam = request.getParameter("reverse");     if (reverseParam != null)          reverse = Boolean.valueOf(reverseParam).booleanValue( );     // sort the list     if (sortBy != null) {       Comparator comparator = new BeanComparator(sortBy);       if(reverse) comparator = new ReverseComparator(comparator);       Collections.sort( list, comparator );     }          // add the list as a request attribute and forward to the JSP     request.setAttribute( "weekForecast", list );     return mapping.findForward("success");   } }

Then create an action element in the struts-config.xml that uses ViewForecastAction and forwards to the JSP page that displays the table:

<action path="/ViewForecast"         type="com.oreilly.strutsckbk.ch04.ViewForecastAction">     <forward name="success" path="/sorted_struts_table.jsp"/> </action>

On the JSP page (sorted_struts_table.jsp), shown in Example 4-9, the table header cells contain links to the ViewForecast action. Each link sets request parameters that indicate the property name to sort by and if the sort order is reversed (i.e., descending).

Example 4-9. Using table column headers for sorting
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib uri="http://jakarta.apache.org/struts/tags-bean" prefix=   "bean" %> <%@ taglib uri="http://jakarta.apache.org/struts/tags-logic" prefix=   "logic" %>   <html> <head>   <title>Struts Cookbook - Chapter 4 : Sorted Struts Table</title> </head> <body>   <table width="60%" border="2">     <tr>       <th>Day of Week<br />         <a href="ViewForecast.do">unsort</a>       </th>       <th>Chance of Precipitation<br />         <a href="ViewForecast.do?sortBy=chancePrecip">asc</a>         <a href="ViewForecast.do?sortBy=chancePrecip&reverse=true">desc</a>       </th>       <th>Expected Precipitation (inches)<br />         <a href="ViewForecast.do?sortBy=rainfall">asc</a>         <a href="ViewForecast.do?sortBy=rainfall&reverse=true">desc</a>       </th>     </tr>     <logic:iterate  name="weekForecast">       <tr>         <td>           <bean:write name="forecast" property="day"/>         </td>         <td>           <bean:write name="forecast" property="chancePrecip"/>         </td>         <td>           <bean:write name="forecast" property="rainfall"/>         </td>       </tr>     </logic:iterate>   </table> </body> </html>

Discussion

The approach shown in the solution performs an in-memory sort of the data displayed in an HTML table.

If the tabular data were stored in a database, you would need to store the data collection in the session or refetch the data from the database between requests.


The table is sorted by creating a java.util.Comparator based on the name of the property to sort by. The BeanComparator class provides the intelligence to create the comparator using JavaBean introspection. The created Comparator sorts the data based on the natural ordering of the property. If a reverse or descending order sort is desired, a ReverseComparator is created from the BeanComparator.

Comparing Java Objects

The value passed to the BeanComparator must implement the java.lang.Comparable interface. How that object implements Comparable determines that object's natural ordering. For Strings, the ordering is lexicographic, in other words, dictionary ordering. For numbers, the ordering is numeric.

What's sweet about the BeanComparator is that it does all the sorting for you, yet allows you to control the order. Return an object from the property getter that implements the Comparable interface. In the compareTo(Object obj) method, you can enforce whatever ordering you want. For more information on comparing Java objects, check out Budi Kurniawan's ONJava article at http://www.onjava.com/pub/a/onjava/2003/03/12/java_comp.html.


The Solution for this problem is easy. The grunt work of creating the Comparators is handled by the BeanComparator. If you add a new property to the object in the collection, it can be sorted by passing in a request parameter with the name of that property. If you want to return the collection to its natural, unsorted state, don't pass in the sortBy parameter.

Sorting in ascending or descending order is handled via the reverse request parameter. This parameter is mapped to a Boolean variable. If reverse is true, a ReverseComparator is used.

The JSP page adds sorting capability by providing links that forward to the ViewForecast action. Each link specifies a sortBy parameter corresponding to the column to be sorted. The link for sorting in descending order adds the reverse parameter. Figure 4-5 shows the resultant web page for the Solution. Here the "desc" link in the third column was clicked to order the data by greatest expected rainfall. You can see the generated URL for the "desc" link in the browser's status bar.

Figure 4-5. Sorted table


See Also

This Solution was based in-part on suggestions made in the struts-user mailing list. One useful thread posting by Henri Yandell is archived at http://www.mail-archive.com/struts-user%40jakarta.apache.org/msg95356.html.

JSTL tags can be used to create the table instead of the Struts logic:iterate and bean:write tags. Recipe 4.3 shows examples of JSTL to create tables. Recipe 4.6 shows you how to provide table sorting using the display tags open source tag library. You do not need to code any special Java sorting actions if you use this popular tag library.

For further information on the BeanUtils sorting capabilities, check out the JavaDocs at http://jakarta.apache.org/commons/beanutils/api/org/apache/commons/beanutils/BeanComparator.html.



    Jakarta Struts Cookbook
    Jakarta Struts Cookbook
    ISBN: 059600771X
    EAN: 2147483647
    Year: 2005
    Pages: 200

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net