Search code examples
urlsortingparametersiteratorstruts

Struts2 passing url parameter to sort tag


I´m newbie to Struts FW and JSP at all. I have a couple of list rows generated through <s: iterator>. I wanted to get this list sorted according to each column (name, address, etc.) so I added <s:sort> tag and created to comparator classes (name, address).

Now, I wonder how can I pass through the URL parameter which type of comparator I want to use?

The code looks like this:

<s:bean name="ois.AlphabetComparator" var="alphabetComparator" />   
<s:bean name="ois.AddressComparator" var="addressComparator" />
<s:url id="place" action="getAllPlaces">   
   <s:param name="sortStyle">#addressComparator
    </s:param>   
</s:url>   
<s:a href="%{place}">   
<s:sort comparator="?how to pass url parameter here?" source="places">   
  <s:iterator status="status">   
     ...   
  </s:iterator>   
</s:sort>

Solution

  • EXAMPLE 1

    Use #parameters['sortStyle'] to obtain the value of the parameter. First create URLs with distinct values for the parameter sortStyle :

    <s:url id="place_sortByAddress" action="getAllPlaces">
       <s:param name="sortStyle">ois.AddressComparator
        </s:param>   
    </s:url>
    <s:url id="place_sortByAlphabet" action="getAllPlaces">   
       <s:param name="sortStyle">ois.AlphabetComparator
        </s:param>   
    </s:url>
    

    Then add links (assuming the goal is to sort the list in various ways depending on the selected link) :

    <s:a href="%{place_sortByAddress}">Sort by Adress</s:a></br>
    <s:a href="%{place_sortByAlphabet}">Sort by Alphabet</s:a></br>
    

    The next step is a little more tricky. If there is actually a parameter called sortStyle, then a new bean is created from the value of the parameter sortStyle. This bean will be the comparator class to sort items in the list.

    <table>
        <tbody>
            <s:if test='%{#parameters["sortStyle"] != null}'>
                <s:bean name='%{#parameters["sortStyle"]}' var="comparatorClass" />
                <s:sort comparator="#comparatorClass" source="places">
                  <s:iterator>
                    <tr>
                        <td><s:property value="name"/></td>
                        <td><s:property value="adress"/></td>
                    </tr>
                  </s:iterator>
                </s:sort>
            </s:if>
        </tbody>
    </table>
    

    For example, if you clicked on the first link, your comparator class would be ois.AddressComparator.

    This solution should work fine, but it relies on the use of the parameter, that the user can see and modify, and that we must also check directly in the jsp with a "if" tag.

    Checks and changes could be handled on server-side by the Action class. It may be improved thanks to struts.

    EXAMPLE 2

    in the JSP, use struts s:form tag. Create submit buttons for this form with s:submit tags. Each submit button calls a different method of the Action class, one for each way to sort the list.

    <s:form action="getAllPlaces">
        <!-- Submit buttons -->
        <s:submit key="messages.submit" action="getAllPlaces" method="sortByAdress"/>
        <s:submit key="messages.submit" action="getAllPlaces" method="sortByAlphabet"/>
    

    Then create a table for displaying items of the list. As in the first example, a bean is created from a parametric value. Instead of a parameter sent in the URL, an attribute is set by the Action class and is used in the JSP. Let the Action class handle controls and changes on this attribute.

        <!-- Table for list -->
        <table>
            <tbody>
                <!-- Create a new bean with parametric class name -->
                <s:bean name="%{#attr['comparatorClassName']}" var="comparatorClass" />
                <s:sort comparator="#comparatorClass" source="places">
                <s:iterator>
                      <tr>
                         <td><s:property value="name"/></td>
                         <td><s:property value="adress"/></td>
                       </tr>
                </s:iterator>
                </s:sort>
            </tbody>
        </table>
    </s:form>
    

    There, is the code from the Action class. It has a comparatorClassName attribute with a default value. The value changes each time you call for methods sortByAlphabet() or sortByAddress.

    public class GetAllPlacesAction extends ActionSupport{
    
        /**
         * 
         * @return
         */
        private List<PlaceBean> places = new ArrayList<PlaceBean>();
    
        // Set default comparator class name
        private String comparatorClassName = "ois.AlphabetComparator";
    
        public String execute()
        {   
            // Populate Stub List
            GetAllPlacesAction.populateStubList(this.places);
            // Forward
            return SUCCESS;
        }
    
        public String sortByAdress()
        {
            // Refresh comparator class name
            this.comparatorClassName = "ois.AddressComparator";
            // Populate Stub List
            GetAllPlacesAction.populateStubList(this.places);
            // Forward
            return SUCCESS;
        }
    
        public String sortByAlphabet()
        {
            // Refresh comparator class name
            this.comparatorClassName = "ois.AlphabetComparator";
            // Populate Stub List
            GetAllPlacesAction.populateStubList(this.places);
            // Forward
            return SUCCESS;
        }
    
        private static void populateStubList(List<PlaceBean> p_places)
        {
            // Populate Stub List
            p_places.add(new PlaceBean("Gabriel", "USA"));
            p_places.add(new PlaceBean("Kim", "South Corea"));
            p_places.add(new PlaceBean("Khofi", "Ghana"));
            p_places.add(new PlaceBean("Abel", "Germany"));
        }
    

    This example may be improved by more experienced users. But for the moment it's enough to display a list, and two buttons to change the way its items are sorted. Good luck ;-) @+