The Source for Java Technology Collaboration
User: Password:



Simon Brown

Simon Brown's Blog

Comparing webapp frameworks : Struts

Posted by simongbrown on January 26, 2006 at 09:48 AM | Comments (4)

Struts is the grandaddy of Java webapp frameworks so it's fitting that we start our tour here. I think it's probably safe to say that Struts was the first model 2 (web MVC) framework to gain widespread adoption in the Java arena and to this day it's still used by many people.

Just to ensure everybody is up to speed, model 2/web MVC is an architectural pattern that promotes separation of concerns between the model, the view and the controller in a web environment. As we saw in the previous model 1 implementations of the sample application, each of the JSP pages contains Java code to lookup data and display it to the user. With an MVC approach, each of the components has a strict responsibility as follows.

  • Model : represents the data being viewed/manipulated.
  • View : responsible for rendering the model back to the user.
  • Controller : responsible for taking the request/user input and initialising the model, manipulating it, etc.

In reality, different people have different views as to whether the controller represents only the web specific parts of the process flow and whether real business logic in fact resides in the model (it being a model of the underlying business). What's important here is that web MVC promotes a separation of concerns through reusable and testable components, regardless of how you cut it. For more information about the model 2 architecture, take a look at Designing Web Applications and Servlet Patterns.

Home page
So what's different between the Struts version of the example application and the original model 1 version? Remember that Java code at the top of the page? Basically, that's been moved into a Java class.

package action;

import domain.Blog;
import domain.BlogService;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class ViewBlogEntriesAction extends Action {

  public ActionForward execute(ActionMapping mapping, ActionForm form,
    HttpServletRequest request, HttpServletResponse response) throws Exception {

    BlogService blogService = new BlogService();
    Blog blog = blogService.getBlog();
    request.setAttribute("blog", blog);

    return mapping.findForward("success");
  }
}

In Struts terminology, this class is called an action although you'll also see this general pattern referred to as the command pattern. At runtime, the Struts controller (a Java servlet) maps the incoming request onto an action class and calls the execute() method, which contains the (business) logic required to service the request. In the example, this logic is responsible for locating the Blog instance and making it available (via the request) so that the recent list of blog entries can be presented back to the user. As with all of the others, this example uses JSP as the view technology, although you'll notice from the code above that we don't explicitly say, "please now show JSP page X". We'll cover this shortly but for now, here's the JSP page itself.

<%@ page contentType="text/html;charset=UTF-8" %>
<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">

  <head>
    <title><bean:write name="blog" property="name" /></title>
    <link rel="stylesheet" href="screen.css" type="text/css" />
  </head>

  <body>
    <div id="container">
      <h1><bean:write name="blog" property="name" /></h1>
      <h2><bean:write name="blog" property="description" /></h2>

      <logic:iterate id="blogEntry" name="blog" property="blogEntries" >
        <div class="blogEntry">
          <h3><bean:write name="blogEntry" property="title" /></h3>
        </div>

        <logic:notEmpty name="blogEntry" property="excerpt">
          <bean:write name="blogEntry" property="excerpt" filter="false" />
          <p>
          <html:link action="viewBlogEntry" paramId="id" paramName="blogEntry" paramProperty="id">Read more</html:link>
          </p>
        </logic:notEmpty>

        <logic:empty name="blogEntry" property="excerpt">
          <bean:write name="blogEntry" property="body" filter="false" />
        </logic:empty>

        <p>
        Posted on <bean:write name="blogEntry" property="date" format="dd MMM yyyy HH:mm:ss" />
        </p>
      </logic:iterate>
    </div>
  </body>

</html>

As you can see, moving the Java code out of the page makes for a shorter JSP that looks just like regular XHTML, albeit with a few custom tags here and there. On that note, I've chosen to use Struts tags in this version of the page purely to show something a little different to last time, but you have other alternatives including the (more feature rich) JSTL tags.

So how does a request for the home page make its way through to the ViewBlogEntriesAction class? Well, the main index.jsp page contains a simple JSP forward to /viewBlogEntries.do, which is subsequently mapped to the ViewBlogEntriesAction Java class. With Struts, there are two parts to this. First of all, the mapping between *.do and the Struts front controller servlet is defined in the web.xml file, as follows.

  <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>
    <load-on-startup>1</load-on-startup>
  </servlet>

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

Next, the mapping between a URL and the Java class responsible for processing that request is specified in a file called struts-config.xml that typically resides in /WEB-INF (but is configurable, as you see above). Here's the relevant part of the file that illustrates these mappings (path -> type) for the sample application.

    <action-mappings>

      <action path="/viewBlogEntries" type="action.ViewBlogEntriesAction" name="viewBlogEntries">
        <forward name="success" path="/viewBlogEntries.jsp" />
      </action>

      <action path="/viewBlogEntry" type="action.ViewBlogEntryAction" name="viewBlogEntry">
        <forward name="success" path="/viewBlogEntry.jsp" />
        <forward name="notfound" path="/404.jsp" />
      </action>

    </action-mappings>

