struts-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Mike Menzies <glo...@gmail.com>
Subject JspHelper concept to improve MVC separation
Date Mon, 07 Oct 2013 20:26:26 GMT
Hello,

My name is Mike, and I work for a fairly large company that uses Struts 2
for most of its web apps. Some of these web apps are quite large, and one
in particular has grown into a monster. In my ongoing efforts to clean up
this project, I have developed what I like to call a JspHelper. Before I
explain exactly what that is, I'd like to provide you with some examples of
the problems that I set out to fix.

*Problem 1 - Monster JSPs*
During early development of this project, struts tags were highly
leveraged. I was not involved with the early phases of this project, so I
can't speak to why they were used so extensively.. but they were. Tons of
nested if tags that read var tags that were set in the JSP. Some of these
JSPs were very hard to follow.

Even though I am a fan of struts tags, I've come to realize that they
should not be overused. JSPs cannot be unit tested and JSPs are hard to
debug.

So cleaning up a JSP means shifting logic out, in most cases into the
action. An easy clean up could be something like this:

<s:if test="articles != null && articles.size > 0 && user.canViewArticles">

into

<s:if test="showArticleSection()">

It's instantly more readable, and the logic is in a testable Java class.
Following this approach creates a lot of methods in the action, which can
be a problem if you already have...

*Problem 2 - Bloated Action Classes*

When the project was small, it made a lot of sense to create
abstract/parent action classes to share code between actions. As time
passed, we just continued shoving any shared code in one of two "abstract"
classes... even if the code was only being shared between two out of the 20
actions.

The fix for this trend is to moved shared code into services, so we began
enforcing that practice. But this approach had its limitations. We use
Spring injection for all of our services, and some times a particular piece
of logic just required too much stateful input... it just made more sense
to leave it on the action where it had easy access to everything it needed,
as opposed to shoving it in a stateless service and having to pass in a ton
of arguments.

What we really needed was some best practices put in place for the creation
of stateful, non-Spring services.

*Enter JspHelperInceptor

*
It wasn't until after I created this inceptor that I realized it is almost
identical to the ModelDrivenInceptor. At which point, I wondered if that is
what I should actually be using.. but more on that later.

All this interceptor does is push an object onto the value stack. That's
it. Your action implements JspHelperAware which provides Object
getJspHelper(), and the intercept code reads almost line for line with the
ModelDrivenInterceptor.

The idea behind this JspHelper, which is just a POJO that you define, is to
provide a place where all (or most) of the data your JSP needs can be
found. This means that OGNL can find any public members or operations
faster, and also developers can trace back any OGNL expressions in the JSP
to it's corresponding Java code.

This approach places code in a shareable component. You can easily
aggregate one JSPHelper into another one, and then either provide wrapper
methods or simply push the aggregate helper onto the stack using the s:push
tag for direct access to it's members.

This approach makes the actions leaner, and provides a very clear cut view.
I find at times that the action tends to be both controller and view, when
really it should only act as the controller (IMO).

This technique is functionally very similar to ModelDriven, but it's used
slightly differently. I've used a JspHelper in combination with
ModelDriven, and I've found the JspHelper to be a good place to store
logic.. and leave the Model strictly as a business object.

*Conclusion
*
I have personally found this technique incredibly useful in cleaning up
code. You can shift all of the JSP exclusive logic and properties to the
helper without touching the JSP (the OGNL expressions remain the same).
Then after that initial step, you have a real handle on the exact input
your JSP needs, and the actual clean up process progresses faster and with
less errors. I'm still in the process of establishing some best practices,
but so far this approach is working for us.

I would like some honest feedback

Mime
  • Unnamed multipart/alternative (inline, None, 0 bytes)
View raw message