Implementing Clean URL in Struts

The web application created by using Struts framework can be easily identified by the URL patterns. Mostly all the Struts application have *.do or *.action URL depending on the version of Struts being used and the best practices that are followed.

These URLs are less  search engine friendly as they reveal very little about the content. Hence it can be useful to implement a web application with clean URLs pattern such as /custormer/add or /profile/william.

This can be achieved in Struts by modifying Web.xml and struts-config.xml files. Following is the ActionServlet entry that is normally made in Web.xml file in order to configure struts.

<servlet>
<servlet-name>action</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml</param-value>
</init-param>
<init-param>
<param-name>debug</param-name>
<param-value>2</param-value>
</init-param>
<init-param>
<param-name>detail</param-name>
<param-value>2</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>

Thus, whenever the client request comes, the container match the pattern *.do in the URL and invokes the ActionServlet class which handles the rest of flow in Struts application. In order to use clean URL, make following entry for ActionServlet in your Web.xml file.

<servlet>
<servlet-name>action</servlet-name>
<servlet-class>
org.apache.struts.action.ActionServlet
</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml</param-value>
</init-param>
<init-param>
<param-name>debug</param-name>
<param-value>2</param-value>
</init-param>
<init-param>
<param-name>detail</param-name>
<param-value>2</param-value>
</init-param>
<init-param>
<param-name>chainConfig</param-name>
<param-value>
org/apache/struts/tiles/chain-config.xml
</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>

<!-- Extension mappings to static content -->
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.css</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.js</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.png</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.jpg</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/index.jsp</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>

Please note that here the URL pattern that is mapped to ActionServlet class is not *.do and is / i.e. all the requests that comes will be routed to ActionServlet by the container. Also, URL patterns such as *.js, *.jpg, *.png, *.css etc are mapped to a servlet called default. This ensures that the static content are served to client without getting redirected to ActionServlet. Thus if you have other static content in your website, don’t forget to make an entry here and map it to default servlet. For example, I may have some *.zip files that I want to my users to download. Hence I will create an entry for *.zip and map it to default servlet in Web.xml file.

Once this is done, all the requests (except for static content) will get routed to ActionServlet.

Now, we will make normal entries for Action class in struts-config.xml file. Each entry will have a unique URL pattern that maps to an Action class.

<action path="/login" name="userBean" scope="request"
validate="true" input="/index.jsp"
type="net.viralpatel.sturts.cleanurl.LoginAction">
<forward name="success" path="/home" />
<forward name="fail" path="/index.jsp" />
</action>
<action path="/home" name="userBean" scope="request"
validate="true" input="/index.jsp"
type="net.viralpatel.sturts.cleanurl.HomeAction">
<forward name="success" path="/home.jsp" />
<forward name="fail" path="/home.jsp" />
</action>
<action path="/profile/save" name="profileForm" scope="request"
validate="false" input="/profile.jsp"
type="net.viralpatel.sturts.cleanurl.ProfileAction">
<forward name="success" path="/profile.jsp" />
<forward name="fail" path="/profile.jsp" />
</action>

Thus, whenever client request for a URL /login, LoginAction will be invoked by Struts framework. It is sometimes desirable to achieve clean url where request parameters are passed. For example, in some application /profile/john will point to Profile page of user John and /profile/william will point to that of William.

This can be achieved by using parametrized struts-config entries for actions. For example.

<action path="/profile/*"
type="net.viralpatel.struts.cleanurl.ProfileAction"
parameter="{1}">
<forward name="success" path="/profile.jsp" />
<forward name="fail" path="/profile.jsp" />
</action>

We have mapped a URL pattern /profile/* to ProfileAction. Thus whenever client will request for pages such as /profile/john or /profile/william, ProfileAction will gets invoked by Struts. Also note that we have used a parameter=”{1}” attribute in <action> tag. This will pass whatever string that comes as * in /profile/* to Action class. This parameter can be fetched in Action class from mapping object of ActionMapping class which is passed as method argument in execute() method of Action.

public ActionForward process(ActionMapping mapping, ActionForm actionForm,
HttpServletRequest request, HttpServletResponse response)
throws NoRecordFoundException {

String parameter = mapping.getParameter();
...
}

Also, more than one parameter can be passed into the action for URLs like /profile/john/friends or /profile/john/groups. Thus to acheive this, URL /profile/*/* is mapped to Action and parameter=”{1}${2}” attribute will be added to action tag. Once the parameter is retrived in Action class using mapping.getParameter(), it has to split using $ separator as $ is used to concatenate {1} and {2} arguments.

Comments and queries invited :)



Tags:

11 Comments

  • Guru 13 April, 2009, 11:51

    Hi,

    This was a very good article for struts developers to provide a search engine friendly urls.
    If the application has struts and spring, how can we provide the wildcard in spring action bean definitions.

  • Viral Patel 15 April, 2009, 14:06

    Hi Guru,
    I had not chance to add this functionality in a Strut-Spring based application. I will soon update this tutorial.
    Thanks

  • Matt 5 May, 2009, 22:01

    Hi,

    Thanks for the idea.
    I think your old links like “page.do?param=12″ would not be fonctional anymore!
    Unless you duplicate actions in struts-config.xml.
    I made this implementation of cleaning Struts URLs to become more friendly by imposing a Filter that treats clean url’s and then redirects to the old Struts url.That worked smoothly.

    Thanks
    MS

  • Viral Patel 6 May, 2009, 17:12

    Thanks Matt for your comments.
    This technique can be applied if we are writing any application from scratch. But if we have to migrate an existing application, it becomes a little tedious.

  • john beck mentoring 24 June, 2009, 8:06

    Hi, It was good reading your post! I’ve been hearing about John Beck’s program these days. My colleague also purchased the system to use it as a side business work.

  • Madhukar 26 July, 2009, 0:11

    Nice article, I had seen such clean URL mapping at work and wondered why they had used the wild card * to map URLs to action classes, now I know. Might not use it myself but good to know.

    Offtopic, ViralPatel I would like to see some more articles on Spring – thanks.

  • Tuan 27 October, 2010, 8:41

    Nice article, but when i use is my page lost the path of css or jquery. original css\mycss.css. jsp page recognize normally. but when i use /profile/john/friends i must redefine css or jquerrt link again looklike as ../../css/mycss.css could you please give my any solution.

  • vinod 27 December, 2012, 11:04

    hii viral , i want from u just aded some project in struts aand hibernate

  • rameez 23 September, 2013, 13:16

    Nice work. Thanks. But i have a doubt,can we handle dispatch action in this way?

  • Tamas Fabian 4 February, 2014, 18:52

    Hello!
    Nice article! I just have one question. How can we nicely/easily use clean URLs with html forms?
    Example: let’s say we have a search page with a input text box, and after searching on ‘table’, I would like to have the URL ‘xxx.com/search/table’? How would the form look like?
    With default struts URLs, it looks something like this:

     
    <html:form action="search.do">
      <input type="text" name="search">
      <input type="submit">
    </html:form>
    
  • Barath R 12 February, 2014, 0:18

    Exactly what I have been looking for .. The explanation was clear and perfect

Leave a Reply

Your email address will not be published. Required fields are marked *

Note

To post source code in comment, use [code language] [/code] tag, for example:

  • [code java] Java source code here [/code]
  • [code html] HTML here [/code]

Current day month ye@r *