Within each of the action mappings, you'll also notice one or forward elements and these are essentially an abstraction over the JSP that will be responsible for rendering the response. It's probably worth noting that this is just a URI, so you don't have to reference a JSP page here. If you look back to the ViewBlogEntriesAction class above, you'll see that the last line in the execute method performs mapping.findForward("success"). This says, please find the mapping called success that's defined for this action mapping and forward control to it. In this case, the viewBlogEntries.jsp page is used. This completes the picture and is the basic way that most requests in Struts are handled.

Blog entry detail page
Likewise, for the blog entry page we have an action class and a JSP page. Here's the action.

package action;

import domain.Blog;
import domain.BlogEntry;
import domain.BlogService;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class ViewBlogEntryAction extends Action {

  public ActionForward execute(ActionMapping mapping, ActionForm form,
    HttpServletRequest request, HttpServletResponse response) throws Exception {

    BlogService blogService = new BlogService();
    Blog blog = blogService.getBlog();
    request.setAttribute("blog", blog);

    BlogEntry blogEntry = blog.getBlogEntry(request.getParameter("id"));
    if (blogEntry == null) {
      return mapping.findForward("notfound");
    } else {
      request.setAttribute("blogEntry", blogEntry);
      return mapping.findForward("success");
    }
  }

}

No big surprises here except that there are two possible routes through the action depending on whether the specified blog entry is found or not. And here's the JSP page used to render the successful response.

<%@ page contentType="text/html;charset=UTF-8" %>
<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">

  <head>
    <title><bean:write name="blogEntry" property="title" /> : <bean:write name="blog" property="name" /></title>
    <link rel="stylesheet" href="screen.css" type="text/css" />
  </head>

  <body>
    <div id="container">
      <h1><bean:write name="blog" property="name" /></h1>
      <h2><bean:write name="blog" property="description" /></h2>

      <div class="blogEntry">
        <h3><bean:write name="blogEntry" property="title" /></h3>

        <bean:write name="blogEntry" property="body" filter="false" />

        <p>
        Posted on <bean:write name="blogEntry" property="date" format="dd MMM yyyy HH:mm:ss" />
        </p>
      </div>
    </div>
  </body>

</html>

Summary
Despite its age, Struts is still one of the mostly widely used web application frameworks and one of the top choices for teams building Java EE systems. Additionally, the overall implementation strategy (called the Command and controller strategy in Java EE pattern documentation) is probably the most pervasive in both bespoke build and, as we'll be seeing, other open source alternatives to Struts.


Bookmark blog post: del.icio.us del.icio.us Digg Digg DZone DZone Furl Furl Reddit Reddit
Comments
Comments are listed in date ascending order (oldest first) | Post Comment

  • If you're sick of dealing with struts-config.xml and writing new classes for each action, check out Sprout. Sprout is a set of extensions to Struts that adhere to the DRY (don't repeat yourself) principle. Applications using Sprout will work seamlessly alongside legacy Struts applications.

    Posted by: seth on January 26, 2006 at 01:47 PM

  • > As you can see, moving the Java code out of the page
    > makes for a shorter JSP that looks just like regular XHTML,
    > albeit with a few custom tags here and there.

    Actually, for your use case and restrictions the Struts sample looks worse than JSP + JSTL. Pages are not simpler, new tags, Java classes, config file. Lotsa stuff. For the example as simple as yours using Struts instead of plain JSP does not make any sense (some would argue that using Struts does not make any sense at all, but this is a totally different story). Therefore it is hard to make a point whether Struts is better than plain JSP or not. Model 2 vs. Model 1 argument does not really work, because JSP can be used in "view helper" mode, which is like an inverted Model 2. I guess you will get there when you will be trying Stripes.

    Posted by: michael_jouravlev on March 08, 2006 at 01:17 PM

  • I agree with Michal that after all, Struts introduces so many complications that it is difficult to say it really helps you.

    In fact, I detected a very common error while using Struts, that is mistaking MVC pattern with Template View pattern.

    After studying Struts, I prefer to go back to plain old jsps.

    Posted by: daviti on March 20, 2006 at 01:36 AM

  • I read these postings and I had to sign up just so I could agree with the 2 previous comments. In my opinion and experience Struts is total overkill for an application like this one. For a simple database driven application where you're the only developer, no question about it, LEAVE STRUTS AT HOME. It's so much nicer to work on something and have all the code in the SAME place.

    Although, Struts obviously has it's place, but I would never choose it for something this simple unless it was for training purposes.

    Posted by: chuckyellig on January 12, 2007 at 09:30 AM



Only logged in users may post comments. Login Here.


Powered by
Movable Type 3.01D
 Feed java.net RSS Feeds