Integrating Struts 2 + JSF + Facelets
What if you didn't have to choose between a request-based framework and a component-based framework? What if you could use them together and use request-based for some pages and component-based for others? This is the functionality that the Struts 2 JSF Plugin provides.
To be fair, the JSF-Spring project says it does the same thing for Spring MVC + JSF, but there doesn't appear to be any documentation.
I did some prototyping of Struts 2 + JSF and discovered that it does indeed work. I also discovered that there's no documentation on integrating it with Facelets. Luckily, it's pretty easy to do - hence my reason for writing this entry. You might ask why I want to use Facelets when JSF 1.2 supports JSP fairly well? My reason is because JSP 2.1 hijacks #{}, which Struts 2's OGNL uses for some expressions. Because of this, I want to be able to run on a JSP 2.0 container until a workaround comes along. Sun's JSF 1.2 RI can run on a JSP 2.0 container, while MyFaces 2.1 cannot (at least in my experience).
There's two ways to get Struts 2 + JSF + Facelets working:
- Create a WEB-INF/faces-config.xml file and override the default view-handler:
<?xml version="1.0" encoding="UTF-8"?> <faces-config xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd" version="1.2"> <application> <view-handler>com.sun.facelets.FaceletViewHandler</view-handler> </application> </faces-config>
- The 2nd way is to use Ajax4JSF and declare the view-handler in your web.xml (allowing you to get rid of faces-config.xml):
<context-param> <param-name>org.ajax4jsf.VIEW_HANDLERS</param-name> <param-value>com.sun.facelets.FaceletViewHandler</param-value> </context-param>
NOTE: You have to use 2nd method if you want to use Ajax4JSF. It won't read the view-handler from faces-config.xml.
If you're using SiteMesh, you may have to add another <parser> element to your sitemesh.xml to get Facelets pages decorated:
<parser content-type="application/xhtml+xml" class="com.opensymphony.module.sitemesh.parser.HTMLPageParser"/>
Thanks to Laurie Harper for his assistance figuring this stuff out.
Now you might ask - why would you want to do this? For one, Struts 2 has a better navigation model (IMO) than JSF. Also, if developers want to use JSF and think it's a better way for a certain module - let them go to it!