|
Recipe 14.8. Integrating JavaServer Faces with StrutsProblemYou want to migrate an existing Struts application to JavaServer Faces without having to rewrite the entire application. SolutionUse the Struts-Faces integration library. DiscussionIt's reasonable to consider JavaServer Faces (JSF) to be the "son of Struts." In fact, the creator of Struts, Craig McClanahan, serves as co-lead for the JSF specification. Unlike Struts, JSF specifies a component model for the user interface of applications. Theoretically, that model can be rendered by any type of user interface, and not just a web-based interface. But in its current release, JSF targets web application development. There are two implementations of JSF available. The reference implementation (RI) has been developed and is distributed by Sun. MyFaces, an open source Apache project, implements the JSF specification and adds additional components not contained in the reference implementation. Struts-Faces, initially developed by Craig McClanahan, allows you to use JSF technology in a Struts application. Using this library, you can continue to use your actions and action forms as written, but you use the JSF custom tags instead of the Struts tags for the user interface. Struts-Faces allows you to migrate your existing Struts applications to JSF a page at a time. This recipe will help you get started with Struts-Faces. It applies this technology to a three-page application having an index page, a login page, and a welcome page displayed upon login. Struts-Faces is under active development. For the latest documentation and code, download the nightly build of Struts-Faces from http://svn.apache.org/builds/struts/nightly/struts-faces/, extracting the archive into a directory on your system:
The servlet mapping for the Faces servlet directs all requests with a .faces extension through the JSF FacesServlet for standard JSF processing. You will need to configure Struts to use a custom request processor for handling JSF integration. Example 14-21 shows the struts-config.xml, which specifies the controller declaration for the FacesRequestProcessor, that includes the action mappings for this example application. Example 14-21. Struts configuration file that uses Struts-Faces<?xml version="1.0" encoding="ISO-8859-1" ?> <!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN" "http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd"> <struts-config> <form-beans> <form-bean name="logonForm" type="org.apache.struts.action. DynaActionForm"> <form-property name="username" type="java.lang.String"/> <form-property name="password" type="java.lang.String"/> </form-bean> </form-beans> <global-forwards> <forward name="welcome" path="/welcome.faces"/> <forward name="logon" path="/logon.faces"/> <forward name="home" path="/index.jsp" redirect="true"/> </global-forwards> <!-- ========== Action Mapping Definitions =========================== --> <action-mappings> <action path="/Logon" name="logonForm" scope="request" type="com.oreilly.strutsckbk.ch14.LogonAction"> <forward name="success" path="welcome.faces"/> </action> </action-mappings> <controller> <set-property property="processorClass" value="org.apache.struts.faces.application.FacesRequestProcessor"/> </controller> <message-resources parameter="ApplicationResources"/> </struts-config> The first page of the application, shown in Example 14-22 (index.jsp), provides a link to the "logon" page. This conventional JSP page doesn't contain any JSF or Struts-Faces components. Example 14-22. Regular Struts-based index page<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %> <%@ taglib prefix="html" uri="http://struts.apache.org/tags-html" %> <html> <head> <title>Struts Cookbook - Integrating Struts and JSF</title> </head> <body> <h2>Struts Cookbook - Integrating Struts and JSF</h2> <html:link forward="logon">Try out Struts and JSF</html:link> </body> </html> The second page, logon.jsp shown in Example 14-23, contains the logon form submitted to the /Logon action. Example 14-23. Logon page using Struts-Faces components<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="f" uri="http://java.sun.com/jsf/core" %> <%@ taglib prefix="h" uri="http://java.sun.com/jsf/html" %> <%@ taglib prefix="s" uri="http://struts.apache.org/tags-faces" %> <f:view> <s:html locale="true"> <head> <title>Struts Cookbook - Integrating Struts and JSF</title> </head> <body> <p /> <s:form action="/Logon" focus="username" style> <h:outputLabel for="username" style value="Username:"/> <h:inputText value="#{logonForm.username}" required="true" size="10"/> <p /> <h:outputLabel for="password" style value="Password:"/> <h:inputSecret value="#{logonForm.password}" required="true" size="10"/> <p /> <h:commandButton type="SUBMIT" value="Logon" /> </s:form> </body> </s:html> </f:view> If you've never used JavaServer Faces, this page probably looks funky. The page starts conventionally and declares the taglib directives for the JSF core and html tag libraries, as well as the Struts-Faces tag library.
On this page, the f:view tag contains the entire content of the view. All JSF pages must contain a f:view tag that encapsulates the custom JSF tags. The s:form tag, from the Struts-Faces library, creates an HTML form that can be submitted to a Struts action. The h:outputLabel tags display label text for input fields declared with the h:inputText tags. The h:inputSecret tag creates a password input field. The h:commandButton tag creates the form's submit button. When this page was first written, yours truly inadvertently left off the value attribute for the h:inputText and h:inputSecret tags. As Struts developers, the best practice is to eschew specifying the value attribute for tags like html:text since the values are automatically retrieved from the form based on name. When this application was tested, data entered on the form wasn't populated to the action form. Because JavaServer Faces uses a different binding convention than Struts, you must explicitly bind each field to a form-bean property. Adding the value attributes to the form as shown solved the problem. The Struts-Faces tags resemble the Struts html tag library. By design, Struts developers will find it easy to learn the Struts-Faces tags. The s:form tag, for example, closely matches the Struts html:form tag. However, with the s:form tag, you use the JSF html tags instead of the Struts html tags. Table 14-2 provides a complete list of tags included with Struts-Faces.
The FacesRequestProcessor processes the submitted logon form and executes the LogonAction. This action doesn't have to do anything special related to JSF. The Struts-Faces library integrates Struts and JSF so your action classes and action forms require no modification when using JSF. Example 14-24 shows the LogonAction for this application. A "real" action would authenticate the user. Example 14-24. Action for logonpackage com.oreilly.strutsckbk.ch14; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.beanutils.PropertyUtils; import org.apache.struts.action.Action; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; public class LogonAction extends Action { public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { String name = (String) PropertyUtils.getSimpleProperty(form, "username"); User user = new User( ); user.setUsername(name); request.getSession( ).setAttribute("user", user); return mapping.findForward("success"); } } The application culminates by rendering a "welcome" page that includes text from the message resources bundle as well as the username entered on the preceding form. The welcome.jsp page, accessed through the welcome.faces path, is shown in Example 14-25. Example 14-25. Rendering HTML with JSF and Struts-Faces tags<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="f" uri="http://java.sun.com/jsf/core" %> <%@ taglib prefix="h" uri="http://java.sun.com/jsf/html" %> <%@ taglib prefix="s" uri="http://struts.apache.org/tags-faces" %> <f:view> <s:loadMessages var="messages"/> <s:html locale="true"> <head> <title>Struts Cookbook - Integrating Struts and JSF</title> </head> <body> <h2>Struts Cookbook - Integrating Struts and JSF</h2> <h3><s:message key="index.welcome"/></h3> <h:outputText value="#{messages['msg.loggedIn']}"/> <b><h:outputText value="#{user.username}"/></b>. </body> </s:html> </f:view> At this point, you have a working application, which uses Struts and JSF together, that preserves your custom action classes and action forms and allows you to take advantage of the rich components afforded by JavaServer Faces. See AlsoFor the latest documentation on Struts-Faces, consult the documentation included with the Struts-Faces nightly build. If you're unsure about using JSF or Struts, Craig McClanahan presents a fair assessment on his blog at http://java.net/craigmcc. You'll find a good article on integrating Struts, JSF, and Tiles on IBM's Developer Works at http://www-106.ibm.com/developerworks/java/library/j-integrate/. The source for information on JavaServer Faces, including the specification and the reference implementation, can be found at http://java.sun.com/jsf. You can use Struts-Faces with any JSF compliant implementation. The MyFaces project (http://incubator.apache.org/projects/myfaces.html) implements the JSF specification and provides an alternative to the reference implementation. You'll find the quick reference for the standard JSF tags at http://www.horstmann.com/corejsf/jsf-tags.html to be quite handy. |
|