Search code examples
javajspurlstruts2ognl

Creating dynamic URL with 2 action parameters in Struts 2 using OGNL


If I have a url: www.myurl.com/books and want to be able to create new <s:url> filtering on author and year: www.myurl.com/books/Sartre/1942 by passing Sartre and 1942 as parameters to the action class which will render the books page with the appropriate results. How to do this in Struts2?

I have the backend logic in place so it would be great if:

  1. I could reuse the same jsp and action class that the permalink www.myurl.com/books uses.
  2. Show the dynamically rendered URL www.myurl.com/books/Sartre/1942 in the address bar even after the get request has loaded the page (not www.myurl.com/books, that is).

Solution

  • You need Advanced Wildcard Mappings.

    From the documentation: Struts2's Advanced Wildcard Mappings:

    Advanced Wildcards

    From 2.1.9+ regular expressions can be defined defined in the action name. To use this form of wild card, the following constants must be set:

    <constant name="struts.enable.SlashesInActionNames" value="true"/> 
    <constant name="struts.mapper.alwaysSelectFullNamespace" value="false"/>
    <constant name="struts.patternMatcher" value="regex" />
    

    The regular expressions can be in two forms, the simplest one is {FIELD_NAME}, in which case the field with the FIELD_NAME in the action will be populated with the matched text, for example:

    <package name="books" extends="struts-default" namespace="/">
        <action name="/{type}/content/{title}" class="example.BookAction">
            <result>/books/content.jsp</result>
        </action> 
    </package>
    

    In this example, if the url /fiction/content/Frankenstein is requested, BookAction's field "type" will be set to "fiction", and the field "title" will be set to "Frankenstein".

    If using Struts2-Convention-Plugin, your example would be:

    @Action(value="/books/{author}/{year}")
    public class Books extends ActionSupport {
        private String  author; 
        private Integer year;
        /* ...GETTERS AND SETTERS HERE... */
    
        public String execute(){            
            /* ...LOAD DATA HERE... */
            if (noDataFound)
                return NONE;
            return SUCCESS
        }
    }
    

    If you need to work with those parameters in prepare() method, read this question.