Struts 2 isn’t Spring 3 but its darn close

By Chris L Hardin
Sr. Software Architect

Five years ago I wrote off Struts in favor of Spring MVC and with good reason. I was already using Spring for a myriad of other things and it was just logical to use the MVC portion since it had all the niceties that I came to expect from Struts, plus a lot more. Also, after Spring 3 came along, I think I decided there couldn’t be anything farther from perfection.

I started using Struts when it was still in its infancy and I used it on more than 20 projects, some of which were really high profile like the Toyota and Lexus Web sites. Struts was the solution to all these home-rolled frameworks that other architects were writing at the time. I think at this point all of those in-house solutions have been replaced by some Web framework by now or at least I hope they are.

I enjoyed Struts while it was in its heyday and I still think it dominates as the most widely used and accepted framework even today. All this being said, I haven’t seen anything Struts can do that can top Spring 3 though.

Recently, I had the pleasure of working on a project that was full-blown Struts 2 and I kept saying things like, “This is a new project, why are we using Struts.” and “Struts is dead…move on.” I was wrong.

Struts 2, which is actually WebWork rebranded as Struts, is a different animal. A pretty well designed framework that does a good job of creating a MVC architecture. It has all the features you have come to expect from Struts, along with a plugin framework and much, much more.

Struts 2 is still configuration heavy and I am pretty disappointed in that, but there is a convention plugin that allows you to use annotations and there is a JSON plugin as well that is really useful. All in all, I think there are around 30 plugins or more in Struts 2 that you can use.

Since I really love Spring 3 and conventional configuration options, I decided I would share some of my Struts 2 + Convention plugin configurations and code.

Simply, the convention plugin annotations allow you to use the “Zero Configuration” option for Struts 2, which I highly recommend. If you are still gluing your actions together with the struts.xml, you really need to stop overworking yourself. Let’s look at some examples of creating actions by convention.

The app that follows is an app for searching up and displaying users using either Ajax forms or an HTML form. The options you have are to return another page or just to return the JSON data.

I only have one class for this example and here is the declaration.


@ParentPackage("json-default")
@Namespace("/")
public class DefaultAction extends ActionSupport implements
ModelDriven {

Our UserSearch object contains just setters and getters for your form like get/setFirstName, etc. The UserSearch object is also annotated using the Java Validation Framework annotations. We implement ModelDriven so that we can externalize our form bean properties away from our action. We also extend ActionSupport so that we can add error and validation messages. I do not like having to extend ActionSupport just for the sake of adding messages because my object is no longer a POJO at that point. I couldn’t find anyway to add messages without extending this class.


@Action(value = "Start", results = { @Result(name = "success", location = "start.jsp") })
@Override
public String execute() {
...

private UserSearch search = new UserSearch();

@Override
public UserSearch getModel() {

return search;

}

Our first action is simple. Someone asks for /Start and we execute and redirect to start.jsp if success is returned.


@Action(value = "Process", results = { @Result(name = "success", location = "start.jsp") })
public String process() {

Set<ConstraintViolation> violations = search
.validate(search);
for (ConstraintViolation violation : violations) {
addActionError(violation.getPropertyPath() + " "
+ violation.getMessage());
}

In our form, we submit to /Process and since we have annotated the UserSearch with the Java Validation Framework, we can now validate the object. Struts 2 has built-in validation,. but I prefer to use the Java standard. If there are any constraint violations, we add them to action messages and they get returned to the client to display in the JSP page if you are using the correct tags from Struts.


@Action(value = "json", results = { @Result(name = "success", type = "json"),
@Result(name = "error",location = "start.jsp") })
public String executeAsJSON() {

Just in case you wanted to return the results of the search as JSON, you can do this in Struts 2. This will return the Model represented as JSON. This doesn’t do you much good in this case because the model is what we passed in the form, a UserSearch object. I got around this by putting a new property on UserSearch called UserSearchResult which contains the results of the search. In the executeAsJSON method, I merely call getModel().setUserSearchResult(result) and then I can access the results in JSON. In Spring 3, I could have set the return type of the method to UserSearchResult and solved the problem, but I couldn’t figure out in Struts how to do this or I don’t know if it is even possible yet, so I settled for my little hack.

I know I said that there was nothing in the struts.xml, but I didn’t exactly tell the truth. I did set some configuration options in the file.

<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">

<!---->

<!-- -->

<!-- -->

<!-- -->
<!-- -->
<!-- -->
<!-- -->

<!-- -->

<!---->

I’m not going to go into an explanation of these properties. They are kind of self explanatory anyway.

There is also another great plugin for Struts 2 for Spring integration. It allows you to use @Autowire in your actions to automatically inject the value of a bean from Spring into the action. This is very useful, but if you’re already using Spring, you’ll probably use the more flexible Spring 3 features instead of Struts anyway.

I have to say that I love Struts 2 and you really can’t go wrong by choosing it for your MVC framework. I will add though that some more work needs to be done on supporting the convention-based options. Some of the things I would like to see are the ability to easily just let the return type be anything and have the framework convert it to JSON and I’d like to see content negotiation whereby I can change the output of the method from json to XML to PDF to Excel, just by requesting a different extension.

All in all Struts may be an old dog, but it certainly has learned some new tricks.

Follow

Get every new post delivered to your Inbox.