I spent a few hours last night replacing Tiles with SiteMesh in AppFuse. I had the Struts version done in 2 hours, and most of the Spring version done in an additional hour. Then I spent another 3 hours today twiddling with things and getting it just right. During this process, I discovered a few things I thought I'd share. Keep in mind that I'm pretty much a SiteMesh rookie. Hopefully, implementing and using it in AppFuse will help me to fully understand its power.
- SiteMesh lacks injection. Tiles allows you to inject JSP fragments into your base layout on a per-page basis. I didn't use this feature much, but I did use it to determine which menu should show up on what pages. For example, the login page would get a "projects used" menu, the signup page wouldn't have a menu, and all other pages would get the standard site menu. With SiteMesh, all of this seems to be done best with JSP includes and some <c:if> logic in your decorator. I ended up using
<c:import>
in my login.jsp
for the login menu, importing nothing for signup, and using <c:if>
statements in my decorator to see if the user was logged in. If they were, then I import the site menu and its necessary scripts and styles. In the end, this worked fine and it's probably easier for new AppFuse users to understand - so that's a good thing.
- Injecting scripts and stylesheets. With Tiles, I was able to easily control which scripts and stylesheets were shown on each page. With SiteMesh, this is pretty easy to do by putting them in the <head> element of your page. However, what I would've really liked to see is the ability to put these in an included JSP and have them end up in the <head> of the final document. I know it's virtually impossible, but it would be cool.
- Headings. Adding a <title> title element per-page works great using the <title> tag. However, if you want to add a heading (which I specify with an <h1> tag), you have to use a <content> tag. It would be cool if I could somehow use <h1> or <heading> in my page to indicate a heading. I ended up going with the following in each page to specify the title and heading:
<title><fmt:message key="mainMenu.title"/></title>
<content tag="heading"><fmt:message key="mainMenu.heading"/></content>
|
There's probably an easier way to do this, but this works for now.
- Injecting <body> ids. Using body ids to set styles on a per-page basis is a great way to control CSS. With Tiles, I set this as an attribute in
tiles-config.xml
and then grabbed/used it with the following JSTL code:
<c:set var="bodyId" scope="request">
<tiles:getAsString name="body.id" ignore="true"/>
</c:set>
<body<c:if test="${not empty bodyId}"> id="<c:out value="${bodyId}"/>"</c:if>>
|
Yeah, it's ugly, but it works. With SiteMesh, you can easily set a body id by using <body id="name">
. In fact, you don't even need to wrap your content with it, you can simpley do <body id="name"/>
. I'm grabbing and using this in my decorator with the following code. This works, but it would be cool if I could check for the existence of the attribute first - so I could eliminate id=""
when no body id is set.
<body id="<decorator:getProperty property='body.id'/>">
|
- Inheritance. With Tiles, you could extend page definitions and override attributes. This feature seems to be completely lacking in SiteMesh. I don't know how you could implement it, but it would be nice to have something where you could specify the parent - for instance, to use the same <head> content.
- Error page decoration. SiteMesh seems to be incapable of decorating error pages (i.e. 404) in Tomcat 5.0.x (even if I add
<dispatcher>ERROR</dispatcher>
to the filter-mapping). A workaround is to use wrap the error page with a <page:applyDecorator>
tag. This works, but if you specify elements in <head>, they will end up in the body of page, rather than in the decorator's header.
- SiteMesh simplifies. Switching from Tiles to SiteMesh allowed me to delete somewhere around 8 JSPs. AppFuse has 34 after committing everything. Most of these were JSPs that sat in the root folder and had a one-liner to pull in a Tiles definition. However, it also eliminated 11 JSPs from the Spring MVC install - allowing reduction of duplication. The Spring MVC install now has 17 JSPs.
So there you have it. AppFuse now uses SiteMesh instead of Tiles! I'm sure the implementation will get cleaner and more refined as more folks use it. I'm looking forward to deleting some chunks out of AppFuse's tutorials because SiteMesh makes page development so much easier. The hardest part of SiteMesh is setting up the infrastructure. Once you're got that done, you hardly ever touch it again.
Next task: WebWork integration.