The application I am currently working on uses Struts2 and Velocity. We recently implemented Sitemesh and while I applying it to our project, I was surprised by the very few posts across the web that talk about using Struts2, Velocity and Sitemesh. Maybe it is obvious to everyone else and I was just a bit lost because I am new to Java web development and Struts2. Hopefully, this post will help you in using Sitemesh along with Velocity and Struts2.
Sitemesh
Sitemesh is a layout engine that will help developers to implement a consistent look and feel for their web applications. It will also facilitate the maintenance of the layout code. There are other frameworks that serve the same purpose and take a different approach. Among them, the most popular would be Tiles framework. Tiles framework follows the composite pattern: in a very simplified explanation, each page will specifies which UI components (the top navigation, a left column or the footer) it needs in addition to the content of the page. Sitemesh has a different approach and uses the decorator pattern. Each page is only concerned about what is specific to it. Before the page is sent back to the client, the framework applies a decorator that contains the UI components (top nav, left nav … ) common to your pages. There are pros and cons of using either framework. What made me decide for Sitemesh is that if you need to change your layout, you’ll only have to make the change in your decorator while if you use Tiles, you’ll have to touch every pages. Also, something else that I like about Sitemesh is that you can have several decorators for the same application, meaning, you can apply a decorator for printing pages, or have 2 decorators, one implementing a newer layout and one keeping the current layout so users can choose which layout/style they like better.
Installing Sitemesh
- dependency: Add the framework’s jar in your lib folder or via your pom.xml if you are using maven.
- Create a decorator folder and drop there your decorator.xml
- Update your web.xml file as follow:
- Right before the Struts2Dispatch filter, drop the following:
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter>
<filter-name>struts-cleanup</filter-name>
<filter-class>org.apache.struts2.dispatcher.ActionContextCleanUp</filter-class>
</filter>
<filter>
<filter-name>sitemesh</filter-name>
<filter-class>com.opensymphony.module.sitemesh.filter.PageFilter</filter-class>
</filter>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter>
<filter-name>struts-cleanup</filter-name>
<filter-class>org.apache.struts2.dispatcher.ActionContextCleanUp</filter-class>
</filter>
<filter>
<filter-name>sitemesh</filter-name>
<filter-class>com.opensymphony.module.sitemesh.filter.PageFilter</filter-class>
</filter>
Then, in your servlet section, drop the following:
<servlet>
<servlet-name>sitemesh-velocity</servlet-name>
<servlet-class>com.opensymphony.module.sitemesh.velocity.VelocityDecoratorServlet</servlet-class>
<init-param>
<param-name>org.apache.velocity.toolbox</param-name>
<param-value>/WEB-INF/toolbox.xml</param-value>
</init-param>
<init-param>
<param-name>org.apache.velocity.properties</param-name>
<param-value>/WEB-INF/config/base/velocitybase.properties</param-value>
</init-param>
</servlet>
There are a few things to understand from this configuration:
- The order of the filter matters.Sitemesh processing happen on top of Struts’s FileDispatcher. This implies you won’t have access to Struts objects in your decorators and files parsed in the decorators.
- In the servlet section, if you are using Velocity, you need to specify 2 things: where your toolbox.xml is and where your velocity macros are. You use for that the <init-param> element
Pitfalls
- Sitemesh is layout engine, so use it for what it is for. Let’s say you created a decorator and need to access an object exposed by your controller, well, you don’t have access to this object anymore since Sitemesh processing is happening after Struts2′s in the response. You can extend the Sitemesh filter and put your objects in the context but I found that it’s best to stay away from deep changes and keep your design as simple as possible. Simple is good, it makes it easy to maintain code and often, engineers tend to over engineer a solution.
- AJAX responses will get decorated so exclude the AJAX URLs in the decorators.xml file using the exclude element.
- the Sitemesh version you need depends on the version of Struts2 you are using
