UIX Developer's Guide |
Contents |
Previous |
Next |
The Struts framework (see http://jakarta.apache.org/struts/) has become one of the most popular frameworks for
building J2EE web applications. While Struts developers often use
JSPs for their pages, Struts supports the use of alternative view
technologies. UIX provides a set of extensions that lets you use
uiXML for part or all of your Struts applications, and lets you use
completely standard Struts Actions
,
ActionForm
beans and configuration files to control your
uiXML-based application.
This chapter assumes you're familiar with the basics of Struts development. If not, you may want to visit the Struts site to learn more about this technology.
This chapter contains the following sections:
We'll assume that you've installed both UIX and Struts already
(though UIX requires at least Struts 1.1 beta 1). Now, you'll need to
register UIX's Struts extensions. Here's a minimal
WEB-INF/uix-config.xml
file:
<?xml version="1.0" encoding="ISO-8859-1"?>
<configurations xmlns="http://xmlns.oracle.com/uix/config">
<application-configuration>
<ui-extensions>
<extension-class>oracle.cabo.servlet.struts.StrutsUIExtension</extension-class>
</ui-extensions>
</application-configuration>
</configurations>
If you haven't seen this configuration file before, you might want to read the Configuration chapter.
That's all you need. With the setup out of the way, let's start building a basic two-page login application. First, we'll write the Struts code. As you'll see, this is completely generic Struts code without any reference to UIX - a good thing, since your controller code shouldn't contain any dependencies on your view code.
We'll use four files: a Struts configuration file, a
LogonBean
for storing the login information, a
LogonAction
for processing the login, and a small
.properties file for storing our messages. We won't talk much
about this code: if you're familiar with Struts, it should all
be straightforward.
<?xml version="1.0"?>
<!DOCTYPE struts-config SYSTEM "struts-config_1_1.dtd">
<struts-config>
<form-beans>
<form-bean
name="logonForm"
type="LogonBean" />
</form-beans>
<global-forwards
type="org.apache.struts.action.ActionForward">
<forward name="welcome" path="/welcome.uix"
redirect="false" />
</global-forwards>
<action-mappings>
<action
path="/logon"
type="LogonAction"
name="logonForm"
scope="request"
input="/logon.uix"
unknown="false"
validate="true"/>
</action-mappings>
<message-resources parameter="LogonText"/>
</struts-config>
import javax.servlet.http.HttpServletRequest;
import org.apache.struts.action.ActionError;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;
public class LogonBean extends ActionForm
{
public String getUser()
{
return _user;
}
public void setUser(String user)
{
_user = user;
}
public String getPassword()
{
return _password;
}
public void setPassword(String password)
{
_password = password;
}
public ActionErrors validate(
ActionMapping mapping, HttpServletRequest request)
{
// For the purposes of this demo, just call
// "123" a good password!
if (!"123".equals(_password))
{
ActionErrors errors = new ActionErrors();
errors.add("pwd", new ActionError("password"));
return errors;
}
return null;
}
private String _user;
private String _password;
}
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionMessage;
import org.apache.struts.action.ActionMessages;
public class LogonAction extends Action
{
public ActionForward perform(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
{
LogonBean bean = (LogonBean) form;
// Tell the user the login was successful
ActionMessages messages = new ActionMessages();
messages.add(ActionMessages.GLOBAL_MESSAGE,
new ActionMessage("loggedIn", bean.getUser()));
saveMessages(request, messages);
// And go to the generic "welcome" page
return mapping.findForward("welcome");
}
}
password=Bogus password! (Try 123)
loggedIn=Hello {0}, you logged in successfully!
As you can see, this is all generic Struts code. If the user logs
in successfully - for the purposes of this demo, by entering the magic
"123" password - validation succeeds, and the LogonAction
will redirect the user to the welcome page. The welcome page is
defined in the Struts configuration file as handled by "welcome.uix".
If we were to write our "login" and "welcome" UIX pages without Struts, they'd probably look like:
<page xmlns="http://xmlns.oracle.com/uix/controller"
xmlns:ctrl="http://xmlns.oracle.com/uix/controller">
<content>
<dataScope xmlns="http://xmlns.oracle.com/uix/ui"
xmlns:data="http://xmlns.oracle.com/uix/ui">
<contents>
<pageLayout>
<contents>
<form name="theForm" method="post">
<contents>
<labeledFieldLayout>
<contents>
<messageTextInput prompt="User" name="user"/>
<messageTextInput secret="true" prompt="Password"
name="password"/>
<submitButton ctrl:event="login" text="Log On"/>
</contents>
</labeledFieldLayout>
</contents>
</form>
</contents>
</pageLayout>
</contents>
</dataScope>
</content>
<handlers>
<event name="login">
<!-- Here, we handle the event... somehow -->
</event>
</handlers>
</page>
<page xmlns="http://xmlns.oracle.com/uix/controller"
xmlns:ctrl="http://xmlns.oracle.com/uix/controller">
<content>
<dataScope xmlns="http://xmlns.oracle.com/uix/ui"
xmlns:data="http://xmlns.oracle.com/uix/ui">
<contents>
<pageLayout title="Hi there!"/>
</contents>
</dataScope>
</content>
</page>
The only really interesting thing about these two pages is the name
of the two <messageTextInput>
elements: "user" and
"password". These correspond to the names of the two properties on
LogonBean
. Struts will rely on this when we hook it up
to this page.
These are two pretty simple pages, but they don't yet do anything.
First, we'll hook in our LogonAction
class.
<page xmlns="http://xmlns.oracle.com/uix/controller"
xmlns:ctrl="http://xmlns.oracle.com/uix/controller"
xmlns:struts="http://xmlns.oracle.com/uix/struts">
<content>
<dataScope xmlns="http://xmlns.oracle.com/uix/ui"
xmlns:data="http://xmlns.oracle.com/uix/ui">
<contents>
<pageLayout>
<contents>
<form name="theForm" method="post">
<contents>
<labeledFieldLayout>
<contents>
<messageTextInput prompt="User" name="user"/>
<messageTextInput secret="true" prompt="Password"
name="password"/>
<submitButton ctrl:event="login" text="Log On"/>
</contents>
</labeledFieldLayout>
</contents>
</form>
</contents>
</pageLayout>
</contents>
</dataScope>
</content>
<handlers>
<event name="login">
<struts:action path="/do/logon"/>
</event>
</handlers>
</page>
We've added two pieces to this page. First, we assigned the XML
namespace http://xmlns.oracle.com/uix/struts
to the
"struts" prefix. Next, we used the <struts:action>
event to handle our "login" event.
Now, we have two functional pages. Entering the wrong password takes you back to try to login again, and getting the right password sends you to the welcome page. But we've got three things to fix up:
Both are easy to solve with the other UIX Struts XML elements.
To preserve values entered by the user, we'll change from the
standard uiXML <form>
element to the special uiXML
<struts:form>
element. We'll also change our
<messageTextInput>
elements to
<struts:messageTextInput>
.
<page xmlns="http://xmlns.oracle.com/uix/controller"
xmlns:ctrl="http://xmlns.oracle.com/uix/controller"
xmlns:struts="http://xmlns.oracle.com/uix/struts">
<content>
<dataScope xmlns="http://xmlns.oracle.com/uix/ui"
xmlns:data="http://xmlns.oracle.com/uix/ui">
<contents>
<pageLayout>
<contents>
<struts:form name="theForm" method="post"
beanName="logonForm">
<contents>
<labeledFieldLayout>
<contents>
<struts:messageTextInput prompt="User" name="user"/>
<struts:messageTextInput secret="true" prompt="Password"
name="password"/>
<submitButton ctrl:event="login" text="Log On"/>
</contents>
</labeledFieldLayout>
</contents>
</struts:form>
</contents>
</pageLayout>
</contents>
</dataScope>
</content>
<handlers>
<event name="login">
<struts:action path="/do/logon"/>
</event>
</handlers>
</page>
In addition to changing <form>
and
<messageTextInput>
to the Struts versions, we've
also set a "beanName" attribute on <struts:form>
.
This attribute is required, and must match the
<form-bean>
name defined in your
struts-config.xml
(the "name", not the "type").
If you try this, you'll notice that the "user" is automatically restored to what the user entered in case of a password error. The "password" isn't, though, and this is intentional - passwords get sent in plain text in the HTML, even though they look like a series of asterisks in your browser.
In addition to <struts;form> and <struts:messageTextInput>, uiXML includes Struts elements for:
If you've read the Handling
Errors chapter, you're already
familiar with the <messageBox>
element
and inline messaging. UIX doesn't include a special
Struts <struts:messageBox>
element, but it
doesn't need to. Instead, a special <struts:dataScope>
element fills this need.
The <struts:dataScope>
element has all the
features of a normal <dataScope>
, so if you're
using a <dataScope>
element around your page
already, just substitute the Struts version. In addition to the usual
data-scope features, this will automatically find any
ActionMessage
or ActionError
objects and add
them to the list of UIX messages.
<page xmlns="http://xmlns.oracle.com/uix/controller"
xmlns:ctrl="http://xmlns.oracle.com/uix/controller"
xmlns:struts="http://xmlns.oracle.com/uix/struts">
<content>
<struts:dataScope xmlns="http://xmlns.oracle.com/uix/ui"
xmlns:data="http://xmlns.oracle.com/uix/ui">
<contents>
<pageLayout>
<messages>
<messageBox automatic="true"/>
</messages>
<contents>
<struts:form name="theForm" method="post"
beanName="logonForm">
<contents>
<labeledFieldLayout>
<contents>
<struts:messageTextInput prompt="User" name="user"/>
<struts:messageTextInput secret="true" prompt="Password"
name="password">
<boundMessage select="pwd"/>
</struts:messageTextInput>
<submitButton ctrl:event="login" text="Log On"/>
</contents>
</labeledFieldLayout>
</contents>
</struts:form>
</contents>
</pageLayout>
</contents>
</struts:dataScope>
</content>
<handlers>
<event name="login">
<struts:action path="/do/logon"/>
</event>
</handlers>
</page>
<page xmlns="http://xmlns.oracle.com/uix/controller"
xmlns:ctrl="http://xmlns.oracle.com/uix/controller"
xmlns:struts="http://xmlns.oracle.com/uix/struts">
<content>
<struts:dataScope xmlns="http://xmlns.oracle.com/uix/ui"
xmlns:data="http://xmlns.oracle.com/uix/ui">
<contents>
<pageLayout title="Hi there!">
<messages>
<messageBox automatic="true"/>
</messages>
</pageLayout>
</contents>
</struts:dataScope>
</content>
</page>
We've changed our <dataScope> to <struts:dataScope>,
and added a standard <messageBox>. In the login page, we also
added a <boundMessage> element inside of our password field;
this will automatically add inline error messages. The "pwd" string
here matches the string used in the validate()
method of
our LogonBean
.